Docker 持久化存储 Volumes
- 简介
- 如何选择 -v 和 --mount
- -v或--volume
- --mount
- 创建和管理卷
- 启动带有卷的容器
- 使用Docker Compose的卷
- 使用卷启动服务
- 使用只读卷
- 备份、恢复或迁移数据卷
- 备份卷
- 删除卷
- 自动删除匿名卷
- 删除所有未使用卷
简介
官方文档: https://docs.docker.com/storage/volumes/
卷是持久化Docker容器生成和使用的数据的首选机制。虽然绑定挂载依赖于主机的目录结构和操作系统,但卷完全由Docker管理。与绑定挂载相比,卷具有以下几个优势:
- 卷比绑定挂载更容易备份或迁移。
- 可以使用Docker CLI命令或Docker API管理卷。
- 卷可以在Linux和Windows容器上工作。
- 可以在多个容器之间更安全地共享卷。
- 卷驱动程序允许将卷存储在远程主机或云提供商上,以加密卷的内容或添加其他功能。
- 新卷的内容可以由容器预先填充。
如何选择 -v 和 --mount
一般来说,
--mount
更加明确和详细。最大的区别是-v
语法将所有选项组合在一个字段中,而--mount
语法将它们分开。
- 如果需要指定卷驱动程序选项,则必须使用
--mount
。 - 创建服务时,使用
--mount
。
-v或–volume
由三个字段组成,用冒号(:)分隔
。字段必须按正确的顺序排列,并且每个字段的含义不同。
docker run -d --name vtest -v myvol2:/app:ro nginx:latest
# [1] [2] [3]
- [1]: 对于命名卷,第一个字段是卷的名称,并且在给定的主机上是唯一的。对于匿名卷,第一个字段被省略,由docker 生成。
- [2]: 第二个字段是容器中要挂载的目录或文件路径。
- [3]: 第三个字段是可选的,是一个逗号分隔的选项列表,如ro。
–mount
由多个键值对组成,用逗号分隔,每个键值对由一个<key>=<value>
元组组成。--mount
语法比-v或--volume
更详细,但键的顺序并不重要。
type
键:值可以为bind
volume
tmpfs
。source
键: 值为挂载的来源,对于命名卷,是卷的名称。对于匿名卷,此字段被省略。也可以写成为src
。destination
键: 值为要挂载到容器中的目录或文件的路径,也可以写成dst
或者target
。readonly
选项如果存在,会以只读方式挂载到容器。也可以写成ro
。docker run -d \ --name=nginxtest \ --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \ nginx:latest
volume-opt
可以指定多次,选项名称和其值组成的键值对。从外部CSV解析器中转义值
如果卷驱动程序接受以逗号分隔的列表作为选项,则必须从外部CSV解析器中转义该值。要转义volume-opt
,用双引号(“)将volume-opt
括起来,并用单引号(')将整个mount参数括起来。
例如,本地驱动程序接受挂载选项作为o参数中逗号分隔的列表。此示例演示了转义列表的正确方法。docker service create \ --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"' --name myservice \ <IMAGE>
创建和管理卷
- 创建卷
docker volume create my-vol
- 列出卷
docker volume ls local my-vol
- 查看卷详情
docker volume inspect my-vol [ { "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/my-vol/_data", "Name": "my-vol", "Options": {}, "Scope": "local" } ]
- 删除卷
docker volume rm my-vol
启动带有卷的容器
如果用一个不存在的卷启动一个容器,Docker会创建该卷。以下示例将卷 myvol2 挂载到容器中的 /app/ 中。
--mount
docker run -d \ --name devtest \ --mount source=myvol2,target=/app \ nginx:latest
-v
docker run -d \ --name devtest \ -v myvol2:/app \ nginx:latest
【注】:
--mount
和-v
示例产生的效果一样。
- 使用
docker inspect devtest
查看docker 是否创建了卷,并正确挂载到容器中。"Mounts": [ { "Type": "volume", "Name": "myvol2", "Source": "/var/lib/docker/volumes/myvol2/_data", "Destination": "/app", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ],
这表明挂载是一个卷,并且源路径和目标路径正确,权限是读写。
- 删除容器和卷
docker container stop devtest docker container rm devtest docker volume rm myvol2
使用Docker Compose的卷
- 下面的示例展示了一个带有卷的Docker Compose服务:
services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp:
第一次运行
docker compose up
会创建一个卷。当随后运行该命令时,Docker会重用相同的卷。
- 也可以使用
docker volume create
直接在Compose 外部创建一个卷,然后在docker-Compose.yml
内部引用它,如下所示:services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp: external: true
使用卷启动服务
启动服务并定义卷时,每个服务容器都使用自己的本地卷。如果使用本地卷驱动程序,则任何容器都无法共享此数据。但是,有些卷驱动程序确实支持共享存储。
以下示例启动一个具有四个副本的nginx服务,每个副本使用一个名为myvol2的本地卷。
docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest
使用 docker service ps devtest-service
服务来验证服务是否正在运行:
docker service ps devtest-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
4d7oz1j85wwn devtest-service.1 nginx:latest moby Running Running 14 seconds ago
删除服务以停止正在运行的任务:
docker service rm devtest-service
删除该服务不会删除该服务创建的任何卷。删除卷是一个单独的步骤。
docker service create
不支持-v
或者--volume
,必须使用--mount
。
使用只读卷
设置权限
-
--mount
docker run -d \ --name=nginxtest \ --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \ nginx:latest
-
-v
docker run -d \ --name=nginxtest \ -v nginx-vol:/usr/share/nginx/html:ro \ nginx:latest
有多个权限选项时,用逗号隔开。
-
使用
docker inspect nginxtest
, 查看详情,只看Mount
部分就好。"Mounts": [ { "Type": "volume", "Name": "nginx-vol", "Source": "/var/lib/docker/volumes/nginx-vol/_data", "Destination": "/usr/share/nginx/html", "Driver": "local", "Mode": "", "RW": false, "Propagation": "" } ],
备份、恢复或迁移数据卷
备份卷
-
创建一个容器
dbstore
docker run -v /dbdata --name dbstore ubuntu /bin/bash
-
备份
- 创建一个新容器并从
dbstore
容器挂载卷。 - 将本地目录挂载到容器
/backup
。 - 将
/dbdata
的内容打包到/backup/backup.tar
中。docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
当命令执行结束容器停止时,
dbdata
备份完成。
- 创建一个新容器并从
-
从备份还原卷
使用刚刚创建的备份,可以将其恢复到同一个容器,或者恢复到另一个容器。- 恢复到另一个容器
dbstore2
docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
- 恢复到另一个容器
删除卷
自动删除匿名卷
删除容器时并不会自动删除匿名卷,运行容器时使用
--rm
选项自动删除匿名卷。
docker run --rm -v /foo -v awesome:/bar busybox top
--rm
可以自动删除/foo
的匿名卷,但是命名卷awesome
不会被删除。
如果其它容器使用
--volumes-from
绑定了匿名卷,容器删除时,匿名卷会被保留,不会被删除。
删除所有未使用卷
- 删除所有未使用的卷释放空间
docker volume prune