COW技术原理(Copy On Write,写时复制)
Ø 直接映射原始盘的数据内容
Ø 当原始盘的旧数据有修改时,在修改之前自动将旧数据存入前端盘
Ø 对前端盘的修改不回写到原始盘
Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。
如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所隐藏,这就是“写时复制(COW)”机制。
示例
[root@localhost ~]# docker run -it --name b1 --rm busybox /bin/sh
/ # ls
bin dev etc home proc root sys tmp usr var
/ # mkdir data
/ # echo 'hello world' > data/index.htlm
//先启动一个容器 创建一个目录
[root@localhost ~]# docker commit -a 'sean <1@2.com>' -c 'CMD ["/bin/sh"]' -p b1 busybox:v0.1
sha256:df9c91d328620ab63efee4f645d9b7ef90890f2b808f38f048cb36910646cd3f
[root@localhost ~]# docker run -it --name b2 busybox:v0.1
/ #
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # ls data/
index.htlm
/ #
/ # rm -rf data
/ # ls
bin dev etc home proc root sys tmp usr var
/ #
//在另一个终端打开删除
[root@localhost ~]# docker run -it --name b1 --rm busybox /bin/sh
/ # ls
bin dev etc home proc root sys tmp usr var
/ # mkdir data
/ # echo 'hello world' > data/index.htlm
/ # ls
bin data dev etc home proc root sys tmp usr var
/ #
//再回到第一个终端查看并没有删除 ,只是被隐藏
对于这种方式来说,我们去访问一个文件,修改和删除等一类的操作,其效率会非常的低,因为隔着很多层镜像。
而要想绕过这种限制,我们可以通过使用存储卷的机制来实现。
使用存储卷的好处
容器中进程所生成的数据,都保存在存储卷上,从而脱离容器文件系统自身后,当容器被关闭甚至被删除时,都不用担心数据被丢失,实现数据可以脱离容器生命周期而持久,当再次重建容器时,如果可以让它使用到或者关联到同一个存储卷上时,再创建容器,虽然不是之前的容器,但是数据还是那个数据,特别类似于进程的运行逻辑,进程本身不保存任何的数据,数据都在进程之外的文件系统上,或者是专业的存储服务之上,所以进程每次停止,只是保存程序文件,对于容器也是一样;容器就是一个有生命周期的动态对象来使用,容器关闭就是容器删除的时候,但是它底层的镜像文件还是存在的,可以基于镜像再重新启动容器。
但是容器有一个问题,一般与进程的启动不太一样,就是容器启动时选项比较多,如果下次再启动时,很容器会忘记它启动时的选项,所以最好有一个文件来保存容器的启动,这就是容器编排工具的作用。一般情况下,是使用命令来启动操作docker,但是可以通过文件来读,也就读文件来启动,读所需要的存储卷等,但是它也只是操作一个容器,这也是需要专业的容器编排工具的原因。
另一个优势就是容器就可以不置于启动在那台主机之上了,如几台主机后面挂载一个NFS,在各自主机上创建容器,而容器上通过关联到宿主机的某个目录上,而这个目录也是NFS所挂载的目录中,这样容器如果停止或者是删除都可以不限制于只能在原先的宿主机上启动才可以,可以实现全集群范围内调试容器的使用,当再分配存储、计算资源时,就不会再局限于单机之上,可以在集群范围内建立起来,基本各种docker的编排工具都能实现此功能,但是后面严重依赖于共享存储的使用。
为什么要用存储卷
关闭重启容器,数据不受影响。但是删除docker容器,则其更改会全部丢失
因此docker存在的问题有:
1 存储与联合挂在文件系统中,不宜与宿主机访问
2 容器间数据共享不便
3 删除容器其数据会丢失
而要解决以上的问题就是要是有存储卷
存储卷管理
“卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某个目录“绑定(关联)”;
类似于挂载一样,宿主机的/data/web目录与容器中的/container/data/web目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以宿主机向容器供集内容,两者是同步的。
mount名称空间本来是隔离的,可以让两个本来是隔离的文件系统,在某个子路径上建立一定程度的绑定关系,从而使得在两个容器之间的文件系统的某个子路径上不再是隔离的,实现一定程度上共享的效果。
在宿主机上的这个与容器形成绑定关系的目录被称作存储卷。
容器数据的管理
用户在使用docker的 过程中,往往需要查看容器内应用产生的数据,或者需要把容器内的数据进行备份,甚至多个容器之间数据共享,这必然涉及到容器数据的管理操作。
容器中数据管理主要有2种方式:
1 数据卷 (DaTa Volumes)
2 数据卷容器(DaTa Volumes Containers)
容器Volumes使用语法:
Docker Managed Volume
示例,没绑定过的卷
[root@localhost ~]# docker run -it --rm --name b1 -v /data busybox /bin/sh
/ # ls
bin data dev etc home proc root sys tmp usr var
/ #
//创建一个容器
"Mounts": [
{
"Type": "volume",
"Name": "af5b3e55d185ab66e6f06ee177c544984ee56938e58bc635c728ae8aec0429e1",
"Source": "/var/lib/docker/volumes/af5b3e55d185ab66e6f06ee177c544984ee56938e58bc635c728ae8aec0429e1/_data",
"Destination": "/data",
//查看位置
[root@localhost ~]# cd /var/lib/docker/volumes/af5b3e55d185ab66e6f06ee177c544984ee56938e58bc635c728ae8aec0429e1/_data
[root@localhost _data]# ls
[root@localhost _data]# touch abc
[root@localhost _data]# ls
abc
//进入这个路径写一个目录去容器查看
[root@localhost ~]# docker run -it --rm --name b1 -v /data busybox /bin/sh
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # cd data/
/data # ls
abc
/data #
/ # rm -f data/abc
/ # exit
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
//删掉之后去另一边查看
[root@localhost _data]# ls
[root@localhost _data]#
//也随之删掉
示例2 绑定之后的卷
[root@localhost ~]# docker run -it --rm --name b1 -v /web:/data busybox
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # ls data/
/ #
//创建一个容器绑定一个web
[root@localhost ~]# ls /
bin dev home lib media opt root sbin sys usr web
boot etc index.htlm lib64 mnt proc run srv tmp var
//在真机上系统会自动创建一个web
[root@localhost ~]# cd /web
[root@localhost web]# ls
[root@localhost web]# echo 'hello world' > index.htlm
//进入web创建一个文件
/ # cd data/
/data # ls
index.htlm
//此时容器里面也会同步
/data # exit
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
//退出删除后去web查看文件是否存在
[root@localhost web]# ls
index.htlm
[root@localhost ~]# docker run -it --rm --name b1 -v /web:/data busybox
/ # ls data/
index.htlm
/ #
//可以看见删除之后和重新创建之后文件依然存在
用存储卷部署网站
[root@localhost web]# mv ~/123.zip .
[root@localhost web]# ls
123.zip
[root@localhost web]# unzip 123.zip
Archive: 123.zip
inflating: ┼▄┐с╒╧░н╠°╘╛╨б╙╬╧╖╥╗╕Ў╢╝▓╗─▄╦└HTML5═°╥│╨б╙╬╧╖┤·┬ы╧┬╘╪-╙╬╧╖╘┤┬ы-╦╪▓─╦╡├ў.txt
creating: 38234/images/
inflating: 38234/images/gdyx.png
inflating: 38234/images/wu.png
inflating: 38234/images/xiaoren.png
inflating: 38234/images/ygdbns.jpg
inflating: 38234/index.html
creating: 38234/js/
inflating: 38234/js/main.js
inflating: 38234/js/require.js
inflating: ╘┤┬ы╦╪▓─├т╖╤╧┬╘╪.url
inflating: ░о╕°═°-╘┤┬ы-├т╖╤╧┬╘╪.txt
//解压
[root@localhost web]# ls
123.zip
38234
images
index.html
js
[root@localhost web]# rm -rf 123.zip/ 38234
[root@localhost web]# ls
123.zip
images
index.html
js
写一个httpd的网站
[root@localhost ~]# docker run -d --name web -v /web:/usr/local/apache2/htdocs -p 80:80 httpd
11daaf56faf553395a2a604b5e8bba4e2e85f96a2be4b52c4135bdeb83e4f6f0
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11daaf56faf5 httpd "httpd-foreground" 37 seconds ago Up 36 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp web
[root@localhost ~]# ss -ant
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 [::]:80 [::]:*
LISTEN 0 128 [::]:22 [::]:*
接下来访问网站
只读挂载,不影响网站访问
[root@localhost ~]# docker rm -f web
web
[root@localhost ~]# docker run -d --name web -v /web:/usr/local/apache2/htdocs:ro -p 80:80 httpd
ff5a103f26616b2ca45a657d80f97cbd1c2958ba17bbf9100a308f2ee10508ab
root@ff5a103f2661:/usr/local/apache2/htdocs# touch abc
touch: cannot touch 'abc': Read-only file system
/此时在网站里面创建文件不行
[root@localhost web]# touch abc
root@ff5a103f2661:/usr/local/apache2/htdocs# ls
123.zip
abc
images
index.html
js
//在外创建里面可一查看。
数据卷容器
如果用户需要在容器之间共享一些持续更新的数据,最简单的方式就是使用数据卷容器。数据卷容器就是一个普通的容器,专门用他提供数据卷供其他容器挂载使用。方法如下:
创建一个dbdata的容器
[root@localhost ~]# docker run -itd --name dbdata -v /dbdata busybox
0d0d4a72659439e16fd24e848cac4cbc928d21989ba265092d6c6b5eec24ba69
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d0d4a726594 busybox "sh" 5 seconds ago Up 4 seconds dbdata
然后使用Volumes from来挂载dbdata容器中的数据卷
[root@localhost ~]# docker run -itd --name db1 --volumes-from dbdata busybox
878ab7c72adac6d321b70556688cc637f54e1283357b92d643fca7e55c078a0b
[root@localhost ~]# docker run -itd --name db2 --volumes-from dbdata busybox
af6eeef0a534cba93547d0948f4f54db590e2dd7fffd8e7ee3adae8a4a6bdbc0
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
af6eeef0a534 busybox "sh" 5 seconds ago Up 4 seconds db2
878ab7c72ada busybox "sh" 39 seconds ago Up 39 seconds db1
0d0d4a726594 busybox "sh" 4 minutes ago Up 4 minutes dbdata
此时可以发现在db1上创建文件可以在db2上看到
[root@localhost ~]# docker exec -it db1 /bin/sh
/ # ls
bin dev home root tmp var
dbdata etc proc sys usr
/ # cd dbdata/
/dbdata # touch abc
/dbdata # ls
abc
[root@localhost ~]# docker exec -it db2 /bin/sh
/ # ls dbdata/
abc
[root@localhost ~]# docker run -itd --name db3 --volumes-from dbdata busybox
8ead6bdc4f8ed225cbcb1b735bd8fe9c171f7fd1e4f7f7da49437ccab2f52018
[root@localhost ~]# docker exec -it db3 /bin/sh
/ # cd dbdata/
/dbdata # ls
/dbdata # echo 'hello world' > abc
/dbdata # ls
abc
/dbdata # cat abc
hello world
[root@localhost ~]# docker exec -it dbdata /bin/sh
/ # ls dbdata/
abc
/ # cat dbdata/abc
hello world
使用-V删除建立关系的容器,必须全部删掉
[root@localhost ~]# docker exec -it db3 /bin/sh
/ # cd dbdata/
/dbdata # ls
abc
//进入db3
[root@localhost ~]# cd /var/lib/docker/volumes/68731bf3053b730a1e5d4593ab4917943515af52a11c09bde72d3aba97d7fbc3/_data
[root@localhost _data]# ls
abc
//文件在路径中
[root@localhost ~]# docker rm -f db3
db3
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
//删掉db3
[root@localhost _data]# ls
abc
//文件还在
使用-V才能完全删除
利用数据卷迁移数据
[root@localhost ~]# docker run --name worker --volumes-from dbdata -v $(pwd):/backup centos tar cvf /backup/backup.tar /dbdata
用centos镜像创建一个worker容器,使用--volumes-from让worker容器挂载到dbdata的数据卷‘。
使用-v $(pwd):/backup参数来挂在本地当前目录到worker容器的backup目录。
worker容器启动后使用 tar cvf /backup/backup.tar /dbdata命令将dbdata下内容备份为容器内的/backup/backup.tar,寄宿住机当前目录的backup.tar
恢复
[root@localhost ~]# docker -it --name dbdata2 -v /dbdata centos /bin/bash
然后在创建一个容器 挂载到dbdata2 使用untar解压到备份文件所挂载的容器卷即可
[root@localhost ~]# docker run --volumes-from dbdata2 -v $(pwd):/bakup busybox tar xvf /backup/backup.tar