docker持久化存储
在使用 docker 提供的容器服务时,如果不小心删除了容器,那么默认情况下与容器关联的数据也会一并丢失,不过实际上 docker 提供了几种持久化存储的方式。
docker 数据存储的方式
问题
默认情况下,所有的数据文件都是在容器内创建并存储在可写入的存储层中。这意味着一旦容器被删除,那么数据也会丢失,而且这种方式不利于数据的迁移和共享,性能也会大大降低。
解决方案
针对上述问题,docker 提供了两种方案实现持久化存储,分别是数据卷 volumes 和绑定挂载 bind mounts。
volumes 是由 docker 管理的,可以在多个容器之间共享,并且在容器删除之后 volume 中的数据也会保留下来。volumes 不需要关注宿主机的文件系统结构,可移植性强,易于管理和备份,但是在宿主机下通常无法直接修改 volumes 的内容,也不推荐直接在宿主机修改 volumes 的内容。
bind mounts 允许你将宿主机的文件或目录挂载到容器中。与 volumes 不同,bind mounts 依赖于宿主机的文件系统结构,这也表示它的可移植性不如 volumes,但它可能是最简单易用的方式,因为它可以将你在宿主机上对 bind mounts 挂载点下的文件修改操作立即反映到容器内部。
补充
对于不想持久化存储的数据,可以考虑使用 tmpfs mounts。tmpfs mounts 允许你在容器内存中创建一个临时文件系统,只需要重启或关闭容器就会删除数据。
tmpfs mounts 的使用参考docker官方文档
docker 持久化存储实践
使用 volumes
创建一个名为 vol
的空的 volume
1 | docker volume create vol |
查看已有的 volume
1 | docker volume ls |
可以通过 -v
或 --mount
参数指定 volume 数据卷挂载到容器的指定目录,在容器中所有针对该目录的写入操作都会保存到宿主机的 volume 中。
1 | docker run -d \ |
或使用以下写法
1 | docker run -d \ |
在 docker-compose.yml 中
1 | services: |
或使用以下写法
1 | services: |
执行 docker-compose up
即可。
如果创建时没有指定 volume 的名称,则会创建匿名卷。
为了防止用户忘记将关键数据挂载到宿主机目录,通常会在 Dockerfile 中定义命名卷,指定了容器内特定的路径应该被外部卷挂载。
在运行容器时,如果指定了容器内路径但未提供卷名,Docker 会自动创建匿名卷。
1 | docker run -v /path/in/container my_image |
未指定卷名,会创建匿名卷。
删除一个名为vol
的 volume
1 | docker volume rm vol |
批量删除 volume
1 | docker volume prune # 只删除未使用的匿名卷 |
查看容器关联的 volume 可使用以下命令
1 | docker inspect [container_id] | grep Mounts -A 50 |
使用bind mounts
bind mounts 的使用和 volumes 类似,也是通过 -v
和 --mount
参数将宿主机文件挂载到容器中
1 | docker run -d \ |
或使用以下写法
1 | docker run -d \ |
在 docker-compose.yml 中
1 | services: |
或使用以下写法
1 | services: |
其它的删除修改等操作可直接在宿主机下进行,但是删除宿主机挂载点下的文件后可能会导致容器因为配置文件或其他文件丢失而出错。
存储方式的转换
从 volumes 转换到 bind mounts
在宿主机上创建新的目录,作为 bind mount 的源
1 | mkdir /path/on/host/bind/mount |
使用 docker cp
命令将卷中的数据复制到宿主机目录
1 | docker cp my_container:/path/in/container /path/on/host/bind_mount |
在 docker cp
不可用的情况下,可以通过临时容器复制数据
1 | docker run --rm \ |
在新的容器使用 bind mount
1 | docker run -d -v /path/on/host/bind_mount:/path/in/container my_image |
从 bind mounts 转换到 volumes
在宿主机上创建一个新的 volume
1 | docker volume create my_new_volume |
挂载新创建的 volume 和宿主机上的 bind mount 目录到容器内的不同路径上
1 | docker run --rm -it \ |
在容器内执行复制操作,将数据从 bind mount 的路径复制到新创建的 Docker 卷的路径
1 | cp -ar /path/in/container/old/. /path/in/container/new/ |
在新的容器使用 volume
1 | docker run -d -v my_new_volume:/path/in/container my_image |
使用场景
volumes 和 bind mounts 都是一种宿主机与容器之间的共享文件。但是它们的使用场景有所不同。以下是一些对比:
volumes
- 易于备份和迁移(可移植性高)
- 通过docker完全管理,数据安全性更好
- 易于数据共享
- 可以借助驱动实现远程挂载
bind mounts
- 具有更好的性能
- 使用起来更加简单
- 在宿主机下可以很方便地访问修改文件
关于 volumes 和 bind mounts 在挂载行为上的差异。空的 volumes 在挂载时,会自动将容器内指定目录的数据复制过来。而空的 bind mounts 在挂载时则会覆盖容器内的配置(原本的内容会被隐藏)。
因此使用 volume 更倾向于数据备份,使用 bind mounts 更倾向于文件修改。
总结
docker 的持久化存储方式有 volumes 数据卷存储和 bind mounts 绑定挂载存储。
volumes 比较适合数据库持久化存储等需要易于备份和迁移的场景,而 bind mounts 比较适合修改文件并即时反映到容器的开发环境场景等。
在简单的场景下,这两种存储方式在使用上并没有什么明显差异。不过,如果要开发新的 docker 应用程序,则应该优先考虑使用 volumes。
持久化存储方式解决了容器的数据长期存储问题。不过容器存在一定的性能损耗,能否作为生产环境也是个问题。当然现在有很流行的 Kubernetes 项目,平常用户所购买的 vps、云服务器等都借助了虚拟化技术,性能问题或许已经不是最主要的问题了。
从个人学习的角度上来看,docker 也非常具有学习价值,并且可以通过 docker 来快速搭建各种环境,例如通过 docker 安装 ubuntu 来学习基础的 linux 命令,通过 docker 搭建各种 web 服务等。
参考资料
相关推荐
- 标题: docker持久化存储
- 作者: Entropy Tree
- 创建于 : 2023-10-07 13:48:41
- 更新于 : 2024-07-10 15:35:07
- 链接: https://www.entropy-tree.top/2023/10/07/docker-persistent-storage/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。