在生产环境中使用Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。容器中的管理数据主要有两种方式∶
数据卷(Data Volumes)∶容器内数据直接映射到本地主机环境(对数据进行持久化)
数据卷容器(Data Volume Containers)∶使用特定容器维护数据卷(多个容器之间的数据共享)
数据卷
数据卷(Data Volumes)是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux 中的mount 行为。数据卷可以提供很多有用的特性∶
(1)数据卷可以在容器之间共享和重用,容器间传递数据将变得高效与方便
(2)对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作
(3)对数据卷的更新不会影响镜像,解耦开应用和数据
(4)卷会一直存在,直到没有容器使用,可以安全地卸载它。
1. 创建数据卷
Docker提供了 volume子命令来管理数据卷,如下命令可以快速在本地创建一个数据卷∶
[root@www ~]# docker volume create -d local test
test
此时,查看/var/1ib/docker/volumes 路径下,会发现所创建的数据卷位置∶
[root@www ~]# ls -ld /var/lib/docker/volumes/test
drwxr-xr-x 3 root root 19 Jul 29 15:42 /var/lib/docker/volumes/test
除了create子命令外,docker volume 还支持inspect(查看详细信息)、ls(列出已有数据卷)、prune(清理无用数据卷)、rm(删除数据卷)等,可以自行实践。
[root@www ~]# docker volume inspect test
[
{
"CreatedAt": "2020-07-29T15:42:32+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/test/_data",
"Name": "test",
"Options": {},
"Scope": "local"
}
]
[root@www ~]# docker volume ls
DRIVER VOLUME NAME
local test
2.绑定数据卷
除了使用volume子命令来管理数据卷外,还可以在创建容器时将主机本地的任意路径挂载到容器内作为数据卷,这种形式创建的数据卷称为绑定数据卷。
在用docker 【container】 run命令的时候,可以使用-mount选项来使用数据卷。-mount 选项支持三种类型的数据卷,包括∶
(1)volume∶普通数据卷,映射到主机/var/lib/docker/volumes路径下
(2) bind∶绑定数据卷,映射到主机指定路径下
(3) tmpfs∶临时数据卷,只存在于内存中。
下面使用centos7-ansible镜像创建一个容器,并创建一个数据卷挂载到容器的/tmp目录∶
[root@www ~]# docker run -itd -p 6322:22 --name os1 --privileged=true --mount type=bind,source=/webapps,destination=/tmp ansible/centos7-ansible
bce572d1ed1936fe5c822d8dd791e2c1e62ac9e1cfb29f3cbdaa8181d6ff14be
[root@www ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bce572d1ed19 ansible/centos7-ansible "/bin/bash" 5 seconds ago Up 3 seconds 0.0.0.0:6322->22/tcp os1
[root@www ~]# ll /webapps/
total 0
-rw-r--r-- 1 root root 0 Jul 26 11:27 c.txt
-rw-r--r-- 1 root root 0 Jul 26 11:20 hhhhhhhhh
-rw-r--r-- 1 root root 0 Jul 26 11:28 xxxxx
[root@www ~]# docker exec -it bce572d1ed19 ls /tmp/
c.txt hhhhhhhhh xxxxx
上述命令等同于使用旧的-v标记可以在容器内创建一个数据卷∶
[root@www ~]# docker run -itd -p 6323:22 --name os2 --privileged=true -v /webapps:/tmp ansible/centos7-ansible
280eae20f120b7fba91a864a0b84bee89d57ab7a79ed135fe1664ebec2cec6a1
[root@www ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
280eae20f120 ansible/centos7-ansible "/bin/bash" 3 seconds ago Up 3 seconds 0.0.0.0:6323->22/tcp os2
[root@www ~]# docker exec -it 280 ls /tmp
c.txt hhhhhhhhh xxxxx
这个功能在进行应用测试的时候十分方便,比如用户可以放置一些程序或数据到本地目录中实时进行更新,然后在容器内运行和使用。(如web应用的发布目录)
另外,本地目录的路径必须是绝对路径,容器内路径可以为相对路径。如果目录不存,docker会自动创建。
Docker挂载数据卷的默认权限是读写(rw),用户也可以通过ro指定为只读, 加了∶ro 之后,容器内对所挂载数据卷内的数据就无法修改了,举个例子如下:
[root@www ~]# docker run -itd -p 6324:22 --name os4 --privileged=true -v /webapps:/tmp:ro ansible/centos7-ansible
e954ddba363ef9518a57d7e4bf2608ccb661c090d47900aa22d7da428bec5140
[root@www ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e954ddba363e ansible/centos7-ansible "/bin/bash" 3 seconds ago Up 2 seconds 0.0.0.0:6324->22/tcp os4
[root@www ~]# docker exec -it e954 /bin/bash
[root@e954ddba363e ansible]# cd /tmp/
[root@e954ddba363e tmp]# ls
c.txt hhhhhhhhh xxxxx
[root@e954ddba363e tmp]# touch a.txt
touch: cannot touch 'a.txt': Read-only file system
[root@e954ddba363e tmp]# exit
exit
[root@www ~]# touch /webapps/a.txt
[root@www ~]# docker exec -it e954 ls /tmp
a.txt c.txt hhhhhhhhh xxxxx
如果直接挂载一个文件到容器,使用文件编辑工具,包括vi或者 sed--in-place 的时候,可能会造成文件inode的改变。从Docker 1.1.0起,这会导致报错误信息。所以推荐的方式是直接挂载文件所在的目录到容器内。
数据卷实战举例说明
什么是容器数据卷?来看看Docker的理念:
将应用与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的容器之间希望有可能共享数据。Docke容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来, 那么当容器删除后,数据自然也就没有了
为了能保存数据在docker中我们使用卷,容器数据卷能做什么
1.容器数据的持久化
2.容器之间继承和共享数据
当我们启动一个tomcat容器,该容器运行中里面数据也在发生变化,比如日志在变化,如果使用这条命令,那么容器里面的数据都会丢失,因为数据是放在容器里面的。
[root@localhost ~]# docker rm -f $(docker ps -aq)
88a5d97862ea
52c8a7cd8ba9
有些时候希望数据持久化能够保存下来,那么就可以使用容器数据卷,docker容器在运行的时候是隔离的,容器卷可以实现容器之间的数据共享,说白了容器数据卷的目的就是为了数据的持久化。
添加数据卷的方式,直接使用命令去添加:
docker run -it -v /宿主机目录:/容器目录 centos /bin/bash
-v就是容器卷的意思
举例说明第一则
[root@localhost data]# docker run -itd -v /root/data:/root/data --privileged=true centos7-ssh /bin/bash
3a09ccd56cfb30be4a9e264e4ce4a8fa9c42800c78b36225e22ee8e4818827fe
[root@localhost data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3a09ccd56cfb centos7-ssh "/bin/bash" 20 seconds ago Up 19 seconds trusting_shaw
[root@localhost data]# docker exec -it 3a09ccd56cfb /bin/bash
[root@3a09ccd56cfb ansible]# cd /root/data/
[root@3a09ccd56cfb data]# ls
hots.txt
[root@3a09ccd56cfb data]# exit
exit
[root@localhost data]# echo "hots" > /root/data/hots.txt 在宿主机添加数据
[root@localhost data]# docker exec 3a09ccd56cfb cat /root/data/hots.txt
Hots
#可以看到容器里面的数据和宿主机的数据是共享的,是不是有点像linux的硬链接
[root@localhost data]# pwd
/root/data
[root@localhost data]# touch a.txt
[root@localhost data]# docker exec 3a09ccd56cfb ls /root/data
a.txt
hots.txt
举例说明第二则
#Tomcat容器目录在/usr/local/tomcat/webapps
[root@localhost data]# docker run -itd -p 8080:8080 ashince/tomcat8 /bin/bash
9e18d88e4c6d1504a579ba6b8377b0f0644fd397631a6dc1d9e09972612ca4f0
[root@localhost data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e18d88e4c6d ashince/tomcat8 "/bin/bash" 4 seconds ago Up 2 seconds 0.0.0.0:8080->8080/tcp jovial_goodall
[root@localhost data]# docker exec -it 9e18d88e4c6d /bin/bash
root@9e18d88e4c6d:/usr/local/tomcat# cd /usr/local/tomcat/webapps/
root@9e18d88e4c6d:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
#如果要发布项目需要将项目拷贝到容器里面的/usr/local/tomcat/webapps/
下面,能不能在宿主机下面建立这么一个容器卷,和宿主机目录挂钩,在宿主机里面加war包,对应的容器里面的tomcat也有该war包
[root@localhost data]# docker run -itd -p 8080:8080 -v /webapps:/usr/local/tomcat/webapps --privileged=true ashince/tomcat8
eff93bd04e9e45b9f78185ea376aed9e91c9685eccc3d8cf88bde6c83ea718da
[root@localhost data]# ll /webapps/
total 0
[root@localhost data]# cd
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eff93bd04e9e ashince/tomcat8 "catalina.sh run" 59 seconds ago Up 58 seconds 0.0.0.0:32768->8080/tcp brave_kapitsa
[root@localhost ~]# docker exec -it eff93bd04e9e /bin/bash
root@eff93bd04e9e:/usr/local/tomcat# cd webapps/
root@eff93bd04e9e:/usr/local/tomcat/webapps# ls
#之前有五个目录,现在可以看到在Tomcat容器中被清空了。容器卷一旦被建立,里面的内容就会被清空
如果要将项目发布就可以将war包放在宿主机的/webapps目录下,不需要进入容器
[root@localhost webapps]# pwd
/webapps
#将你要发布的内容放在该目录下面
[root@localhost webapps]# ls
examples host-manager manager ROOT
[root@localhost webapps]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e2d137a66f9 ashince/tomcat8 "catalina.sh run" 4 minutes ago Up 4 minutes 0.0.0.0:8080->8080/tcp competent_leavitt
[root@localhost webapps]# docker exec -it 1e2d137a66f9 /bin/bash
root@1e2d137a66f9:/usr/local/tomcat# cd webapps/
root@1e2d137a66f9:/usr/local/tomcat/webapps# ls
ROOT examples host-manager manager
[root@localhost webapps]# docker inspect 1e2d137a66f9
"Mounts": [
{
"Type": "bind",
"Source": "/webapps", 宿主机目录
"Destination": "/usr/local/tomcat/webapps", 容器目录
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
上面是容器卷,将容器的数据和宿主机的数据进行同步,并且实现了数据的持久化