1.Docker镜像由多个只读层叠加而成,启动镜像时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层,前面Docker的第三章节有讲过关于Docker复制底层可读镜像为可读写层的知识内容
2.如果运行中的容器修改了现有的一个已存在文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读层仍然存在,只是被读写层中该文件的副本所隐藏,此即“写时复制(COW)”机制
例子:假如Redis或者MySQl这种对磁盘IO性能较高的应用,数据就不适合放在容器中存储了,先不说容器数据存储的缺点,容器写入本来就是基于底层镜像所复制的一个可读写层面,在容器中运行IO性能要求较高的应用效率显然是不高的
以下总结几点关于Docker数据存储的弊端:
1.正常关闭并重启容器,其数据不会受到影响;但是删除Docker容器,则其更改,数据将会全部丢失
2.存储于联合文件系统中,不易于宿主机访问;关于Docker的第三章有讲Docker的联合文件系统知识
3.容器间数据共享不便
4.删除容器其数据丢失
“卷”是容器的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机的某目录“绑定(关联)”,也不瞎扯什么术语了,“卷”就是我们常用的文件挂载,嘻嘻
例子:上面有说到在容器中存储数据效率指定不高,但是通过挂载的方式把宿主机的文件挂载到容器中,例如宿主机的 /container/data/web/目录挂载到容器的 /data/web目录下,然后在容器中运行redis和mysql这种应用,把应用所产生的数据直接写入到挂载当中,这个时候使用的IO性能就是宿主机磁盘的IO性能,效率也不会缩减;这样挂载的方式也实现了数据一致性,即为容Docker中有四台Web容器,而他们的网页目录都在此挂载的目录中,他们所读取的文件内容是一致的;即使是其中的一台容器因为某种原因而发生了故障,例如redis和mysql这种应用都是属于有状态长连接并且需要消息持久化的应用,应用进程突发故障后,会把该应用自身所占用内存中的数据给持久化道硬盘当中,即使容器挂了之后,但数据已经被持久化磁盘当中,即为主机内的共享目录,数据也不会因容器故障而导致数据丢失;我们刚有讲过容器突发故障后,下次启动容器的时候我们并不一定非要启动上次故障的那台容器,我们可以另外启动一台容器,跑同样的应用,还到相同的挂载目录去取数据,没有硬性限制应用非要启动到哪台容器之上
1.磁盘IO性能的提高
2.数据同步即一致性
3.数据消息持久化
4.没有硬限制
存储卷于创建容器时一同创建,docker run -v 加挂载路径命令,详细后续会讲解,由base image提供的卷中数据会在此期间完成复制
存储卷的初衷是独立于容器的生命周期实现的数据持久化,因此删除容器时既不会删除卷,也不会对哪个应用的卷做垃圾回收操作
Docker有两种类型的卷,每种类型中都在容器中存在一个挂载点,但其在宿主机的位置有所不同
1.Bind mount volume:绑定挂载卷
所谓的绑定挂载卷就是在宿主机上的共享路径你需要人工指定一个特定路径,相同容器也需要你指定一个特定的挂载路径,然后两个已知路径建立关联关系
2.Docker-managed volume:Docker管理卷
所谓的Docker管理卷就是只需在容器中指定一个特定的挂载路径,而宿主机无需指定,会由Docker daemon管理来自动为你在/var/lib/docker下创建一个共享路径,然后和容器的挂载点建立关联关系
1.绑定挂载卷实现方法
#以下内容示范把宿主机的/container/data/web目录挂载到容器的/data/web目录下,如果宿主机或者容器中指定的目录不存在,则自动创建
[root@Docker-node1 ~]# docker run -it --name nginx_volume -v /container/data/web:/data/web nginx:latest /bin/bash
root@fbe2d6177dd7:/# echo 'welcome to nginx_volume
' > /data/web/index.html
root@fbe2d6177dd7:/# exit
exit
[root@Docker-node1 ~]# cat /container/data/web/index.html
<h1>welcome to nginx_volume</h1>
[root@Docker-node1 ~]# docker inspect -f {
{.Mounts}} nginx_volume #docker inspect获取容器的元数据,-f指定返回值得模板文件
[{
bind /container/data/web /data/web true rprivate}] #可以看到此Mounts采用bind绑定方式
2.Docker管理卷
[root@Docker-node1 ~]# docker run -it --name busybox_voulme -v /opt/data/busybox busybox:latest /bin/sh
/ # echo 'welcome to busybox_volume
' > /opt/data/busybox/index.html
/ # exit
[root@Docker-node1 ~]# docker inspect -f {
{.Mounts}} busybox_voulme #查看宿主机的共享目录被分配到了/var/lib/docker那个目录下
[{
volume 2d799e4637d5a6eed5bf0c5ef1242ae9618a0d624af3730f95aa367432a34fad /var/lib/docker/volumes/2d799e4637d5a6eed5bf0c5ef1242ae9618a0d624af3730f95aa367432a34fad/_data /opt/data/busybox local true }]
[root@Docker-node1 ~]# cat /var/lib/docker/volumes/2d799e4637d5a6eed5bf0c5ef1242ae9618a0d624af3730f95aa367432a34fad/_data/index.html
<h1>welcome to busybox_volume</h1>
在上一章Docker网络实践中有讲到过Docker联盟式网络,联盟式网络是指容器之间共享了名称空间IPC、UTS、Network;隔离了User、PID、Mount,这里讲解使用联盟式网络不仅共享IPC、UTS、Network还有Mount文件系统
首先我们先创建一个基于架构支持的容器,然后Nginx、Tomcat、MySQl容器都与此容器做成联盟式网络,我们的Tomcat和MySQL只需要监听lo接口即可,使用Nginx容器来进行反代功能,因Tomcat和MySQl并没有在外部暴露任何端口信息,从而保证了这两台容器的隐蔽性;这三台的挂载存储卷都在宿主机的共享目录内,当Nginx收到客户端的请求报文后,先拆封此报文内是否含有jsp请求文件,如果有Nginx则把jsp请求报文通过本地的lo接口转发给Tomcat进行处理,如果没有,Nginx直接去挂载点去取需要返回的报文信息进行返回。
Nginx、Tomcat、MySQL、这三台容器对外看来就像一台主机容器而已,因为他们是联盟式网络,共享同一个主机名、域名、IP协议栈等
1.创建基础架构支持容器
[root@Docker-node1 ~]# docker run -it --name busybox -v /data/web:/data/web/html busybox:latest
/ # echo 'welcome to busybox
' > /data/web/html/index.html
/ # exit
[root@Docker-node1 ~]# docker start busybox
[root@Docker-node1 ~]# docker inspect -f {
{.NetworkSettings.Networks.bridge.IPAddress}} busybox
172.17.0.2
2.创建Nginx容器并与基础架构容器busybox成为联盟式网络
#这里为测试镜像就全部采用了busybox,因为该镜像轻巧
[root@Docker-node1 ~]# docker run -it --name nginx_bosybox --network container:busybox --volumes-from busybox busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # cat /data/web/html/index.html
<h1>welcome to busybox</h1>
[root@Docker-node1 ~]# docker start nginx_bosybox
3.创建Tomcat容器并与基础架构busybox成为联盟式网络
[root@Docker-node1 ~]# docker run -it --name tomcat_bosybox --network container:busybox --volumes-from busybox busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # cat /data/web/html/index.html
<h1>welcome to busybox</h1>
[root@Docker-node1 ~]# docker start tomcat_bosybox
4.创建MySQl容器并与基础架构成为联盟式网络
[root@Docker-node1 ~]# docker run -it --name mysql_bosybox --network container:busybox --volumes-from busybox busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # cat /data/web/html/index.html
<h1>welcome to busybox</h1>
[root@Docker-node1 ~]# docker start mysql_bosybox
5.总结
如果可以请自行下载相应docker镜像进行修改容器配置,来做相对比较健全的测试,如:模拟请求报文给Nginx,测试Nginx和Tomcat的动静分离,测试MySQl的持久化等等
[root@Docker-node1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55914ec04a3e busybox:latest "sh" 2 minutes ago Up About a minute mysql_bosybox
8f73416d30c0 busybox:latest "sh" 3 minutes ago Up About a minute tomcat_bosybox
310193ffddc3 busybox:latest "sh" 6 minutes ago Up About a minute nginx_bosybox
56c9db128fd7 busybox:latest "sh" 19 minutes ago Up 15 minutes busybox