本文和大家分享的是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 canchangethis behaviorbyspecifying a volumemountpropagation property. Making a volumesharedmounts doneunderthat volume insidecontainerwill bevisibleonhostandvice-a-versa. Making a volumeslaveenablesonlyone waymountpropagationandthatismounts doneonhostunderthat volume will bevisibleinsidecontainerbutnotthe other way around.Tocontrolmountpropagation propertyofvolume one canuse:[r]shared, :[r]slaveor:[r]privatepropagation flag. Propagation property can be specifiedonlyforbind mounted volumesandnotforinternal volumesornamed volumes.Formountpropagationtoworksourcemountpoint (mountpointwheresourcedirismountedon) hastohaverightpropagation properties.Forsharedvolumes,sourcemountpoint hastobe shared.Andforslavevolumes,sourcemounthastobe eithersharedorslave.

(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