如果你不知道Docker,或者不了解Docker的基本用法,建议先读一下上篇文章:零基础入门Docker。入门Docker之后,我们继续了解Docker中比较进阶性的知识:容器中的数据管理。
先思考一些场景,如果利用Docker创建了一个N个容器,这些容器之间需要数据共享,此时该怎么办?如果我们想在本机了解容器的运行状态、命令历史等,此时该怎么办?
按照Docker官方文档的说明,容器中的数据管理有两种形式:Manage data in containers
数据卷(Data Volumes)
可以将“数据卷”理解为容器中的一个目录,类似于Linux中mount的概念。创建容器时,可以一并创建数据卷,并且能够挂载一个主机目录为数据卷。有点绕口,实例说明一下。
(1)创建mysql容器,不添加任何关于数据卷的参数:
# 这里假设我们已经pull下mysql镜像
[root@xx ~]# docker run -d -p 3306:3306 --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 mysql # 创建一个名字为mysql01的容器
此时并没有指定关于任何数据卷的参数。-p 3306:3306是将本机的3306端口映射到容器的3306端口。此时利用命令查看容器的基本信息,其中一段为:
[root@xx ~]# docker inspect mysql01
......
"Mounts": [
{
"Name": "6cb3597e2da5......",
"Source": "/var/lib/docker/volumes/6cb3597e2da5....../_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
......
这段数据说明该容器自动生成一个数据卷,在容器中的目录为"/var/lib/mysql",用于存放Mysql数据,同时在本机也有相对应的目录:"/var/lib/docker/volumes/....../_data"。当你在Mysql中创建数据库、表时,就会在本机目录下生成相应的数据。
(2)创建mysql容器,并添加自定义的数据卷:
# 这里假设我们已经pull下mysql镜像
[root@xx ~]# docker run -d -p 3307:3306 --name mysql02 -e MYSQL_ROOT_PASSWORD=123456 -v /appdata mysql # 创建一个名字为mysql02的容器
此时指定了一个-v /appdata的参数,用于在容器中创建一个目录为/appdata的数据卷。注意-p选项变为了-p 3307:3306,这是因为上一次的容器将本机的3306端口占用了,需要选择另外一个端口。此时利用inspect命令查看容器基本信息,其中一段为:
[root@xx ~]# docker inspect mysql02
"Mounts": [
{
"Name": "d95fd2d33.......",
"Source": "/var/lib/docker/volumes/d95fd2d33....../_data",
"Destination": "/appdata",
........
},
{
"Name": "695e371973......",
"Source": "/var/lib/docker/volumes/695e371973....../_data",
"Destination": "/var/lib/mysql",
........
}
],
这个容器中有两个数据卷,一个是Mysql自建的"/var/lib/mysql",用于存放mysql数据。另外一个是我们自己指定的"/appdata",类似于前者,这个数据卷在本机也有相对应的目录。这里的"appdata"数据卷并没有什么用,只是作为例子说明一下。
(3)创建mysql容器,并挂载本机目录作为数据卷
# 这里假设我们已经pull下mysql镜像
[root@xx ~]# docker run -d -p 3308:3306 --name mysql03 -e MYSQL_ROOT_PASSWORD=123456 -v /root/mysqldata/:/var/lib/mysql mysql
此时的-v参数将本机的"/root/mysqldata"目录挂载到"/var/lib/mysql"。此时查看容器的基本信息,其中一段为:
[root@xx ~]# docker inspect mysql03
"Mounts": [
{
"Source": "/root/mysqldata",
"Destination": "/var/lib/mysql",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
这里只有一个数据卷,应该比较容易理解。注意这里的"Propagation"参数,官方的解释为:
By default bind mounted volumes are private. That means any mounts done inside container will not be visible on host and vice-a-versa. One can change this behavior by specifying a volume mount propagation property. Making a volume shared mounts done under that volume inside container will be visible on host and vice-a-versa. Making a volume slave enables only one way mount propagation and that is mounts done on host under that volume will be visible inside container but not the other way around. To control mount propagation property of volume one can use :[r]shared, :[r]slave or :[r]private propagation flag. Propagation property can be specified only for bind mounted volumes and not for internal volumes or named volumes. For mount propagation to work source mount point (mount point where source dir is mounted on) has to have right propagation properties. For shared volumes, source mount point has to be shared. And for slave volumes, source mount has to be either shared or slave.
(4)创建容器,并挂载本机文件作为数据卷。
除了能挂载本机的目录外,同样可以挂载本机文件。官网上给出的例子是:
$ docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash
这里将本机的.bash_history文件挂载到容器的.bash_history文件上。根据数据卷的特性,这样在本机就能看到容器中的操作历史了。
(5)删除数据卷。数据卷是被用来持久化数据的,它独立于容器存在。当我们删除容器时,并不会自动删除数据卷,同时Docker也没有垃圾回收机制可以回收无用的数据卷。但是我们可以在删除容器时,连同数据卷一并删除,比如:docker rm -v mysql02。
数据卷容器(Data Volumes Container)
如果你有一些需要持续更新,并且需要在容器之间共享的数据,建议创建数据卷容器。数据卷容器其实就是一个容器,专门用来提供数据卷供其他容器挂载。
(1)首先建立一个数据卷容器,用于存放数据。
[root@xx ~]# docker run -d -p 3306:3306 --name store -v /data/ -e MYSQL_ROOT_PASSWORD=123456 mysql
(2)接着你就能使用--volumes-from选项在其他容器中挂载/data/目录。
[root@xx ~]# docker run -d -p 3307:3306 --name u1 --volumes-from store -e MYSQL_ROOT_PASSWORD=123456 mysql
[root@xx ~]# docker run -d -p 3308:3306 --name u2 --volumes-from store -e MYSQL_ROOT_PASSWORD=123456 mysql
此时容器u1和u2中都有/data/目录,并且和容器store中的该目录共用。即当我们在容器u1中新建、更改、删除文件时,容器u2同样能得到对应的操作。
注意,这里的数据卷容器store并不需要一直处于运行的状态。
(3)删除数据卷容器。这里删除容器u1、u2或store都不会删除数据卷,需要在删除后一个容器时使用-v选项来删除数据卷。这里建议删除每一个时都带有-v选项。
[root@xx ~]# docker rm -v u1
[root@xx ~]# docker rm -v u2
[root@xx ~]# docker rm -v store
数据卷的备份、恢复和迁移
比较简单,直接查看官方文档即可。地址:Manage data in containers
数据拷贝
在容器和主机之间,可以利用命令docker cp进行数据拷贝。
[root@xx ~]# docker cp CONTAINER:SRC_PATH DEST_PATH
[root@xx ~]# docker cp SRC_PATH CONTAINER:DEST_PATH
数据拷贝和数据卷之间的区别在于:数据卷挂载后,数据卷中的数据实际上是存放在主机上的,相当于建立了一个软连接。而数据拷贝之后,容器中是存在数据的,当把容器commit成一个镜像时,镜像中也是存在该数据的。
=============================================================
作者主页:笑虎(Python爱好者,关注爬虫、数据分析、数据挖掘、数据可视化等)
作者专栏主页:撸代码,学知识 - 知乎专栏
作者GitHub主页:撸代码,学知识 - GitHub
欢迎大家拍砖、提意见。相互交流,共同进步!
==============================================================