一. 基本说明
是时候了解Docker如何管理数据了。本节主要说明持久化和非持久化,着重持久化
数据存储分为两类,持久化和非持久化。
● 持久化数据是需要保存的数据,例如客户的信息、财务、审计日志等
● 非持久化数据是不需要保存的数据
每个Docker容器都有自己的非持久化存储,非持久化存储自动创建,从属于容器,生命周期与容器相同。这意味着删除容器也会删除全部非持久化数据。简要说服务应用删除、重启后数据丢失,一般在内存缓存中的数据在服务重启后会丢失
如果需要自己的容器数据保留下来,则需要将数据存储在卷上。卷与容器是解耦的,从而可以独立的创建并管理卷,并且卷并未与任何容器生命周期绑定。简要说就是把服务应用删除、停止、重启后历史的数据还会存在,以文件形式存储在磁盘上
● 非持久化数据是在容器内部应用的缓存中,与容器生命周期为一体
● 非持久化数据与容器是相互隔离状态,不随容器状态的改变而改变
二. 数据持久化实现方式
● volume
docker自身管理的一种数据持久化方式
● mount bind
数据由人为自定义管理的一种方式
下面将对2钟持久化做一个演示
三. 演示镜像模板
FROM nginx MAINTAINER wangtianciEXPOSE 80 # 创建测试镜像 docker build -f /root/nginx_dockerfile -t nginx:v1 .
四. volume持久化
1. 如何去查看容器的存储路径
Docker自身提供了"docker volume ls"的指令查看数据卷
[root@doc03 Docker]# docker volume ls DRIVER VOLUME NAME local 2f68c77fb5b576bdb94857f113e7e5d12be7faaecd752a1ce31317655d809028 local 50d1bb27a79fd743b3b69f4be90d21f4a717b34ff5a3b2017493bbf0abeddd2b local 58441bc7713392eb3c6895ba2aae7e26b03f325ff366a1bde3ee51b0b6f45d1c
第二列"VOLUME NAME"为数据存储目录名称,第一眼看很懵,数据存储对应的是那个容器?如果数据量过小可以使用"find"指令去查到关键文件从而获得容器数据存储路径,当数据量过大时使用"find"不太现实
2. 如何去自定义容器的存储路径
Docker提供了"-v"参数来自定义容器卷名称,示范如下
[root@doc03 ~]# docker run -d --name nginx-volume-test1 -p 8888:80 -v test-volume:/usr/share/nginx/html nginx:v1 961213c2f96cca344afabf01c7579184e9edaff9a7d36b667e86a722da49eee2 [root@doc03 Docker]# docker volume ls DRIVER VOLUME NAME local 2f68c77fb5b576bdb94857f113e7e5d12be7faaecd752a1ce31317655d809028 local 50d1bb27a79fd743b3b69f4be90d21f4a717b34ff5a3b2017493bbf0abeddd2b local 58441bc7713392eb3c6895ba2aae7e26b03f325ff366a1bde3ee51b0b6f45d1c local test-volume [root@doc03 ~]# tree /opt/app/Docker/volumes/test-volume /opt/app/Docker/volumes/test-volume └── _data ├── 50x.html └── index.html 1 directory, 2 files
可以看到,在"volumes"目录下,docker自身创建了"test_volume/_data"目录,并且nginx主页文件"index.html"、"50x.html"也在这个目录下。说明容器内的文件会自动迁移到主机数据存储目录中
-v:host_dirname:container_dirname
注意:host_dirname 不需要写绝对路径,只需指明单独一个目录即可,会将数据统一存储在docker自身的数据管理目录下
这里数据存储路径命名得有规范性,若是随意命名有可能导致环境混乱,笔者建议按照服务的名称或者是提供业务去命名
3. 数据卷共享
创建一个实例"nginx-volume-test1"
[root@doc03 ~]# docker run -d --name nginx-volume-test2 -p 9999:80 -v test-volume:/usr/share/nginx/html nginx:v1 3febe889c87382f1718ef3990d86cd61b59668493f9f5e8d91d6cdba26695691 [root@doc03 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3febe889c873 nginx:v1 "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 0.0.0.0:9999->80/tcp nginx-volume-test2 961213c2f96c nginx:v1 "/docker-entrypoint.…" 17 seconds ago Up 17 seconds 0.0.0.0:8888->80/tcp nginx-volume-test1
在本地创建一个"test.html"的文件并访问
echo "nginx data volume test" > test.html && chmod 644 test.html # 本地请求 [root@doc03 _data]# curl 10.125.7.74:9999/test.html nginx data volume test [root@doc03 _data]# curl 10.125.7.74:8888/test.html nginx data volume test
注意:这里得注意文件权限644
4. 数据卷持久化
删除实例"nginx-volume-test2"
[root@doc03 ~]# docker stop nginx-volume-test2 nginx-volume-test2 [root@doc03 ~]# docker rm nginx-volume-test2 nginx-volume-test3 [root@doc03 ~]# tree /opt/app/Docker/volumes/test-volume /opt/app/Docker/volumes/test-volume └── _data ├── 50x.html └── index.html └── test.html
查看"test-volume"数据目录,文件并未被删除
注意:这里得说明下"/opt/app/Docker/volumes/metadata.db"这个文件,metadata.db,存储路径的元数据并不是动态更新修改,当目录已经创建并关联的容器删除时,其他新建的容器无法使用已经创建过的这个目录,需要手动删除历史使用过的目录,可使用"docker volume --help"查看具体使用方式
五. mount bind持久化
与"volume"不同的是,此方式用户可以自定义数据挂载路径
docker run -d -v host_path:container_path ······
1. 自定义数据存储路径
[root@doc03 Docker]# pwd /opt/app/Docker [root@doc03 Docker]# tree Container_data/ Container_data/ 0 directories, 0 files
2. 实例化一个容器
[root@doc03 Docker]# docker run -d --name nginx-volume-test10 -p 33333:80 -v //opt/app/Docker/Container_data/nginx-volume-test10:/usr/share/nginx/html nginx:v1 2b2a7e4b05b4d0bdefa9f4b6ad32c40a7beadbcbca216bac42103518b97b427b [root@doc03 Docker]# tree Container_data/ Container_data/ └── nginx-volume-test10 1 directory, 0 files [root@doc03 Docker]# tree Container_data/nginx-volume-test10/ Container_data/nginx-volume-test10/
"nginx-volume-test10"数据存储目录自动创建,且目录下不存在nginx主页文件"50x.html"、"index.html"
3. 多容器数据卷共享
创建一个nginx-volume-test11的实例,共享"nginx-volume-test10"文件系统
在这里可以使用"inspect"去核查2个容器之间数据目录是否共享
[root@doc03 Docker]# pwd /opt/app/Docker # "nginx-volume-test11"使用了"ro"只读模式 [root@doc03 Docker]# docker run -d --name nginx-volume-test11 -p 44444:80 -v /opt/app/Docker/Container_data/nginx-volume-test10:/usr/share/nginx/html:ro nginx:v1 ca310b2e5076a7340aaa43e1a7737306ce53ffb7dd8d14f90114b3156e467106
在宿主机上创建访问主页
[root@doc03 Docker]# echo "volume shard test" > Container_data/nginx-volume-test10/index.html [root@doc03 Docker]# chmod 644 Container_data/nginx-volume-test10/index.html
进入"nginx-volume-test10"并追加"test10"内容,通过"nginx-volume-test10"、"nginx-volume-test11"访问主页
[root@doc03 Docker]# docker exec -it nginx-volume-test10 /bin/bash root@2b2a7e4b05b4:/# cd /usr/share/nginx/html/ root@2b2a7e4b05b4:/usr/share/nginx/html# ls index.html root@2b2a7e4b05b4:/usr/share/nginx/html# echo "test10 add content" >> index.html root@2b2a7e4b05b4:/usr/share/nginx/html# cat index.html root@2b2a7e4b05b4:/usr/share/nginx/html# exit exit [root@doc03 Docker]# curl http://10.125.7.74:33333 volume shard test test10 add content [root@doc03 Docker]# curl http://10.125.7.74:44444 volume shard test test10 add content
进入"nginx-volume-test11"尝试追加内容
[root@doc03 Docker]# docker exec -it nginx-volume-test11 /bin/bash root@ca310b2e5076:/# cd /usr/share/nginx/html/ root@ca310b2e5076:/usr/share/nginx/html# echo 1 > index.html bash: index.html: Read-only file system
"nginx-volume-test10"、"nginx-volume-test11"测试说明数据已经共享,但是"nginx-volume-test11"由于设置了"ro"只读权限,没有权限做增删改操作,如果在主机上删除文件,则2个容器的数据也会删除
4. 多容器数据继承
指令模型: docker run -itd --name 子容器名称 --volumes-from 父容器名称 镜像名称 /bin/bash
创建"nginx-volume-test20"实例
[root@doc03 Docker]# docker run -d --name nginx-volume-test20 -p 60000:80 -v //opt/app/Docker/Container_data/nginx-volume-test20:/usr/share/nginx/html nginx:v1 cda5bd44e77c979ddede127322fca7d5a0abe4997be78a4a8973b0700bceb81d
以"nginx-volume-test20" 实例为父容器,创建"nginx-volume-test20.1"子容器
[root@doc03 Docker]# docker run -d --name nginx-volume-test20.1 --volumes-from nginx-volume-test20 nginx:v1 96df84470069a6cb59a1ba160ffd74b1fc0c91f11e60eae9f6d6544a90bf742f
以"nginx-volume-test20.1" 实例为父容器,创建"nginx-volume-test20.1.1"子容器
[root@doc03 Docker]# docker run -d --name nginx-volume-test20.1.1 --volumes-from nginx-volume-test20.1 nginx:v1 4224e166eade5b8348736d31d9f9e3146630bfa92772aea78522a6a323075ec5
nginx-volume-test20.1 继承 nginx-volume-test20、nginx-volume-test20.1.1 继承 nginx-volume-test20.1,继承方自动创建目录
多容器数据场景使用的不多,这里不做过多的演示,只说明个人结论
● 父子容器磁盘共享,所有容器均可对容器卷做读写操作
● 删除父子容器中的某个节点,不会对数据造成损坏、丢失
六. volume、mount bind2者的特点
1. volume
● 数据存储路径由docker程序自身管理
● container 内部目录数据统一在 "$volumes/_data"路径下
● container内数据有文件,则会统一同步至 "$volumes/_data"路径下
● 多个container 使用相同的 "$volumes/_data"时,所有数据共享
● 即使容器被销毁,数据也不会丢失
● 当本地路径不存在时,会自动创建
● 权限控制,当有多个容器共享统一数据时,可以针对部分容器目录只有只读权限(不做演示,test-volume3:/usr/share/nginx/html:ro),此限制只针对容器
● 实例可移植性强,数据存储路径有docker自身管理
● -v参数定义的名称必定是目录,不可能是文件
2. bind mount
● 数据存储路径由用户自身去定义
● container内部有数据文件时,不会迁移至数据存储目录
● 多个container 使用相同的数据存储目录时,所有数据共享
● 即使容器被销毁,数据也不会丢失
● 当本地路径不存在时,会自动创建
● 权限控制,当有多个容器共享统一数据时,可以针对部分容器目录只有只读权限(不做演示,test-volume3:/usr/share/nginx/html:ro),此限制只针对容器
● 可移植性差,因为有用户自定义的host_path参数
● -v 参数即可指明目录也可以指明文件,当指明文件时此文件必须存在