Docker資源管理
一臺宿主機可以放多個容器,預設的情況下,
Docker
沒有對容器進行硬體資源的限制,當容器負載過高時會盡可能的佔用宿主機資源,所以有時候我們需要對容器的資源使用設定一個上限,今天我們就來看看如何管理 Docker 使用的資源。真正可以控制的只有記憶體和CPU
檢視宿主機資源使用情況
Docker 使用 cgroups
歸類執行在容器中的程序,這就使得我們可以管理一組程序使用的資源。執行 systemd-cgls
命令 就可以檢視 cgroups
樹 :
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22 ├─docker │ ├─93d5ecbdf58ff840f737c41adff9d0f9506aac036a1fd2f0c3f31edf696ce7f1 │ │ ├─24291 mysqld │ │ ├─29404 bash │ │ └─29480 mysql -uroot -px xxxx │ ├─b1f53779101af8778ba8e8dfd0946a84e8c69b3d8b0b35cd8753c46d966ffba5 │ │ ├─23893 mysqld │ │ ├─25112 bash │ │ └─28740 mysql -uroot -px xxxx │ └─57aff029f6c65c6bbe0edcb3f9b61b4c3a6253bd1093d2dfc8ec318dd2cc4b9b │ ├─23667 mysqld │ ├─24709 bash │ └─29649 mysql -uroot -px xxxx ......
使用 systemd-cgtop
命令可以看到使用最多資源的程序。
CPU
預設情況下,每一個容器可以使用宿主機上的所有 CPU 資源,但大多數系統使用的資源排程演算法是CFS
(完全公平排程器),它公平排程每一個工作程序。程序分CPU密集型
和IO密集型
兩類。系統核心會實時監測系統程序,當某個程序佔用 CPU 資源時間過長時,核心會調整該程序的優先順序。
引數
引數名 | 作用 |
---|---|
--cpu-share | cpu資源提供給一組容器使用,組內的容器按比例使用cpu資源,當容器處於空閒狀態時,cpu資源被負載大的容器佔用,(按壓縮方式比例分配),當空閒進行執行起來時,cpu資源會被分配到其他容器 |
--cpus= value | 指定 cpu的核心數量 |
--cpuset-cpus | 指定容器只能執行在哪個cpu核心上(繫結cpu);核心使用0,1,2,3編號; |
–cpu-share | 隨機指定cpu |
例項:
docker run -di --name=os --cpus=2 centos:latest bash
設定記憶體
預設情況下,docker 並沒有對容器記憶體進行限制,也就是說容器可以使用主機提供的所有記憶體。這當然是非常危險的事情,如果某個容器運行了惡意的記憶體消耗軟體,或者程式碼有記憶體洩露,很可能會導致主機記憶體耗盡,因此導致服務不可用。對於這種情況,docker 會設定 docker daemon 的 OOM(out of memory) 值,使其在記憶體不足的時候被殺死的優先順序降低。另外,就是你可以為每個容器設定記憶體使用的上限,一旦超過這個上限,容器會被殺死,而不是耗盡主機的記憶體。
限制記憶體上限雖然能保護主機,但是也可能會傷害到容器裡的服務。如果為服務設定的記憶體上限太小,會導致服務還在正常工作的時候就被 OOM 殺死;如果設定的過大,會因為排程器演算法浪費記憶體。因此,合理的做法包括:
- 為應用做記憶體壓力測試,理解正常業務需求下使用的記憶體情況,然後才能進入生產環境使用
- 一定要限制容器的記憶體使用上限
- 儘量保證主機的資源充足,一旦通過監控發現資源不足,就進行擴容或者對容器進行遷移
- 如果可以(記憶體資源充足的情況),儘量不要使用 swap,swap 的使用會導致記憶體計算複雜,對排程器非常不友好
docker 限制容器記憶體使用量
在 docker 啟動引數中,和記憶體限制有關的包括(引數的值一般是記憶體大小,也就是一個正數,後面跟著記憶體單位 b
、k
、m
、g
,分別對應 bytes、KB、MB、和 GB):
引數 | 作用 |
---|---|
-m 或 --memory |
容器能使用的最大記憶體大小,最小值為 4m |
--memory-swap | 容器能夠使用的 swap 大小 |
--memory-swappiness | 預設情況下,主機可以把容器使用的匿名頁(anonymous page)swap 出來,你可以設定一個 0-100 之間的值,代表允許 swap 出來的比例 |
--memory-reservation | 設定一個記憶體使用的 soft limit,如果 docker 發現主機記憶體不足,會執行 OOM 操作。這個值必須小於 --memory 設定的值 |
--kernel-memory | 容器能夠使用的 kernel memory 大小,最小值為 4m。 |
--oom-kill-disable | 是否執行 OOM 的時候殺死容器。只有設定了 -m ,才可以把這個選項設定為 false,否則容器會耗盡主機記憶體,而且導致主機應用被殺死 |
關於 --memory-swap
的設定必須解釋一下,--memory-swap
必須在 --memory
也配置的情況下才能有用。
- 如果
--memory-swap
的值大於--memory
,那麼容器能使用的總記憶體(記憶體 + swap)為--memory-swap
的值,能使用的 swap 值為--memory-swap
減去--memory
的值 - 如果
--memory-swap
為 0,或者和--memory
的值相同,那麼容器能使用兩倍於記憶體的 swap 大小,如果--memory
對應的值是200M
,那麼容器可以使用400M
swap - 如果
--memory-swap
的值為 -1,那麼不限制 swap 的使用,也就是說主機有多少 swap,容器都可以使用
例項:
docker run -di --name=os -m=1g centos:latest bash
測試
1) 安裝 Docker 容器
[root@VM_0_15_centos ~]# docker pull centos:latest
2) 執行容器並指定CPU 和記憶體
[root@VM_0_15_centos ~]# docker run -di --name=os --cpus=0.3 -m=512MB centos:latest bash
3) 進入容器並安裝壓測工具
[root@VM_0_15_centos ~]# docker exec -it os bash
[root@7a1de35f8a52 /]# yum install wget gcc gcc-c++ make -y
[root@7a1de35f8a52 /]# yum install -y epel-release
[root@7a1de35f8a52 /]# yum install stress -y
4) 壓測前觀察 Docker 資源使用情況
docker stats
5) 壓測CPU
stress --cpu 2 --timeout 600
增加2個 CPU 程序,處理 sqrt()
函式函式,以提高系統CPU負荷,測試600S
6) 觀察 Docker 資源使用情況
docker stats
可以看到容器 CPU 基本上不能彪到 30%以上了。
7)壓測記憶體
[root@ef431fea0e9e /]# stress --vm 1 --vm-bytes 1g --timeout 600
新增1個 IO 程序,記憶體大小為 1G,發現程序直接被 kill 掉了
stress: info: [162] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: FAIL: [162] (415) <-- worker 163 got signal 9
stress: WARN: [162] (417) now reaping child worker processes
stress: FAIL: [162] (451) failed run completed in 1s