docker 数据管理
在生产环境中使用 Docker ,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作
容器中的管理数据主要有两种方式:
数据卷 Data Volumes 容器内数据直接映射到本地主机环境;
数据卷容器(Data Volume Containers 使用特定容器维护数据卷
数据卷(Data Volumes)
数据卷是一个可供一个或多个容器使用的特殊目录,它将主机操作系统目录直接映射进容器, 它可以提供很多有用的特性:
数据卷 可以在容器之间共享和重用
对数据卷的修改会立马生效
对数据卷的更新,不会影响镜像
数据卷 默认会一直存在,即使容器被删除
不同的数据挂载方式
无论哪种类型的挂载,数据在容器内看起来都是一样的。它在容器的文件系统中以目录或单个文件的形式显示。
要直观地了解volumes、bind mounts和tmpfs mounts之间的区别,可以考虑数据在Docker主机上的存放位置。
Volumes存储在主机文件系统的一部分,由Docker管理(Linux上为/var/lib/docker/volumes/)。非Docker进程不应修改文件系统的这一部分。Volumes是在Docker中保存数据的最佳方式。
Bind mounts可以存储在主机系统的任何地方。它们甚至可能是重要的系统文件或目录。Docker主机或Docker容器上的非Docker进程可以在任何时候修改它们。
tmpfs mounts只存储在主机系统的内存中,不会被写入主机系统的文件系统。
使用 Volumes
Volumes是保存由Docker容器产生和使用的数据的首选机制。Bind mounts依赖于主机的目录结构和操作系统,而Volumes则完全由Docker管理。Volumes比Bind mounts有几个优势。
Volumes比Bind mounts更容易备份或迁移。
你可以使用Docker CLI命令或Docker API来管理Volumes。
Volumes在Linux和Windows容器上都可以工作。
Volumes可以更安全地在多个容器之间共享。
Volumes的驱动可以让你在远程主机或云供应商上存储Volumes,对Volumes的内容进行加密,或添加其他功能。
新的Volumes可以由容器预先填充其内容。
Docker桌面上的Volumes比来自Mac和Windows主机的Bind mounts的性能高得多。
此外,Volumes通常是比在容器的可写层中持久化数据更好的选择,因为Volumes不会增加使用它的容器的大小,而且Volumes的内容存在于特定容器的生命周期之外。
创建和管理Volumes
创建一个Volume
$ docker volume create my-vol
列出Volumes
$ docker volume ls
查看Volume信息
$ docker volume inspect my-vol
删除Volume
$ docker volume rm my-vol
启动一个带Volume的容器
如果你用一个尚不存在的卷来启动一个容器,Docker会为你创建这个卷。下面的例子将卷myvol2挂载到容器的/app/中。
$ docker run -d \--name devtest \--mount source=myvol2,target=/app \nginx:latest # 方式一:使用 --mount $ docker run -d \--name devtest \-v myvol2:/app \nginx:latest # 方式二:使用 -v $ docker inspect devtest # 查看容器信息 1234567891011121314
挂载点信息:
"Mounts": [{"Type": "volume","Name": "myvol2","Source": "/var/lib/docker/volumes/myvol2/_data","Destination": "/app","Driver": "local","Mode": "","RW": true,"Propagation": ""} ], 123456789101112
这表明挂载的是一个卷,它显示了正确的源和目标,并且挂载是读写的。
停止容器并删除卷。注意卷的移除是一个单独的步骤。
$ docker container stop devtest $ docker container rm devtest $ docker volume rm myvol2 123
用卷来启动一个服务容器
当你启动一个服务并定义一个卷时,每个服务容器使用它自己的本地卷。如果你使用本地卷驱动,所有的容器都不能共享这些数据,但有些卷驱动确实支持共享存储。Docker for AWS和Docker for Azure都支持使用Cloudstor插件的持久化存储。
下面的例子启动了一个有四个副本的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 rm devtest-service # 删除该服务,这将停止其所有任务。 # 移除服务不会移除该服务所创建的任何卷。卷的移除是一个单独的步骤。 123456789101112
服务容器语法不同点docker service create 命令不支持
-v
或者--volume
标志,当挂载一个卷到一个服务类型的容器中时,你必须使用-mount
标志。
使用一个容器填充一个卷
如果你启动了一个创建新卷的容器,如上所述,并且该容器在要挂载的目录中拥有文件或目录(比如上面的/app/),那么该目录的内容就会被复制到该卷。然后容器挂载并使用该卷,其他使用该卷的容器也可以访问预先填充的内容。
为了说明这一点,本例启动了一个nginx容器,并将容器的/usr/share/nginx/html目录的内容填充到新的卷nginx-vol中,该目录是Nginx存储默认HTML内容的地方。
$ docker run -d \--name=nginxtest \--mount source=nginx-vol,destination=/usr/share/nginx/html \nginx:latest # 方式一:使用 --mount $ docker run -d \--name=nginxtest \-v nginx-vol:/usr/share/nginx/html \nginx:latest # 方式二:使用 -v 1234567891011
运行以下命令来清理容器和卷。注意卷的移除是一个单独的步骤。
$ docker container stop nginxtest $ docker container rm nginxtest $ docker volume rm nginx-vol 123
使用只读卷
对于一些开发应用,容器需要写进绑定挂载,以便将变化传播回Docker主机。在其他时候,容器只需要对数据进行读取访问。请记住,多个容器可以挂载同一个卷,它可以对其中一些容器进行读写挂载,而同时对其他容器进行只读挂载。
这个例子修改了上面的例子,但是把目录挂载为只读卷,方法是在容器内的挂载点后面的选项(默认为空)列表中加入ro。如果有多个选项,请用逗号将它们分开。
$ docker run -d \--name=nginxtest \--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \nginx:latest # 方式一:使用 --mount $ docker run -d \--name=nginxtest \-v nginx-vol:/usr/share/nginx/html:ro \nginx:latest # 方式二:使用 -v $ docker inspect nginxtest # 查看容器信息 1234567891011121314
挂载点信息:
"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": ""} ], 123456789101112
运行以下命令来清理容器和卷。注意卷的移除是一个单独的步骤。
$ docker container stop nginxtest $ docker container rm nginxtest $ docker volume rm nginx-vol 123
备份、恢复或迁移数据卷
卷对于备份、恢复和迁移很有用。使用 --volumes-from 标志来创建一个新的容器,挂载该卷。
备份一个卷
例如,创建一个名为dbstore的新容器。
$ docker run -itd -v /dbdata --name dbstore nginx
然后在下一个命令中:
启动一个新的容器,并从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 -itd -v /dbdata --name dbstore2 nginx
然后在新容器的数据卷中解压备份文件:
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup nginx bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1" 1
你可以使用上述技术,用你喜欢的工具自动进行备份、迁移和恢复测试。
删除卷
一个Docker数据卷在容器被删除后仍然存在。有两种类型的卷需要考虑:
命名卷有一个来自容器外部的特定来源,例如awesome:/bar
匿名卷没有特定的来源,所以当容器被删除时,指示Docker引擎守护程序来删除它们
移除匿名卷
要自动删除匿名卷,可以使用–rm选项。例如,这个命令创建了一个匿名的/foo卷。当容器被删除时,Docker引擎会删除/foo卷,但不会删除awesome卷。
$ docker run --rm -v /foo -v awesome:/bar busybox top
Note:
如果另一个容器用 --volumes-from 绑定卷,卷的定义会被复制,匿名卷也会在第一个容器被移除后保持不变。
删除所有卷
要删除所有未使用的卷,释放空间:
$ docker volume prune
使用bind mounts
用绑定挂载启动一个容器
$ docker run -d \-it \--name devtest \--mount type=bind,source="$(pwd)"/target,target=/app \nginx:latest # 方式一:使用 --mount $ docker run -d \-it \--name devtest \-v "$(pwd)"/target:/app \nginx:latest # 方式二:使用 -v $ docker inspect nginxtest # 查看容器信息 12345678910111213141516
挂载点信息:
"Mounts": [{"Type": "bind","Source": "/tmp/source/target","Destination": "/app","Mode": "","RW": true,"Propagation": "rprivate"} ], 12345678910
挂载到容器上一个非空的目录中
如果你绑定挂载到容器上的一个非空目录,该目录的现有内容会被绑定挂载所掩盖。这可能是有益的,例如当你想测试你的应用程序的一个新版本而不建立一个新的镜像。然而,它也可能是令人惊讶的,这种行为与docker卷的行为不同。
$ docker run -d \-it \--nme broken-container \--mount type=bind,source=/tmp,target=/usr \nginx:latest # 方式一:使用 --mount $ docker run -d \-it \--name broken-container \-v /tmp:/usr \nginx:latest # 方式二:使用 -v 12345678910111213
使用只读的绑定挂载
对于某些开发应用,容器需要写入绑定挂载,这样变化就会传播到Docker主机上。在其他时候,容器只需要读取权限。
$ docker run -d \-it \--name devtest \--mount type=bind,source="$(pwd)"/target,target=/app,readonly \nginx:latest # 方式一:使用 --mount $ docker run -d \-it \--name devtest \-v "$(pwd)"/target:/app:ro \nginx:latest # 方式二:使用 -v $ docker inspect nginxtest # 查看容器信息 12345678910111213141516
挂载点信息:
"Mounts": [{"Type": "bind","Source": "/tmp/source/target","Destination": "/app","Mode": "ro","RW": false,"Propagation": "rprivate"} ], 12345678910
总结
Docker 数据管理推荐使用volume,绑定挂载常用于应用开发环境。
Docker 数据管理非常重要。