一.cow机制
Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层。
如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所隐藏,这就是“写时复制(COW)”机制
对于这种方式来说,我们去访问一个文件,修改和删除等一类的操作,其效率会非常的低,因为隔着很多层镜像。而要想绕过这种限制,我们可以通过使用存储卷的机制来实现
二.什么是存储卷
存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时,容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录
在宿主机上的这个与容器形成绑定关系的目录被称作存储卷
三.使用存储卷的好处
- 防止数据的丢失。即使容器关闭或被删除,只要不删除容器绑定在宿主机上的存储目录,那我们就不用担心数据丢失
- 摆脱容器和主机之间的限制。可以在任意一台部署了docker的主机上运行容器,而且数据可以放置在一个共享存储文件系统上,比如nfs
四.为什么要使用存储卷
关闭并重启容器,其数据不受影响,但删除Docker容器,则其更改将会全部丢失。
因此Docker存在的问题有:
- 存储于联合挂载文件系统中,不易于宿主机访问
- 容器间数据共享不便(容器之间本身是隔离的)
- 删除容器其数据会丢失
因此我们使用存储卷来解决这些问题
五.存储卷管理方式
存储卷(Data Volume)于容器初始化时被自动创建,由base image提供的卷中的数据会于此期间完成复制。
Volume的初衷是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对未被引用的卷做垃圾回收操作。
存储卷为Docker提供了独立于容器的数据管理机制,我们可以把镜像想象成静态文件,例如“程序”,把卷类比为动态内容,例如“数据”。所以镜像可以重用,而卷则可以共享。
卷实现了“程序(镜像)”和“数据(卷)”的分离,以及“程序(镜像)”和“制作镜像的主机”的分离,用户制作镜像时无须再考虑镜像运行的容器所在的主机的环境
六.存储卷的分类
Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同:
- Bind mount volume(绑定挂载卷)
a volume that points to a user-specified location on the host file system(指向主机文件系统上用户指定位置的卷)
- Docker-managed volume (Docker-managed体积)
the Docker daemon creates managed volumes in a portion of the host’s file system that’s owned bye Docker(Docker守护进程在bye Docker拥有的主机文件系统的一部分中创建托管卷)
七.容器数据管理
用户在使用Docker的过程中,往往需要能查看容器内应用产生的数据,或者需要把容器内的数据进行备份,甚至多个容器之间进行数据的共享,这必然涉及容器的数据管理操作。
容器中管理数据主要有两种方式:
数据卷(Data Volumes)
数据卷容器(Data Volumes Containers)
容器Volume使用语法:
1.docker管理的卷
在容器本地目录或者容器内删除或者增加,都会同步增删
语法为:docker run -it --name CONTAINER_NAME -v VOLUMEDIR IMAGE_NAME
[root@localhost ~]# docker run -it --rm --name b1 -v /data busybox /bin/sh //运行一个容器,并且创建data目录
/ # ls
bin data dev etc home proc root sys tmp usr var
//到另一台终端
[root@localhost ~]# docker inspect b1 | grep "Source" //在主机上查看容器data目录的详细路径
"Source": "/var/lib/docker/volumes/fc996fd70b70ab6a80c28eaa8ef6e61c4e13aa1f1ed9c3fbbb739ef3b82b68b3/_data",
[root@localhost ~]# cd /var/lib/docker/volumes/fc996fd70b70ab6a80c28eaa8ef6e61c4e13aa1f1ed9c3fbbb739ef3b82b68b3/
[root@localhost fc996fd70b70ab6a80c28eaa8ef6e61c4e13aa1f1ed9c3fbbb739ef3b82b68b3]# ls
_data
[root@localhost fc996fd70b70ab6a80c28eaa8ef6e61c4e13aa1f1ed9c3fbbb739ef3b82b68b3]# cd _data/
[root@localhost _data]# ls
[root@localhost _data]# touch 1234 //创建一个文件用于测试
[root@localhost _data]# ls
1234
//回到容器内查看data,发现我们刚才创建的测试文件
/ # ls data
1234
2.用户绑定的挂载卷
与主机目录绑定,即使容器删除,文件数据依旧存在
语法:docker run -it --name CONTAINER_NAME -v HOSTDIR:VOLUMEDIR IMAGE_NAME
[root@localhost ~]# docker run -it --rm --name b1 -v /web:/data busybox //将真机的web目录与容器内的data目录绑定
/ # ls
bin data dev etc home proc root sys tmp usr var
//真机写入文件
[root@localhost ~]# ls /
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr web
[root@localhost ~]# cd /web/
[root@localhost web]# ls
[root@localhost web]# echo 'yyds' > index.html
[root@localhost web]# ls
index.html
[root@localhost web]# cat index.html
yyds
//容器内同步出现
/ # cd data/
/data # ls
index.html
/data # cat index.html
yyds
/data # exit
[root@localhost ~]# docker ps -a //退出则删除容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
//删除了容器,文件依然存在
[root@localhost web]# ls
index.html
八.在容器中使用数据卷
使用数据卷内容部署一个网站
网站内容来自源码之家
地址如下:
HTML源码下载_HTML网站源码_HTML源代码下载_源码之家
参数-p ——暴露端口号,使我们可以访问容器
//将下载好的源码包移到虚拟机中
[root@localhost ~]# yum install -y unzip //下载安装解压工具
[root@localhost web]# mv ~/chishenme.zip . //将根目录下的源码包复制到web
[root@localhost web]# ls
chishenme.zip
[root@localhost web]# unzip chishenme.zip
[root@localhost web]# ls
chishenme chishenme.zip
[root@localhost web]# mv chishenme/* .
[root@localhost web]# ls
服务器之家.url chishenme ic.ico index.html
精品免费商业源码下载.url chishenme.zip img
//运行一个容器,将源码所在的主机目录作为数据卷绑定,并且查看效果
[root@localhost ~]# docker run -d --name web -v /web:/user/local/apache2/htdocs -p 80:80 httpd
12c1c88f75134921ae3a42e46f340d71ef8aca005a5bab7f070721aff51cab38
[root@localhost ~]# ss -antl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
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 [::]:*
效果图
用只读的方式运行容器
Docker挂载数据卷的默认权限是读写(rw),用户也可以通过(ro)指定为只读
//在绑定数据卷最后加上:ro即可设置为只读
[root@localhost ~]# docker run -d --rm --name web -v /web:/usr/local/apache2/htdocs:ro -p 80:80 httpd
7fc4d7023509617d1ac36e3c767c7f4f897fc57d95e8daf294e9955f4261f425
//此时进入容器,只可读取,不能修改
[root@localhost ~]# docker exec -it web /bin/bash
root@7fc4d7023509:/usr/local/apache2# ls
bin build cgi-bin conf error htdocs icons include logs modules
root@7fc4d7023509:/usr/local/apache2# cd htdocs/
root@7fc4d7023509:/usr/local/apache2/htdocs# ls
ic.ico img index.html
root@7fc4d7023509:/usr/local/apache2/htdocs# touch abc
touch: cannot touch 'abc': Read-only file system //只读
[root@localhost web]# touch abc //宿主机内依然可以创建
[root@localhost web]# ls
abc ic.ico img index.html
root@7fc4d7023509:/usr/local/apache2/htdocs# ls //容器内照常可以查看
abc ic.ico img index.html
挂载一个本地主机文件作为数据卷
参数-v——可以从主机挂载单个文件到容器中作为数据卷
[root@localhost ~]# docker run -it --rm -v ~/.bash_history:/.bash_history centos /bin/bash
这样就可以记录在容器输入过的命令历史了。
如果直接挂载一个文件到容器,使用文件编辑工具,包括vi或者sed去修改文件内容的时候,可能会造成inode的改变,这样将会导致错误。所以推荐的方式是直接挂载文件所在的目录
九.数据卷容器
如果用户需要在容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器其实就是一个普通的容器,专门用它提供数据卷供其他容器挂载使用,方法如下:
1.创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/data
[root@localhost ~]# docker run -itd --name dbdata -v /data busybox
223c2848359b285de37817ac0dded0fafc7b29bbee25ab9d0aec5ebea88a9a1b
2.在其他容器中使用–volumes-from来挂载dbdata容器中的数据卷,例如创建db1和db2两个容器,并从dbdata容器挂载数据卷
[root@localhost ~]# docker run -itd --name db1 --volumes-from dbdata busybox
[root@localhost ~]# docker run -itd --name db2 --volumes-from dbdata busybox
3.容器db1和db2都挂载同一个数据卷到相同的/data目录
三个容器任何一方在该目录下的写入,其他容器都可以看到
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fe65631219b7 busybox "sh" About a minute ago Up About a minute db2
6271b1c40fd9 busybox "sh" About a minute ago Up About a minute db1
223c2848359b busybox "sh" 2 minutes ago Up 2 minutes dbdata
例如,在db1容器中创建一个test文件
[root@localhost ~]# docker exec -it db1 /bin/sh
/ # ls
bin data dev etc home proc root sys tmp usr var
/ # cd data/
/data # touch test
/data # ls
test
在db2容器中查看
[root@localhost ~]# docker exec -it db2 /bin/sh
/ # ls /data/
test
在dbdata容器中查看
[root@localhost ~]# docker exec -it dbdata /bin/sh
/ # ls data/
test
可以多次使用–volumes-from参数来从多个容器挂载多个数据卷。还可以从其他已挂载了容器卷的容器来挂载数据卷
[root@localhost ~]# docker run -itd --name db3 --volumes-from db2 busybox
20d25b4ffb2a382ddd61a3b162d8e29ea1022833f84d1529359dc2e2610b5a96
[root@localhost ~]# docker exec -it db3 /bin/sh
/ # ls /data/
test
使用–volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态
如果删除了挂载的容器(包括dbdata、db1和db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式使用docker rm -v命令来指定同时删除关联的容器
[root@localhost ~]# docker rm -f dbdata db1 db2
dbdata
db1
db2
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
20d25b4ffb2a busybox "sh" About a minute ago Up About a minute db3
[root@localhost ~]# docker rm -f -v db3
db3
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10.利用数据卷容器迁移数据
可以利用数据卷容器对其中的数据卷进行备份、恢复,以实现数据的迁移
备份
[root@localhost ~]# docker run -itd --name test -v /data busybox //创建一个容器用于测试
34237d852730ce6dbfcb8ca28a3b48bc27c96298a8600c007c62136083cd2da1
[root@localhost ~]# docker exec -it test /bin/sh
/ # cd /data/
/data # echo "yyds" > index.html //在容器内创建测试文件
//在另一台终端上查看
[root@localhost ~]# docker run --name zsh --volumes-from test -v $(pwd):/backup httpd tar cvf /backup/backup.tar /data
tar: Removing leading `/' from member names
/data/
/data/index.html
[root@localhost ~]# ls
anaconda-ks.cfg backup.tar
[root@localhost ~]# tar -xf backup.tar
[root@localhost ~]# ls
anaconda-ks.cfg backup.tar data
[root@localhost ~]# cat data/index.html
yyds
随便什么镜像都行创建出一个容器 用volumes-from zsh容器的数据来自test容器 -v 宿主机当前位置:zsh容器创建的backup目录 压缩目录backup 为backup.tar 到宿主机当前目录下(backup的数据来自于容器test的data目录)
恢复
[root@localhost ~]# docker run -it --name test1 -v /data busybox /bin/sh //创建一个容器用于测试
/ # ls /data/ //此时该目录下没有内容
//test2的数据来自与于主机当前目录 解压backup.tar
[root@localhost ~]# docker run -it --rm --volumes-from test1 -v $(pwd):/backup busybox tar xf /backup/backup.tar
//再次开启容器查看
/ # ls /data/
index.html
/ # cat /data/index.html
yyds