layout: post
title: Docker的数据管理
date: 2018-11-06 15:13:36
categories: Docker
catalog: true
tags:
- Volume
我们知道容器中的任何修改默认都是不会被保存的。想要保存容器运行时产生的数据,我们需要使用Volume
数据卷技术来提供独立于容器外的持久化存储,它也可以提供容器与容器之前的共享数据。简单来说我感觉就是挂载,把本地磁盘中的某个目录挂载到容器中的某个目录,这样容器对这个目录的任何操作相当与操作我们本地的相应目录。
这里有三种方式使用Volume
进行容器的持久存储。
[root@HJWDEV docker]# docker run -d --name nginx-fun -v /usr/share/nginx/html nginx-fun
--name
指定容器名
-v
需要挂载的目录
上述命令是创建一个名为nginx-fun容器并加载 数据卷
到容器的 /usr/share/nginx/html
目录。也就是把我们本地的某个目录挂载到容器中的 /usr/share/nginx/html
目录中,具体是我们本地的哪个目录不需要我们指定。这也是为了保证Docker的可移植性,因为不是每个宿主机上都有对应的目录。
[root@HJWDEV docker]# docker inspect nginx-fun
通过上述命令我们可以知道使用的是本地的哪个目录,找到如下信息:
"Mounts": [
{
"Type": "volume",
"Name": "388f5df2b08fa24b75358acdccf41ac987971b5c9edb02c693b4bfd8929a09fb",
"Source": "/var/lib/docker/volumes/388f5df2b08fa24b75358acdccf41ac987971b5c9edb02c693b4bfd8929a09fb/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
可以看到Source
指向的地址就是我们本地对应的目录,我们可以进入这个目录查看:
[root@HJWDEV docker]# cd /var/lib/docker/volumes/388f5df2b08fa24b75358acdccf41ac987971b5c9edb02c693b4bfd8929a09fb/_data
[root@HJWDEV _data]# ll
总用量 8
-rw-r--r--. 1 root root 494 9月 25 23:04 50x.html
-rw-r--r--. 1 root root 54 9月 26 10:53 index.html
可以看到目录中有两个文件,是nginx-fun容器中/usr/share/nginx/html
目录的默认文件。
[root@HJWDEV _data]# cat index.html
<html>
<body>
<h2>Docker is Fun!</h2>
</body>
</html>
[root@HJWDEV _data]# vi index.html
我们查看index.html
中的默认内容并修改成如下内容:
<html>
<body>
<h2>Docker is Fun!</h2>
<h3>Docker is interesing</h3>
</body>
</html>
接着进入容器中的/usr/share/nginx/html
目录,看文件是否被修改:
[root@HJWDEV _data]# docker exec -it nginx-fun /bin/bash
root@15f556dcc7e5:/# cd /usr/share/nginx/html
root@15f556dcc7e5:/usr/share/nginx/html# ls
50x.html index.html
root@15f556dcc7e5:/usr/share/nginx/html# cat index.html
<html>
<body>
<h2>Docker is Fun!</h2>
<h3>Docker is interesing</h3>
</body>
</html>
root@15f556dcc7e5:/usr/share/nginx/html#
可以看到容器中的文件也同步修改了。同样的如果容器中/usr/share/nginx/html
中的文件被修改了,宿主机中的对应目录文件也会跟着变动。
这种方式虽然实现了数据的持久存储,但要查询宿主机中挂载的目录比较麻烦,下面这种方式则可以直接指定宿主机中的需要挂载的目录。
[root@HJWDEV docker]# touch volume/index.html
[root@HJWDEV docker]# vi volume/index.html
首页我们在docker/volume
目录新建一个index.html
文件,写入以下内容:
this is volume
接着启动一个nginx容器
[root@HJWDEV docker]# docker run -p 80:80 -d -v $PWD/volume:/usr/share/nginx/html nginx-fun
$PWD
表示当前目录路径
上面的命令把宿主机的$PWD/volume
目录挂载到容器中的 /usr/share/nginx/html
目录。$PWD/volume
目录必须使用绝对路径且是存在的,不然会报错。
访问nginx的首页:
[root@HJWDEV docker]# curl http://localhost/
this is volume
可以看到输出的内容就是我们宿主机挂载目录中的index.html
的内容。
[root@HJWDEV docker]# vi volume/index.htm
我们重新修改一下宿主机挂载目录下的index.html
文件,修改如下:
this is volume,is cool!
我们直接进入容器内查看 /usr/share/nginx/html
目录中的index.html
是否同步被修改:
[root@HJWDEV docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3aad9e00870 nginx-fun "nginx -g 'daemon of…" 13 minutes ago Up 13 minutes 0.0.0.0:80->80/tcp nostalgic_booth
[root@HJWDEV docker]# docker exec -it a3aad9e00870 /bin/bash
root@a3aad9e00870:/# cd /usr/share/nginx/html
root@a3aad9e00870:/usr/share/nginx/html# ls
index.html
root@a3aad9e00870:/usr/share/nginx/html# cat index.html
this is volume,is cool!
可以看到容器中的文件也同步被修改了。
还有一种方式是把宿主机的一个文件挂载到容器中。
[root@HJWDEV docker]# docker run --rm -it -v $PWD/volume/bash_history.txt:/root/.bash_history nginx-fun /bin/bash
root@6b22a51db2ee:/# cd /usr/share/nginx/html
root@6b22a51db2ee:/usr/share/nginx/html# ls
50x.html index.html
root@6b22a51db2ee:/usr/share/nginx/html# exit
exit
[root@HJWDEV docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@HJWDEV docker]# cat volume/bash_history.txt
cd /usr/share/nginx/html
ls
cat index.html
exit
--rm
表示退出进程后自动删除容器,可以看到第5 行中exit
后再 docker ps
显示没有运行的容器了
-it
分配一个伪终端并打开交互模式
上述命令把宿主机中的$PWD/volume/bash_history.txt
文件挂载到容器中的 /root/.bash_history
文件。 /root/.bash_history
文件中记录的是容器内使用命令的历史记录,因此容器中使用过的命令同样也会写入宿主机的$PWD/volume/bash_history.txt
文件中。
如果有一些持续更新的数据需要在容器之间共享,我们可以使用数据卷容器。数据卷容器
其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载。
[root@HJWDEV docker]# docker run -it -v /opt/dbdata --name dbdata ubuntu /bin/bash
root@3842c0845e26:/# cd /opt/dbdata
root@3842c0845e26:/opt/dbdata# touch db.properties
root@3842c0845e26:/opt/dbdata# exit
通过上述命令我们创建一个数据卷容器,在容器的/opt/dbdata
目录创建一个新文件 db.properties
通过 docker inspect
命令查看容器挂载的宿主机目录:
[root@HJWDEV docker]# docker inspect dbdata
可以看到宿主机的目录如下:
"Mounts": [
{
"Type": "volume",
"Name": "01eb6e6a162ece43abc601783805d89a0a0e871cf7c612bad28e1858ae7606f8",
"Source": "/var/lib/docker/volumes/01eb6e6a162ece43abc601783805d89a0a0e871cf7c612bad28e1858ae7606f8/_data",
"Destination": "/opt/dbdata",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
再创建一个名为vol_a
的容器并通过 --volumes-from
命令挂载 dbdata
容器 。进入vol_a
容器查看/opt/dbdata
目录可以看到存在 dbdata
容器中创建的文件,如下:
[root@HJWDEV docker]# docker run -it --name vol_a --volumes-from dbdata ubuntu /bin/bash
root@90f972394243:/# cd /opt/dbdata/
root@90f972394243:/opt/dbdata# ls
db.properties
如挂载源有多个,可以使用多次--volumes-from
这样即实现了容器间的数据共享。
如果创建容器时挂载了volume,会在类似 /var/lib/docker/volumes/01eb6e6a162ece43abc601783805d89a0a0e871cf7c612bad28e1858ae7606f8/_data
目录下会生成相应的文件(路径,不同版本,不同操作系统会有所不同,具体可以用docker inspect查看容器具体信息),当删除容器时,宿主机上的挂载目录时不会删除的,并且目录名称是随机字符,不知意义,所以在删除容器时,需要妥善处理容器的volume。删除容器时一并删除volume有二种方法:
[root@HJWDEV docker]# docker rm -v dbdata
dbdata
[root@HJWDEV docker]# cd /var/lib/docker/volumes/01eb6e6a162ece43abc601783805d89a0a0e871cf7c612bad28e1858ae7606f8/_data
[root@HJWDEV _data]#
使用docker rm
加 -v
参数 删除容器时会一并把 volume 删除,但这里发现目录还是存在,因为我们上面的vol_a
容器还在使用 dbdata
的挂载。所以需要把vol_a
也删除。
[root@HJWDEV docker]# docker rm -v vol_a
vol_a
[root@HJWDEV docker]# cd /var/lib/docker/volumes/01eb6e6a162ece43abc601783805d89a0a0e871cf7c612bad28e1858ae7606f8/_data
-bash: cd: /var/lib/docker/volumes/01eb6e6a162ece43abc601783805d89a0a0e871cf7c612bad28e1858ae7606f8/_data: 没有那个文件或目录
[root@HJWDEV docker]#
这样 volume
的目录也会被删除了。
docker run --rm
启动容器的时候加了 -rm
参数,这样在容器停止后自动删除容器以及容器所挂载的volume
。这种方式上挂载文件
这一节已经使用过。