本文简要介绍了Docker容器对数据卷管理。
1、Docker数据卷管理
数据卷是Docker容器保存数据的方式,跟bind mounts方式相比,有以下优势:
- 数据卷更容易备份迁移
- 使用Docker CLI或者Docker API对数据卷进行管理
- 数据卷可以在多个容器间共享和复用
- Volumes driver可以将卷内容存储在远端主机上
- 可以使用Docker填充新的数据卷内容
- 数据卷内容存在Docker容器之外,并不会增加容器本身大小
1.1 创建和管理卷
1)创建卷
[root@tango-01 ~]# docker volume create my-volume
my-volume
2)List卷
[root@tango-01 ~]# docker volume ls
DRIVER VOLUME NAME
local 4a77c195a70ff39c151ad75367d41f7db1f48de06e0ebb0333189724ca6c389a
local 73cca56105d152363bf63789bb3093443ec239559029caffc66da1a78257f200
local 548de7d0ba3d0a8c85a4b25e1234ba1b2a5891068a3062858825389a3ee4fc42
local my-volume
3)Inspect volume查看卷详细信息
[root@tango-01 ~]# docker volume inspect my-volume
[
{
"CreatedAt": "2020-10-06T20:25:50+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
"Name": "my-volume",
"Options": {},
"Scope": "local"
}
]
4)Remove volume
[root@tango-01 ~]# docker volume rm my-volume
my-volume
5)使用-v选项添加一个数据卷
[root@tango-01 docker]# docker run -d --name voltest -v my-vol1:/data nginx:latest
966f73c1e518adfd115b5bb3321effc9b5692a10a64a2dbf992e533465dc516c
[root@tango-01 docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
966f73c1e518 nginx:latest "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 80/tcp voltest
[root@tango-01 docker]# docker volume ls
DRIVER VOLUME NAME
local 4a77c195a70ff39c151ad75367d41f7db1f48de06e0ebb0333189724ca6c389a
local 73cca56105d152363bf63789bb3093443ec239559029caffc66da1a78257f200
local 548de7d0ba3d0a8c85a4b25e1234ba1b2a5891068a3062858825389a3ee4fc42
local my-vol1
创建数据卷绑定到到新建容器,新建容器中会创建/data数据卷,如果卷不存在,Docker会创建一个新的volume。
>>挂载时创建卷<<
1)挂载卷
[root@tango-01 docker]# docker run -d -p 80:80 -v /data:/usr/share/nginx/html nginx:latest
66bc9c834237cc2f0bf47e63a7f3a2eb0ce51a6689309a6f740dc268403a44ff
[root@tango-01 docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
66bc9c834237 nginx:latest "/docker-entrypoint.…" 6 seconds ago Up 6 seconds 0.0.0.0:80->80/tcp mystifying_banzai
容器内站点目录: /usr/share/nginx/html
2)在宿主机写入数据,查看
[root@tango-01 /]# echo "hello tango" >/data/index.html
[root@tango-01 /]# curl 192.168.112.10
hello tango
3)设置共享卷,使用同一个卷启动一个新的容器
[root@tango-01 /]# docker run -d -p 8080:80 -v /data:/usr/share/nginx/html nginx:latest
b2cb700cd9937674e6d08326ede94932855d59d327c90427ba027903d9c90e61
[root@tango-01 /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b2cb700cd993 nginx:latest "/docker-entrypoint.…" 6 seconds ago Up 4 seconds 0.0.0.0:8080->80/tcp charming_wright
66bc9c834237 nginx:latest "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp mystifying_banzai
[root@tango-01 /]# curl 192.168.112.10:8080
hello tango
4)查看卷列表
[root@tango-01 /]# docker volume ls
DRIVER VOLUME NAME
local 4a77c195a70ff39c151ad75367d41f7db1f48de06e0ebb0333189724ca6c389a
local 73cca56105d152363bf63789bb3093443ec239559029caffc66da1a78257f200
local 548de7d0ba3d0a8c85a4b25e1234ba1b2a5891068a3062858825389a3ee4fc42
local my-vol1
>>创建卷后挂载<<
1)使用卷创建
[root@tango-01 /]# docker run -d -p 9080:80 -v my-vol1:/usr/share/nginx/html nginx:latest
43be86f4ec307e509c36d4145de3cd874c7d8adacff53e32f2a994953b86f7a0
2)宿主机测试
[root@tango-01 /]# echo 'hello tango' > /var/lib/docker/volumes/my-vol1/_data/index.html
[root@tango-01 /]# curl 192.168.112.10:9080
hello tango
3)设置卷
[root@tango-01 /]# docker run -d -P --volumes-from 43be86f4ec30 nginx:latest
5acebbac45d74890819ab36aa38241f2d5fcd0673d7624bf4a55894d3e11efcf
[root@tango-01 /]#
[root@tango-01 /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5acebbac45d7 nginx:latest "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:32768->80/tcp upbeat_einstein
43be86f4ec30 nginx:latest "/docker-entrypoint.…" 9 minutes ago Up 8 minutes 0.0.0.0:9080->80/tcp elated_lederberg
b2cb700cd993 nginx:latest "/docker-entrypoint.…" 15 minutes ago Up 14 minutes 0.0.0.0:8080->80/tcp charming_wright
66bc9c834237 nginx:latest "/docker-entrypoint.…" 16 minutes ago Up 16 minutes 0.0.0.0:80->80/tcp mystifying_banzai
[root@tango-01 /]# curl 192.168.112.10:32768
hello tango
1.2 备份、恢复或迁移数据卷
1)数据卷备份
[root@tango-01 /]# docker run -v /testdata --name voltest ubuntu /bin/bash
[root@tango-01 /]# docker run --rm --volumes-from voltest -v $(pwd):/backup ubuntu tar cvf /backup/test.tar /testdata
tar: Removing leading `/' from member names
/testdata/
启动一个新的容器并且从voltest容器中挂载卷,然后挂载当前目录到容器中为backup,并备份test卷中所有的数据为test.tar,执行完成之后删除容器–rm,此时备份就在当前的目录下,名为test.tar。
注意:后面的/data是数据卷的目录路径(即数据卷创建时在容器里的路径)
2)数据卷恢复或迁移
可以恢复给同一个容器或者另外的容器,新建容器并解压备份文件到新的容器数据卷
[root@tango-01 /]# docker run -v /testdata --name voltest1 ubuntu /bin/bash
[root@tango-01 /]# docker run --rm --volumes-from voltest1 -v $(pwd):/backup ubuntu bash -c "cd /testdata && tar xvf /backup/test.tar --strip 1"
恢复之前的文件到新建卷中,执行完后自动删除容器
>>数据卷备份恢复操作实战<<
1)先创建一个容器voltest,包含两个数据卷/var/volume1和/var/volume2(这两个目录是在容器里的数据卷路径)
[root@tango-01 /]# docker run -t -i -v /var/volume1 -v /var/volume2 --name voltest ubuntu /bin/bash
root@881631b3f8c5:
根据Docker的数据持久化之数据卷容器可知,上面创建的voltest数据卷容器挂载了/var/volume1和/var/volume2两个目录。
2)在数据卷里写些数据,以供测试
root@881631b3f8c5:/# cd /var/volume1
root@881631b3f8c5:/var/volume1# echo "test1" > test1
root@881631b3f8c5:/var/volume1# echo "test11" > test11
root@881631b3f8c5:/var/volume1# echo "test111" > test111
root@881631b3f8c5:/var/volume1# ls
test1 test11 test111
root@881631b3f8c5:/var/volume1# cd /var/volume2
root@881631b3f8c5:/var/volume2# echo "test2" > test2
root@881631b3f8c5:/var/volume2# echo "test22" > test22
root@881631b3f8c5:/var/volume2# echo "test222" > test222
root@881631b3f8c5:/var/volume2# ls
test2 test22 test222
3)进行数据卷的备份操作
为了利用数据卷容器备份,使用–volumes-from标记来创建一个加载voltest容器卷的容器,并从主机挂载当前目录到容器的/backup目录。并备份voltest卷中的数据,执行完成之后删除容器–rm,此时备份就在当前的目录下了。
a) 备份voltest容器中的/var/volume1数据卷数据
[root@tango-01 /]# docker run -i -t --volumes-from voltest -v $(pwd):/backup ubuntu tar cvf /backup/backup1.tar /var/volume1
tar: Removing leading `/' from member names
/var/volume1/
/var/volume1/test1
/var/volume1/test11
/var/volume1/test111
b) 备份voltest容器中的/var/volume2数据卷数据
[root@tango-01 /]# docker run -i -t --volumes-from voltest -v $(pwd):/backup ubuntu tar cvf /backup/backup2.tar /var/volume2
tar: Removing leading `/' from member names
/var/volume2/
/var/volume2/test2
/var/volume2/test22
/var/volume2/test222
c) 备份voltest容器中的/var/volume1和/var/volume2数据卷数据
[root@tango-01 /]# docker run -i -t --volumes-from voltest -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /var/volume1 /var/volume2
tar: Removing leading `/' from member names
/var/volume1/
/var/volume1/test1
tar: Removing leading `/' from hard link targets
/var/volume1/test11
/var/volume1/test111
/var/volume2/
/var/volume2/test2
/var/volume2/test22
/var/volume2/test222
[root@tango-01 /]# ls -l
total 68
-rw-r--r-- 1 root root 10240 Oct 6 22:04 backup1.tar
-rw-r--r-- 1 root root 10240 Oct 6 22:05 backup2.tar
-rw-r--r-- 1 root root 10240 Oct 6 22:06 backup.tar
这样,数据卷容器中的数据就备份完成了
4)恢复数据给同一个容器
a) 为了测试效果,先删除数据卷
[root@tango-01 /]# docker start voltest
voltest
[root@tango-01 /]# docker attach voltest
root@881631b3f8c5:/# ls /var/volume1
test1 test11 test111
root@881631b3f8c5:/# ls /var/volume2
test2 test22 test222
root@881631b3f8c5:/# rm -rf /var/volume1
rm: cannot remove '/var/volume1': Device or resource busy
root@881631b3f8c5:/# rm -rf /var/volume2
rm: cannot remove '/var/volume2': Device or resource busy
root@881631b3f8c5:/# ls /var/volume1
root@881631b3f8c5:/# ls /var/volume2
b) 进行数据卷恢复,恢复数据卷中的所有数据:
[root@tango-01 /]# docker run --rm --volumes-from voltest -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar -C /
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume1/test111
var/volume2/
var/volume2/test2
var/volume2/test22
var/volume2/test222
注意-C后面的路径,这个路径表示将数据恢复到容器里的路径。命令中用"/",即表示将backup.tar中的数据解压到容器的/路径下。后面跟什么路径,就解压到这个路径下,因此这里用"/"。
c) 再次到容器里查看,发现数据卷里的数据已经恢复了
[root@tango-01 /]# docker start voltest
voltest
[root@tango-01 /]# docker attach voltest
root@881631b3f8c5:/# ls /var/volume1
test1 test11 test111
root@881631b3f8c5:/# ls /var/volume2
test2 test22 test222
5)恢复数据给另外的容器,新建容器并解压备份文件到新的容器数据卷
即新建一个容器voltest1,将上面备份的数据卷数据恢复到这个新容器里
[root@tango-01 /]# docker run -t -i -v /var/volume1 -v /var/volume2 --name voltest1 ubuntu /bin/bash
root@7acb459cbe1c:/# ls /var/volume1
root@7acb459cbe1c:/# ls /var/volume2
恢复数据到新的容器voltest1中:
[root@tango-01 /]# docker run --rm --volumes-from voltest1 -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar -C /
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume1/test111
var/volume2/
var/volume2/test2
var/volume2/test22
var/volume2/test222
[root@tango-01 /]# docker start voltest1
voltest1
[root@tango-01 /]# docker attach voltest1
root@7acb459cbe1c:/# ls /var/volume1
test1 test11 test111
root@7acb459cbe1c:/# ls /var/volume2
test2 test22 test222
注:新容器创建时挂载的数据卷路径最好是和之前备份的数据卷路径一致
6)新建容器挂载的数据卷只是备份数据卷的一部分,那么恢复的时候也只是恢复一部分数据。如下,新容器创建时只挂载/var/volume1
[root@tango-01 /]# docker run -t -i -v /var/volume1 --name voltest2 ubuntu /bin/bash
root@e2c453c81390:/# ls /var/volume1
root@e2c453c81390:/# ls /var/volume2
ls: cannot access '/var/volume2': No such file or directory
恢复数据到新的容器voltest2中:
[root@tango-01 /]# docker run --rm --volumes-from voltest2 -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar -C /
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume1/test111
var/volume2/
var/volume2/test2
var/volume2/test22
var/volume2/test222
root@e2c453c81390:/# ls /var/volume1
test1 test11 test111
查看容器,发现只恢复了/var/volume1的数据,/var/volume2数据没有恢复,因为没有容器创建时没有挂载这个。
7)如果新容器创建时挂载的数据卷目录跟之前备份的路径不一致
[root@tango-01 /]# docker run -t -i -v /var/volume3 --name voltest3 ubuntu /bin/bash
root@06bfbfc830a7:/# ls /var/volume3
如果解压时-C后面跟的路径不是容器挂载的容器,那么数据恢复不了,如下
[root@tango-01 /]# docker run --rm --volumes-from voltest3 -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar -C /
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume1/test111
var/volume2/
var/volume2/test2
var/volume2/test22
var/volume2/test222
发现容器内数据没有恢复
root@06bfbfc830a7:/# ls /var/volume3
root@06bfbfc830a7:/#
但是如果解压时-C后面跟的是容器挂载的路径,数据就能正常恢复
[root@tango-01 /]# docker run --rm --volumes-from voltest3 -v $(pwd):/backup ubuntu tar xvf /backup/backup.tar -C /var/volume3
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume1/test111
var/volume2/
var/volume2/test2
var/volume2/test22
var/volume2/test222
发现容器内数据已经恢复了
root@06bfbfc830a7:/# ls /var/volume3
var
root@06bfbfc830a7:/# ls /var/volume3/var
volume1 volume2
root@06bfbfc830a7:/# ls /var/volume3/var/volume1
test1 test11 test111
root@06bfbfc830a7:/# ls /var/volume3/var/volume2
test2 test22 test222
root@06bfbfc830a7:/#
2、Docker容器资源限制
2.1 Namespace资源隔离
Docker使用Linux namespace技术实现容器间的资源隔离
>>以PID namespace为例<<
1)启动一个容器
[root@tango-01 /]# docker run -it --name pidtest ubuntu /bin/bash
2)查看容器中的进程id(可以看到/bin/sh的pid=1)
root@e9fcfb4c6f17:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
8 pts/0 00:00:00 ps
3)查看宿主机中的该/bin/sh的进程id
[root@tango-01 /]# ps -ef|grep ubuntu
root 3079 1671 0 14:48 pts/0 00:00:00 docker run -it --name pidtest ubuntu /bin/bash
root 3146 2387 0 14:49 pts/1 00:00:00 grep --color=auto ubuntu
可以看到,在Docker里最开始执行的/bin/sh,就是这个容器内部的第1号进程(PID=1),而在宿主机上看到它的PID=3709。这就意味着,前面执行的/bin/sh,已经被Docker隔离在了一个跟宿主机完全不同的世界当中。这就是Docker在启动一个容器(创建一个进程)时使用了PID namespace