一、数据管理
用户在使用 Docker 的过程中,往往需要能查看容器内应用产生的数据,或者把容器内的数据进行备份,甚至在多个容器之间进行数据的共享,这必然涉及容器的数据管理操作。
容器中管理数据的方式有两种:
数据卷:数据卷是一个可供容器使用的特殊目录,它绕过文件系统,并提供多个特性。
- 数据卷可以在容器之间共享和重用。
- 对数据卷的修改会立马生效。
- 对数据卷的更新不会影响镜像。
- 卷会一直存在,直到没有容器使用。
数据卷容器:如果用户需要在容器之间共享一些持续更新的数据,最简单的方式就是使用数据卷容器。专门用它提供数据卷供其他容器挂载使用。
(一)在容器内创建一个数据卷
1、只要在 docker run 命令后面跟上 -v 参数即可创建一个数据卷,当然也可以跟多个 -v 参数来创建多个数据卷,当创建好带有数据卷的容器后,就可以在其他容器中通过 --volumes-froms 参数来挂载该数据卷了,而不管该容器是否运行。
2、不能使用 docker export、save、cp 等命令来备份数据卷的内容,因为数据卷是存在于镜像之外的。备份的方法可以是创建一个新容器,挂载数据卷容器,同时挂载一个本地目录,然后把远程数据卷容器的数据卷通过备份命令备份到映射的本地目录里面。
3、也可以把一个本地主机的目录当做数据卷挂载在容器上,同样是在docker run后面跟-v参数,不过-v后面跟的不再是单独的目录了,它是[host-dir]:[container-dir]:[rw|ro]这样格式的,host-dir是一个绝对路径的地址,如果host-dir不存在,则docker会创建一个新的数据卷,如果host-dir存在,但是指向的是一个不存在的目录,则docker也会创建该目录,然后使用该目录做数据源。
为容器添加一个数据卷,这个数据卷在容器里的目录是/opt/data:
[root@localhost bin]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 316b57509753 6 days ago 215 MB
test latest 3af2730c06cf 6 days ago 86.7 MB
docker.io/registry latest 33fbbf4a24e5 12 days ago 24.2 MB
docker.io/ubuntu latest 1d9c17228a9e 2 weeks ago 86.7 MB
[root@localhost bin]# docker run -v /opt/data -t -i ubuntu /bin/bash
root@ec225a892f3f:/# cd /opt/data/
root@ec225a892f3f:/opt/data# ll
total 0
drwxr-xr-x. 2 root root 6 Jan 16 09:33 ./
drwxr-xr-x. 1 root root 18 Jan 16 09:33 ../
root@ec225a892f3f:/opt/data# echo "123" >123
root@ec225a892f3f:/opt/data# echo "456" >456
root@ec225a892f3f:/opt/data# ll
total 8
drwxr-xr-x. 2 root root 28 Jan 16 09:33 ./
drwxr-xr-x. 1 root root 18 Jan 16 09:33 ../
-rw-r--r--. 1 root root 4 Jan 16 09:33 123
-rw-r--r--. 1 root root 4 Jan 16 09:33 456
[root@localhost bin]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec225a892f3f ubuntu "/bin/bash" About a minute ago Up 4 seconds dreamy_montalcini
30da4c14bf41 registry "/entrypoint.sh /e..." 31 hours ago Up 31 hours 0.0.0.0:5000->5000/tcp keen_murdock
在宿主机上,查看对应上面的那个数据卷的目录路径:
示例:在 “Mounts” 里面存在 source 参数,查看 source 参数可以看到目录里创建的文件。
[root@localhost ~]# docker inspect ec22
[
......
"Mounts": [
{
"Type": "volume",
"Name": "40d01d2437d53f7ce47a21c957a7cb394f614f90b35fa575b54a73099923b275",
"Source": "/var/lib/docker/volumes/40d01d2437d53f7ce47a21c957a7cb394f614f90b35fa575b54a73099923b275/_data",
"Destination": "/opt/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "ec225a892f3f",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "ubuntu",
"Volumes": {
"/opt/data": {}
},
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "4f7bf29146b3e72a2a31729947f487097702cc80209debff933669f2972f5912",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/4f7bf29146b3",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "d67206d5ba47d81df70a8fb994cee079f17997734b20de378c157a5937c7162c",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "4d39ec836b91611392702d03d11354e823345cf59c2bd4f86411ab4802236196",
"EndpointID": "d67206d5ba47d81df70a8fb994cee079f17997734b20de378c157a5937c7162c",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03"
}
}
}
}
]
[root@localhost ~]# ll /var/lib/docker/volumes/40d01d2437d53f7ce47a21c957a7cb394f614f90b35fa575b54a73099923b275/_data
总用量 8
-rw-r--r--. 1 root root 4 1月 16 17:33 123
-rw-r--r--. 1 root root 4 1月 16 17:33 456
(二)挂载宿主机文件或目录到数据卷
可以直接挂载宿主机文件或目录到容器里,可以理解为目录映射,这样就可以让所有的容器共享宿主机数据,从而只需要改变宿主机的数据源就能够影响到所有的容器数据。
注意:
-v后面的映射关系是 "宿主机文件/目录 : 容器里对应的文件/目录",其中,宿主机上的文件/目录是要提前存在的,容器里对应的文件/目录会自动创建。
数据卷权限:
挂载的数据默认为可读写权限。
但也可以根据自己的需求,将容器里挂载共享的数据设置为只读,这样数据修改就只能在宿主机上操作。如下实例:
1、挂载宿主机文件到容器上 示例:
挂载宿主机文件到容器上
# 在 /usr/local 目录下创建一个文件,填写数据
[root@localhost local]# cat mount.list
apple
banana
orange
#将目录文件挂载到容器
[root@localhost local]# docker run -t -i -v /usr/local/mount.list:/usr/local/mount.list:ro ubuntu /bin/bash
#查看挂载文件的信息
root@0d45c8e9ff4d:/# cat /usr/local/mount.list
apple
banana
orange
# 向文件中添加信息,提示没有权限
root@0d45c8e9ff4d:/# echo "watermelon" >> /usr/local/mount.list
bash: /usr/local/mount.list: Permission denied
在宿主机上修改共享数据
[root@localhost local]# echo "watermelon" >> /usr/local/mount.list
[root@localhost local]# cat mount.list
apple
banana
orange
watermelon
在容器中查看共享数据,共享数据已经更新
root@0d45c8e9ff4d:~# cat /usr/local/mount.list
apple
banana
orange
watermelon
2、挂载宿主机目录到容器 示例:
[root@localhost local]# mkdir mountdir
[root@localhost local]# echo "data1" >> mountdir/data1
[root@localhost local]# echo "data2" >> mountdir/data2
#将目录挂载到容器
[root@localhost local]# docker run -ti -v /usr/local/mountdir/:/opt/mountdir ubuntu /bin/bash
root@2797491c3d19:/# cd /opt/mountdir/
root@2797491c3d19:/opt/mountdir# ll
total 8
drwxr-xr-x. 2 root root 32 Jan 17 02:37 ./
drwxr-xr-x. 1 root root 22 Jan 17 02:38 ../
-rw-r--r--. 1 root root 6 Jan 17 02:37 data1
-rw-r--r--. 1 root root 6 Jan 17 02:37 data2
在宿主机上修改目录文件
[root@localhost local]# cd mountdir/
[root@localhost mountdir]# ll
总用量 8
-rw-r--r--. 1 root root 6 1月 17 10:37 data1
-rw-r--r--. 1 root root 6 1月 17 10:37 data2
[root@localhost mountdir]# echo "data11" >> data1
在容器中查看共享目录
root@2797491c3d19:/opt/mountdir# cat data1
data1
data11
(三)创建数据卷容器
启动一个名为First_Container容器,此容器包含两个数据卷/var/volume1和/var/volume2(这两个数据卷目录是在容器里的,容器创建的时候会自动生成这两目录)
[root@localhost ~]# docker run -ti -v /var/volume1 -v /var/volume2 --name First_Container ubuntu /bin/bash
查看宿主机上与数据卷对应的目录路径:
[root@localhost ~]# docker inspect First_Container | grep /var/lib/docker/volumes
"Source": "/var/lib/docker/volumes/e90b988156a2763b2e564fcfcf6f8163f5836e1094cd6c4bd61fd13aec93a521/_data",
"Source": "/var/lib/docker/volumes/e26833eb7ad21a5fbdfbbe2a3ceec85a349fef491630ef47777bf6af039cfd69/_data",
由上面命令结果可以查到,两个数据卷/var/volume1和/var/volume2下的数据在/var/lib/docker/volumes/下对于的两个目录的_data下面
创建Second_Container容器,挂载First_Container容器中的数据卷:
[root@localhost ~]# docker run -t -i --rm --volumes-from First_Container --name Second_Container ubuntu /bin/bash
root@91fa9e2d37d8:/#
查询容器中的数据卷
root@91fa9e2d37d8:/# cd /var/
root@91fa9e2d37d8:/var# ll
total 0
drwxr-xr-x. 1 root root 36 Jan 17 03:08 ./
drwxr-xr-x. 1 root root 28 Jan 17 03:08 ../
drwxr-xr-x. 2 root root 6 Apr 24 2018 backups/
drwxr-xr-x. 5 root root 48 Dec 4 17:12 cache/
drwxr-xr-x. 1 root root 17 Dec 4 17:11 lib/
drwxrwsr-x. 2 root staff 6 Apr 24 2018 local/
lrwxrwxrwx. 1 root root 9 Dec 4 17:11 lock -> /run/lock/
drwxr-xr-x. 3 root root 148 Dec 4 17:11 log/
drwxrwsr-x. 2 root mail 6 Dec 4 17:11 mail/
drwxr-xr-x. 2 root root 6 Dec 4 17:11 opt/
lrwxrwxrwx. 1 root root 4 Dec 4 17:11 run -> /run/
drwxr-xr-x. 2 root root 18 Dec 4 17:11 spool/
drwxrwxrwt. 2 root root 6 Dec 4 17:12 tmp/
drwxr-xr-x. 2 root root 6 Jan 17 03:00 volume1/
drwxr-xr-x. 2 root root 6 Jan 17 03:00 volume2/
即便是删除了初始的数据卷容器xqsj_Container,或是删除了其它容器,但只要是有容器在使用该数据卷,那么它里面的数据就不会丢失!(除非是没有容器在使用它们)。
(四)删除数据卷
如果删除了挂载的容器,数据卷不会被自动删除。Volume 只有在下列情况才能被删除:
- docker rm -v 删除容器时添加 -v 选项
- docker run --rm 运行容器时添加 --rm 选项
否则会在 /var/lib/docker/volumes 目录中留下很多不明目录。可以使用下面的方式找出,然后删除数据文件。
[root@localhost ~]# docker inspect First_Container | grep /var/lib/docker/volumes
"Source": "/var/lib/docker/volumes/e90b988156a2763b2e564fcfcf6f8163f5836e1094cd6c4bd61fd13aec93a521/_data",
"Source": "/var/lib/docker/volumes/e26833eb7ad21a5fbdfbbe2a3ceec85a349fef491630ef47777bf6af039cfd69/_data",
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local 40d01d2437d53f7ce47a21c957a7cb394f614f90b35fa575b54a73099923b275
local d171b6e64c660358f3b9ce84e059f44dd2f6c05a2bd3604a4d4efcb36d2dd81d
local e26833eb7ad21a5fbdfbbe2a3ceec85a349fef491630ef47777bf6af039cfd69
local e90b988156a2763b2e564fcfcf6f8163f5836e1094cd6c4bd61fd13aec93a521
local fe0ec142d8d37b79668ca154ebba1a2a40c6db802184e50194cb4e5bc04e3720
[root@localhost ~]# docker rm -vf First_Container
First_Container
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local 40d01d2437d53f7ce47a21c957a7cb394f614f90b35fa575b54a73099923b275
local d171b6e64c660358f3b9ce84e059f44dd2f6c05a2bd3604a4d4efcb36d2dd81d
local fe0ec142d8d37b79668ca154ebba1a2a40c6db802184e50194cb4e5bc04e3720
[root@localhost ~]#
(五)备份
使用下面的命令来备份数据卷容器的数据卷:
[root@localhost ~]# docker run --volumes-form dbdata -v ${pwd}:/backup --name worker ubuntu
tar cvf /backup/backup.tar /dbdata
解释:首先利用 Ubuntu 镜像创建一个容器 worker . 使用 --volumes-form dbdata 参数来让 worker 容器挂载 dbdata 容器的数据卷;使用 -v ${pwd}:/backup 参数来挂载本地的当前目录到 worker 容器的 /backup 目录。
worker 容器启动后,使用了 tar cvf /backup/backup.tar /dbdata 命令来将 /dbdata 下内容备份为容器内的 /backup/backup.tar 即宿主机当前目录下的 backup.tar 。
(六)恢复
恢复数据到一个容器,可以按照下面的操作,先创建一个带有数据卷的容器 dbdata2 :
[root@localhost ~]# docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后创建另一个新的容器,挂载 dbdata2 的容器,并解压备份文件到所挂载的容器卷中即可:
[root@localhost ~]# docker run --volumes-form dbdata2 -v ${pwd}:/backup ubuntu tar xvf /backup/backup.tar