本文簡要介紹了Docker容器對數據卷管理以及CPU、內存和IO等系統資源限制方式
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-volume2)List卷
[root@tango-01 ~]# docker volume ls
DRIVER VOLUME NAME
local my-volume3)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-volume5)使用-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 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 tango3)設置共享卷,使用同一個卷啟動一個新的容器
[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 tango4)查看卷列表
[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
43be86f4ec307e509c36d4145de3cd874c7d8adacff53e32f2a994953b86f7a02)宿主機測試
[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 tango3)設置卷
[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 test2223)進行數據卷的備份操作
為了利用數據卷容器備份,使用--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/test111b) 備份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/test222c) 備份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/volume2b) 進行數據卷恢復,恢復數據卷中的所有數據:
[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 test2225)恢復數據給另外的容器,新建容器並解壓備份文件到新的容器數據卷
即新建一個容器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/bash2)查看容器中的進程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 ps3)查看宿主機中的該/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
2.2 Cgroup資源限制Cgroup是Control Groups的縮寫,是Linux 內核提供的一種可以限制、記錄、隔離進程組所使用的物理資源(如 cpu、memory、磁碟IO等等) 的機制。Docker 通過內核的 cgroups 來做容器的資源限制;包括CPU、內存、磁碟三大方面。
2.2.1 內存限制Docker 提供的內存限制功能有以下幾點:
容器能使用的內存和交換分區大小。
容器的核心內存大小。
容器虛擬內存的交換行為。
容器內存的軟性限制。
是否殺死佔用過多內存的容器。
執行docker run命令時能使用的和內存限制相關的所有選項如下:
2.2.2 CPU限制docker run命令和CPU限制相關的所有選項如下:
其中--cpuset-cpus用於設置容器可以使用的 vCPU 核。-c,--cpu-shares用於設置多個容器競爭 CPU 時,各個容器相對能分配到的 CPU 時間比例。--cpu-period和--cpu-quata用於絕對設置容器能使用 CPU 時間。
>>CPU限制例子<<1)配置控制組
[root@tango-01 cgroup]# cd /sys/fs/cgroup/cpu
[root@tango-01 cpu]# mkdir testcpulimit
[root@tango-01 cpu]# cd testcpulimit/
[root@tango-01 testcpulimit]# ls
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
[root@tango-01 testcpulimit]# cat /sys/fs/cgroup/cpu/testcpulimit/cpu.cfs_quota_us
-1
[root@tango-01 testcpulimit]# cat /sys/fs/cgroup/cpu/testcpulimit/cpu.cfs_period_us
100000創建的這個目錄testcpulimit就稱為一個「控制組」,作業系統會在新創建的目錄下,自動生成該子系統對應的資源限制文件。可以看到testlimit控制組裡的CPU quota還沒有任何限制(即:-1),CPU period則是默認的100000us。
2)配置一個只能使用30% cpu的限制,即長度為cfs_period的一段時間內,只能被分配到總量為cfs_quota的CPU時間。
[root@tango-01 testcpulimit]# echo 30000 > /sys/fs/cgroup/cpu/testcpulimit/cpu.cfs_quota_us
[root@tango-01 testcpulimit]# cat /sys/fs/cgroup/cpu/testcpulimit/cpu.cfs_quota_us
300003)在容器中執行腳本
[root@tango-01 /]# docker run -it --name cputest ubuntu /bin/bash
root@be59c323f3ad:/#
root@be59c323f3ad:/# while : ; do : ; done &
[1] 10
root@be59c323f3ad:/# top
top - 07:24:47 up 1:04, 0 users, load average: 0.08, 0.44, 0.31
Tasks: 3 total, 2 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 30.0 us, 0.3 sy, 0.0 ni, 69.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 976.3 total, 136.2 free, 440.4 used, 399.7 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 362.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10 root 20 0 4232 748 180 R 30.3 0.1 3:39.46 bash
1 root 20 0 4232 2208 1640 S 0.0 0.2 0:00.13 bash
11 root 20 0 6100 1812 1292 R 0.0 0.2 0:00.07 top4)使用cgroup限制該進程的cpu
[root@tango-01 testcpulimit]# echo 3564 > /sys/fs/cgroup/cpu/testcpulimit/tasks
[root@tango-01 testcpulimit]#
[root@tango-01 testcpulimit]# top
top - 15:23:21 up 1:03, 2 users, load average: 0.38, 0.59, 0.34
Tasks: 130 total, 2 running, 128 sleeping, 0 stopped, 0 zombie
%Cpu(s): 29.6 us, 0.3 sy, 0.0 ni, 70.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 999696 total, 138896 free, 378192 used, 482608 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 370456 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3564 root 20 0 4232 748 180 R 29.9 0.1 3:13.66 bash看到使用剛才創建的testcpulimit控制組,將cpu被限制到了30%左右
2.2.3 磁碟IO配額控制相對於CPU和內存的配額控制,docker對磁碟IO的控制相對不成熟,大多數都必須在有宿主機設備的情況下使用。主要包括以下參數:
>>磁碟IO配額控制示例<<1)blkio-weight
要使–blkio-weight生效,需要保證IO的調度算法為CFQ。可以使用下面的方式查看:
[root@tango-01 /]# cat /sys/block/sda/queue/scheduler
noop [deadline] cfq使用下面的命令創建兩個–blkio-weight值不同的容器:
[root@tango-01 /]# docker run -ti --rm --blkio-weight 10 ubuntu
[root@tango-01 /]# docker run -ti --rm --blkio-weight 1000 ubuntu在容器中同時執行下面的dd命令,進行測試:
time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct最終輸出如下所示:
##--blkio-weight 10
[root@tango-01 /]# docker run -ti --rm --blkio-weight 10 ubuntu
root@8f5bd8c7b853:/# time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 10.6883 s, 100 MB/s
real 0m10.690s
user 0m0.001s
sys 0m0.633s
root@8f5bd8c7b853:/#
##--blkio-weight 1000
[root@tango-01 testcpulimit]# docker run -ti --rm --blkio-weight 1000 ubuntu
root@0248a935fa36:/# time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 9.74697 s, 110 MB/s
real 0m9.839s
user 0m0.001s
sys 0m0.673s
root@0248a935fa36:/#2)device-write-bps
使用下面的命令創建容器,並執行命令驗證寫速度的限制。
docker run -tid –name disk1 –device-write-bps /dev/sda:1mb ubuntu通過dd來驗證寫速度,輸出如下圖示:
[root@tango-01 /]# docker run -tid --name disk1 --device-write-bps /dev/sda:1mb ubuntu
33c0cac7c8966e2d16850f9239b2e354c169a275199ed2c5900dfe1959232c19
[root@tango-01 /]# docker exec -ti disk1 bash
root@33c0cac7c896:/# dd if=/dev/zero of=test.out bs=1M count=100 oflag=direct
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 100.003 s, 1.0 MB/s可以看到容器的寫磁碟速度被成功地限制到了1MB/s。
參考資料
https://docs.docker.com/storage/volumes/
https://www.cnblogs.com/kevingrace/p/6238195.html
https://www.cnblogs.com/zhuochong/p/9728383.html
https://blog.csdn.net/songcf_faith/article/details/82749011
https://blog.csdn.net/songcf_faith/article/details/82748987