在了解Docker数据持久化以前,须要对Docker的存储类型有一个简单的了解,执行如下命令便可看出:html
[root@docker01 ~]# docker info //查看Docker的详细信息 Containers: 1 //一共有几个容器 Running: 1 //正在运行的有几个容器 Paused: 0 //挂起、暂停的有几个容器 Stopped: 0 //中止的有几个容器 Images: 2 //有几个镜像 Server Version: 18.09.0 //docker的版本信息 Storage Driver: overlay2 //存储驱动类型为overlay2 Backing Filesystem: xfs //支持的文件系统:xfs Supports d_type: true Native Overlay Diff: false Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local //本地存储 Network: bridge host macvlan null overlay //支持的网络类型 Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-514.el7.x86_64 //内核信息 Operating System: CentOS Linux 7 (Core) //操做系统 OSType: linux //操做系统类型 Architecture: x86_64 CPUs: 4 //CPU个数 Total Memory: 3.686GiB //内存容量 Name: docker01 ID: X6ON:W73P:YWXD:NV7U:3C2J:RXH3:GNPO:SYIP:FF53:CNFN:HSN3:EZG2 Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Registry Mirrors: //采用的加速器信息 https://weimtsj8.mirror.aliyuncs.com/ Live Restore Enabled: false Product License: Community Engine
在docker中实现数据持久化有两种方式:Bind mount和Docker Manager Volume。linux
Bind mount和Docker Manager Volume的区别:nginx
Bind mount数据持久化的方式,若是是挂载本地的一个目录,则容器内对应的目录下的内容会被本地的目录覆盖掉,而Docker Manager Volume这种方式则不会,无论哪一种方式的持久化,在容器被销毁后,本地的数据都不会丢失。
使用“-v”选项挂载时,Bind mount明确指定了要挂载docker host本地的某个目录到容器中,而Docker Manager Volume则只指定了要对容器内的某个目录进行挂载,而挂载的是docker host本地的哪一个目录,则是由docker来管理的。web
如下数据卷容器挂载的方式就是Bind mount实现方式。docker
实现的大概思路以下:apache
1.运行一个容器做为数据卷容器,挂载本地目录到容器内的本地目录,无需所挂载的源目录或目标挂载点是否存在,docker会自动建立相应的目录的,也无需考虑使用哪一个镜像来运行这个容器,任意镜像均可以;
2.以后不管运行多少容器,均可以使用--volumes-from选项来指定第一个运行的容器进行数据持久化;
3.实现的效果为:挂载数据卷容器实现数据持久化的容器,会自动将数据卷容器挂载的本地目录挂载到该容器自己(自己的挂载点与数据卷容器的挂载点自动保持一致),也仅仅只会挂载数据卷容器实现了数据持久化的目录到本身自己,而不是数据卷容器的所有目录。json
上面实现的效果可能我表达的不够好,举个例子 :
有A、B、C这三个容器,其中A做为数据卷容器,挂载了本地的/data/web01和/data/web02这两个目录到容器内的/usr/share/nginx/html/和/data这两个目录。
容器B和容器C在运行之初,经过--volumes-from选项来指定容器A的名称或ID,那么最终实现的效果就是,A、B、C这三个容器内都会存在/usr/share/nginx/html及/data这两个目录,而且是实现了数据持久化的,对应的本地目录都是/data/web01和/data/web02。vim
持久化存储:本质上是DockerHost文件系统中的目录或文件,可以直接被Mount到容器的文件系统中。在运行容器时,能够经过-v 实现。浏览器
Bind mount的特色:网络
Data Volume是目录或文件,不能是没有格式化的磁盘(块设备);
容器能够读写volume中的数据;
随源文件变化而变化;
volume数据能够永久保存,即便使用它的容器已经被销毁;
示例:
[root@localhost ~]# cd /tmp/ [root@localhost tmp]# mkdir /html [root@localhost tmp]# echo "huan ying ni zjz" >> /html/index.html //建立测试页面 [root@localhost tmp]# docker run -itd --name testweb -p 80:80 -v /html:/usr/share/nginx/html nginx:latest //运行容器并使用“-v”选项指定挂载目录,前面为docker host的目录,“:”后面为容器中的目录 [root@localhost tmp]# curl 127.0.0.1 //能够看到挂载已经生效 huan ying ni zjz [root@localhost tmp]# echo "hello" >> /html/index.html [root@localhost tmp]# curl 127.0.0.1 //这种方式能够看出当源文件发生变化时,目标文件也会随之发生变化 huan ying ni zjz hello [root@localhost tmp]# docker inspect testweb //查看容器的详细信息
注意:
DockerHost上须要被挂着的源文件或目录,必须是已经存在,不然,当作的一个目录挂着到容器中;
默认挂载到容器内的文件,容器是有读写权限。能够在运行容器“-v”选项后边加“:ro” 选项来限制容器的写入权限;
能够挂载单独的文件到容器内部,使用场景:若是不想对整个目录进行覆盖,而只但愿添加某个文件,就可使用挂载单个文件;
示例:
[root@docker ~]# docker run -itd --name test1 -v /usr/share/nginx/html nginx:latest //这种方式“-v”选项后,只需添加容器中的目录便可 [root@docker ~]# docker inspect test1
[root@docker~]#ls /var/lib/docker/volumes/46d00301afb2b9c8d5279475d50d9242470af37969fa52338e916de1e35a6e93/_data/ 50x.html index.html //能够看出宿主机上的目录就是容器中挂载的目录
这种方式特色:
会随着源文件的变化而变化,跟Bind mount效果是同样的!
删除容器的操做,默认不会对dockerhost主机上的原文件进行删除,若是想要在删除容器是将原文件删除,能够在删除容器时添加“-v”选项,(通常状况下不建议使用,由于文件有可能被其余容器就使用);
Volume container:给其余容器提供volume存储卷的容器。而且它能够提供bind mount,也能够提供docker manager volume。
[root@docker ~]# docker create --name vc_data -v /html:/usr/share/nginx/html busybox:latest //建立一个容器(无须运行) [root@docker ~]# docker run -itd --name test3 -P --volumes-from vc_data nginx:latest //使用“--volumes-from”来挂载vc_data容器中的数据间到新的容器test3 [root@docker ~]# docker ps //查看其映射的端口 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0c0429f3e8c0 nginx:latest "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:32768->80/tcp test3 [root@docker ~]# curl 127.0.0.1:32768 //测试效果 huan ying ni zjz hello
注意:以上方式在源目录删除后,容器中的数据也会发生丢失现象!
能够采用编写dockerfile文件的方式,将目录或文件写到镜像中,而后根据镜像生成容器,才可保证原数据丢失,容器中的数据不会发生变化!
因为这种方式随机性、灵活性太差,这里就很少作介绍了这样就能够经过数据卷容器实现容器之间的数据共享。
经过以上机制,即便容器在运行过程当中出现故障,用户也不用担忧数据发生丢失。若是发生意外,只需快速从新建立容器便可!
注意:生产环境中最注重的就是存储的可靠性,以及存储的可动态扩展性,必定要在作数据卷时考虑到这一点,在这方面比较出色的还要数GFS文件系统了,我上面只是作了简单的配置,若在生产环境中,必定要好好考虑,就好比上面作的镜像卷容器,就能够在宿主机本地挂载GFS文件系统,而后建立镜像卷容器时,将挂载GFS的目录映射到容器中的镜像卷,这样才是一个合格的镜像卷容器。
Bind Mount 和 Docker Manager Volume的特色;
docket1 | docker2 | docker3 |
---|---|---|
httpd | httpd | nfs |
要求:docker01和docker02的主目录,是同样的。
docker3的操做
[root@nfs ~]# yum -y install nfs-utils #安装nfs [root@nfs ~]# mkdir /datashare #建立共享目录 [root@nfs ~]# vim /etc/exports #设置权限 /datashare *(rw,sync,no_root_squash) [root@nfs ~]# systemctl start rpcbind [root@nfs ~]# systemctl enable rpcbind [root@nfs ~]# systemctl start nfs-server.service #启动 [root@nfs ~]# systemctl enable nfs-server.service #开机自启 [root@nfs ~]# showmount -e #验证 Export list for nfs: /datashare * [root@nfs ~]# cd /datashare/ [root@nfs datashare]# touch 123.txt #建立测试文件 [root@nfs datashare]# echo "12312321312" > 123.txt [root@nfs datashare]# cat 123.txt 12312321312 [root@nfs datashare]# echo "hell world" > index.html
docker1上的操做
#也需安装nfs [root@docker1 ~]# showmount -e 192.168.10.54 #验证 Export list for 192.168.10.54: /datashare * [root@docker1 ~]# mkdir /htdocs #建立目录 [root@docker1 htdocs]# mount -t nfs 192.168.10.54:/datashare /htdocs #将/htdocs目录挂载到192.168.10.54:/datashare 下 [root@docker1 ~]# cd /htdocs/ [root@docker1 htdocs]# pwd /htdocs [root@docker1 htdocs]# ls 123.txt index.html [root@docker1 htdocs]# cat 123.txt 12312321312 [root@docker1 ~]# docker run -itd --name web1 -P -v /htdocs:/usr/local/apache2/htdocs httpd:latest [root@docker1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ed9710a468a2 httpd:latest "httpd-foreground" 43 seconds ago Up 41 seconds 0.0.0.0:32768->80/tcp web1
docker2上的操做和docker1操做同样
#也需安装nfs [root@docker2 ~]# showmount -e 192.168.10.54 #验证 Export list for 192.168.10.54: /datashare * [root@docker2 ~]# mkdir /htdocs [root@docker2 htdocs]# mount -t nfs 192.168.10.54:/datashare /htdocs [root@docker2 ~]# cd /htdocs/ [root@docker2 htdocs]# pwd /htdocs [root@docker2 htdocs]# ls 123.txt index.html [root@docker2 htdocs]# cat 123.txt 12312321312 [root@docker2 htdocs]# docker run -itd --name web2 -P -v /htdocs:/usr/local/apache2/htdocs httpd:latest [root@docker2 htdocs]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2a5ddae0894d httpd:latest "httpd-foreground" 7 seconds ago Up 5 seconds 0.0.0.0:32769->80/tcp web2
此时,用浏览器访问,两个WEB服务的主界面是同样。但若是,NFS服务 器上的源文件丢失,则两个web服务都会异常
想办法将源数据写入镜像内,在基于镜像作一个vc_data容器,因此咱们 在docker01和docker02上先手动建立镜像
docker1上操做
[root@docker1 htdocs]# vim Dockerfile FROM busybox ADD index.html /usr/local/apache2/htdocs/index.html VOLUME /usr/local/apache2/htdocs [root@docker1 htdocs]# docker build -t back_data . [root@docker1 htdocs]# docker create --name back_container1 back_data:latest [root@docker1 htdocs]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE back_data latest bfc2314995b5 24 seconds ago 1.22MB [root@docker1 htdocs]# docker run -itd --name web3 -P --volumes-from back_container1 httpd:latest [root@docker1 htdocs]# docker inspect web3
**总结:<br/>1)解决容器跨主机数据共享的方案: NFS<br/>2)容器与容器的数据共享: 基于某个容器而来(--volumes-from选 项),意味着这些容器和vc容器的数据存储是同样的。**