管理容器中的数据
利用 Docker Engine 来管理容器中的数据主要有两种方法:数据卷 和 数据卷容器。
数据卷
数据卷是绕过联合文件系统的一个或多个容器中的专门指定目录。数据卷为数据的持续性和共享性提供了以下几个特性:
- 当容器创建时,数据卷就被初始化。如果容器的父镜像包含指定挂载点的数据,现有数据会在卷初始化的时候被复制到新卷中。
- 数据卷可以在容器之间共享和重用
- 对数据卷的更改是直接进行的
- 更新镜像时,不包括对数据卷的更改
- 尽管容器被删除,数据卷也依旧存在
数据卷被设计为持久化数据,它独立于容器的生命周期。因此,Docker 不会在删除容器时自动删除卷,也不会对容器不再引用的卷进行“垃圾回收”。
添加数据卷
通过在 docker create
和 docker run
命令中添加 -v
参数来给一个容器添加数据卷。可以使用多次 -v
来挂载多个数据卷。例如:
docker run -d -P --name web -v /webapp training/webapp python app.py
当使用 -P 参数时,Docker 会随机映射一个或多个端口到容器暴露的所有端口。执行此命令后,在容器内部 /webapp 处将会创建一个新的卷。并且,也可以在 Dockerfile中使用 VOLUME 指令给容器添加一个或多个新的卷。
定位数据卷
可以通过docker inspect <container name/id>
命令的输出,查看 Mount 部分的内容。其中,Source 指定了在宿主机上的位置,Destination 指定了卷在容器中的位置。RW 表明的是否可读/写。
将宿主机目录挂载为数据卷
除了使用 -v 参数来创建数据卷,也可以将目录从 Docker Engine 的宿主机挂载到容器中。例如:
docker run -d -P --name web -v /src/webapp:/webapp training/webapp python app.py
这个命令将宿主机中的 /src/webapp
目录挂载到容器中的 /webapp
中。如果路径 /webapp
已经存在在容器镜像中,/src/webapp
挂载会覆盖但不会删除之前存在的内容。一但删除挂载,原来的内容可以再次被访问。
容器目录必须是绝对路径,宿主机目录可以是绝对路径也可以是一个name。当宿主机目录是绝对路径时,Docker 会将挂载绑定到指定的路径上(宿主机上的目录如果不存在,Docker Engine 会自动创建);当宿主机目录是名称时,Docker 会创建一个以指定名称命名的卷。名称必须以数字或字母开头,后跟a-z,0-9,下划线,英文句号或连字符。
可以在挂载目录的同时指定挂载的读写权限,例如:
docker run -d -P --name web -v /src/webapp:/webapp:ro training/webapp python app.py
指定挂载只可读。
从本质上来讲,宿主机目录是依赖于宿主机的。因此,不能从 Dockerfile 中挂载宿主机的目录,VOLUME 指令也不支持传递一个宿主机目录,因为构建的镜像应当是可移植的。
将共享存储卷挂载为数据卷
使用共享卷的一个优点是其对于宿主机是独立的。
通过在 docker run
中使用 --volume-driver
来指定创建卷的驱动。卷驱动通过名称创建卷而不是路径。例如:
docker run -d -P --volume-driver local -v my_named_volume:/webapp --name web training/webapp python app.py
此外,还可以使用 docker volume create
命令在容器中使用卷之前创建它。选项以键值对的形式被指定:o=<key>=<value>
。;例如:
docker volume create -d local --opt o=size=20MB my_named_volume
docker run -d -P -v my_named_volume:/webapp --name web training/webapp python app.py
将宿主机文件挂载为数据卷
通过将 -v 参数指定为一个文件来将宿主机文件挂载为数据卷,例如:
docker run --rm -it -v D:\bash_history.txt:/root/.bash_history ubuntu:1.0 /bin/bash
执行此命令后,在容器中执行的命令历史将会记录在宿主机的文件中。关闭容器时,/root/.bash_history
文件中的内容将会复制到D:\bash_history.txt
中。
创建和挂载数据卷容器
当在容器之间共享持久性数据,或从非持久性容器中使用这些数据时,最好创建一个命名的数据卷容器并在其之上挂载数据。
docker create -v /dbdata --name dbstore training/postgres /bin/true
/bin/true 不做任何事,只是将退出码设置为0,表示成功退出。
尽管这个容器不运行任何应用,但是它重用了 training/postgres 镜像,因此所有容器使用共同的层,节省了磁盘空间。
之后使用--volumes-from
参数来在另一个容器中挂载 dbstore 容器中的 /dbdata 卷。
docker run -d --volumes-from dbstore --name db1 training/postgres
docker run -d --volumes-from dbstore --name db2 training/postgres
如果 training/postgres 镜像中也存在一个 /dbdata 目录,dbstore 容器中的卷会隐藏 postgres 镜像中的卷,之后 dbstore 中的文件可被访问。
同时,可以多次使用--volumes-from
参数来从多个容器中混合数据卷。
您还可以通过 db1 或 db2 容器将来自 dbstore 容器的卷挂载到另一个容器中来扩展链。
docker run -d --name db3 --volumes-from bd1 training/postgres
删除卷
删除挂载卷的容器,不管是初始的 dbstore,还是后面的 db1、db2,卷都不会被删除。如果要删除磁盘上的卷,必须对最后一个引用卷的容器调用 docker rm -v
。
如果删除最后一个引用卷的容器时,没有加参数 -v,可以通过
docker volume ls -f dangling=true
来查找未删除且未引用的卷,然后使用docker volume rm <volume name>
来删除对应的卷。此外,可以通过docker volume prune
删除所有未使用的数据卷并释放空间。
备份、恢复和迁移数据卷
- 将要备份的数据卷的内容打包
- 利用挂载点将备份压缩包复制到宿主机上
- 将上述的宿主机挂载点挂载到新容器的数据卷上
- 将挂载点上的压缩包解压到新容器的数据卷上