docker持久化存储

Entropy Tree Lv4

在使用docker提供的容器服务时,如果不小心删除了容器,那么默认情况下与容器关联的数据也会一并丢失,不过实际上docker提供了几种持久化存储的方式。

docker数据存储的方式

问题

默认情况下,所有的数据文件都是在容器内创建并存储在可写入的存储层中。这意味着一旦容器被删除,那么数据也会丢失,而且这种方式不利于数据的迁移和共享,性能也会大大降低。

解决方案

针对上述问题,docker提供了两种方案实现持久化存储,分别是数据卷volumes和绑定挂载bind mounts

volumes是由docker管理的,可以在多个容器之间共享,并且在容器删除之后volume中的数据也会保留下来。volumes不需要关注宿主机的文件系统结构,可移植性强,易于管理和备份,可能是docker持久化存储的最佳方式。

bind mounts允许你将宿主机的文件或目录挂载到容器中。与volumes不同,bind mounts依赖于宿主机的文件系统结构,这也表示它的可移植性不如volumes,但它可能是最简单易用的方式。

补充

对于不想持久化存储的数据,可以考虑使用tmpfs mountstmpfs mounts允许你在容器内存中创建一个临时文件系统,只需要重启或关闭容器就会删除数据。

tmpfs mounts的使用参考docker官方文档

docker持久化存储实践

使用volumes

创建一个名为vol的空的volume

1
docker volume create vol

查看已有的volume

1
docker volume ls

可以通过-v--mount参数指定volume数据卷挂载到容器的指定目录,在容器中所有针对该目录的写入操作都会保存到宿主机的volume中。

1
2
3
4
5
6
7
8
9
docker run -d \
--name=nginxtest \
--mount source=nginx-vol,target=/usr/share/nginx/html \
nginx:latest
# 或使用以下命令
docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest

docker-compose.yml

1
2
3
4
5
6
7
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:

运行docker-compose up即可。

如果创建时没有指定volume的名称,则会创建匿名卷。

匿名卷是为了防止用户忘记将关键数据挂载到宿主机目录。匿名卷通常是在Dockerfile中定义,在运行时如果用户没有进行挂载,则自动挂载Dockerfile中指定的匿名卷,如果用户指定了挂载项,则会覆盖匿名卷的挂载配置。

删除一个名为volvolume

1
docker volume rm vol

批量删除volume

1
2
docker volume prune # 只删除未使用的匿名卷
docker volume prune -a # 删除所有未使用的卷

补充

查看容器关联的volume可使用以下命令

docker inspect [container_id] | grep Mounts -A 50

使用bind mounts

bind mounts的使用和volumes类似,也是通过-v--mount参数将宿主机文件挂载到容器中

1
2
3
4
5
6
7
8
9
docker run -d \
--name=nginxtest \
--mount type=bind,source=/usr/local/web,target=/usr/share/nginx/html \
nginx:latest
# 或使用以下命令
docker run -d \
--name=nginxtest \
-v /usr/local/web:/usr/share/nginx/html \
nginx:latest

docker-compose.yml

1
2
3
4
5
6
7
8
9
services:
frontend:
image: node:lts
volumes:
- type: bind
source: ./static
target: /opt/app/static
volumes:
myapp:

注意对比volumesbind mounts在使用时的差异。

其它的删除修改等操作可直接在宿主机下进行。

存储方式的转换

  • volumes转换到bind mounts

    首先创建一个新的bind mounts,然后将数据从volume复制到bind mounts

    1
    2
    3
    4
    5
    6
    7
    8
    # 创建bind mounts
    mkdir /path/to/bind/mounts

    # 创建一个临时容器用于复制数据
    docker run --rm --volumes-from my_container -v /path/to/bind/mount:/backup ubuntu tar cvf /backup/backup.tar /path/to/data

    # 在新容器中使用bind mounts
    docker run -d -v /path/to/bind/mount:/path/to/data/ my_image

    这里,my_container是原来使用volume的容器,/path/to/data是容器内的数据路径,/path/to/bind/mount是宿主机上的bind mounts路径,my_image是新容器的镜像。

  • bind mounts转换到volumes

    首先创建一个新的volume,然后将数据从bind mounts复制到数据卷

    1
    2
    3
    4
    5
    6
    7
    8
    # 创建volumes
    docker volume create my_volume

    # 创建一个临时的容器来复制数据
    docker run --rm -v /path/to/bind/mount:/backup -v my_volume:/path/to/data ubuntu tar xvf /backup/backup.tar /path/to/data

    # 在新容器中使用volumes
    docker run -d -v my_volume:/path/to/data my_image

使用场景

volumesbind mounts都是一种宿主机与容器之间的共享文件。但是它们的使用场景有所不同。以下是一些对比:

volume

  • 易于备份和迁移(可移植性高)
  • 通过docker完全管理,数据安全性更好
  • 易于数据共享
  • 可以借助驱动实现远程挂载

bind mounts

  • 具有更好的性能
  • 使用起来更加简单
  • 在宿主机下可以很方便地访问修改文件

关于volumesbind mounts在挂载行为上的差异。空的volumes在挂载时,会自动将容器内指定目录的数据复制过来。而空的bind mounts在挂载时则会覆盖容器内的配置(原本的内容会被隐藏)。

因此使用volume更倾向于数据备份,使用bind mounts更倾向于文件修改。

总结

docker的持久化存储方式有volumes数据卷存储和bind mounts绑定挂载存储。

volume比较适合数据库持久化存储等需要易于备份和迁移的场景,而bind mounts比较适合修改文件并即时反映到容器的开发环境场景等。

在简单的场景下,这两种存储方式在使用上并没有什么明显差异。不过,如果要开发新的docker应用程序,则应该优先考虑使用volume

持久化存储方式解决了容器的数据长期存储问题。不过容器存在一定的性能损耗,能否作为生产环境也是个问题。当然现在有很流行的Kubernetes项目,平常用户所购买的vps、云服务器等都借助了虚拟化技术,性能问题或许已经不是最主要的问题了。

从个人学习的角度上来看,docker也非常具有学习价值,并且可以通过docker来快速搭建各种环境,例如通过docker安装ubuntu来学习基础的linux命令,通过docker搭建各种web服务等。

参考资料

storage | docker docs

相关推荐

另一个容器化工具 podman

  • 标题: docker持久化存储
  • 作者: Entropy Tree
  • 创建于 : 2023-10-07 13:48:41
  • 更新于 : 2023-10-08 09:23:57
  • 链接: https://www.entropy-tree.top/2023/10/07/docker-persistent-storage/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论