Docker 的資源限制和隔離完全基於 Linux cgroups。對 CPU 資源的限制方式也和 cgroups 相同。Docker 提供的 CPU 資源限制選項可以在多核系統上限制容器能利用哪些 vCPU。而對容器最多能使用的 CPU 時間有兩種限制方式:一是有多個 CPU 密集型的容器競爭 CPU 時,設置各個容器能使用的 CPU 時間相對比例。二是以絕對的方式設置容器在每個調度周期內最多能使用的 CPU 時間。
CPU 限制相關參數
docker run –help 命令CPU 限制相關的所有選項如下:
選項 | 說明 |
---|---|
–cpuset-cpus=”” | 允許使用的 CPU 集,格式可以為 0-3, 0,1 |
-c,–cpu-shares=0 | CPU 共享權值(相對權重) |
cpu-period=0 | 限制 CPU CFS 的周期,范圍從 100ms~1s,即[1000, 1000000] |
–cpu-quota=0 | 限制 CPU CFS 配額,必須不小於1ms,即 >= 1000 |
–cpuset-mems=”” | 允許在其上執行的內存節點(MEMs),只對 NUMA 系統有效 |
其中–cpuset-cpus用於設置容器可以使用的 vCPU 核。-c,–cpu-shares用於設置多個容器競爭 CPU 時,各個容器相對能分配到的 CPU 時間比例。–cpu-period和–cpu-quata用於絕對設置容器能使用 CPU 時間。
–cpuset-mems暫用不上.
CPU 集
我們可以設置容器可以在哪些 CPU 核上運行。
例如:
1
|
$ docker run -it --cpuset-cpus="1,3" ubuntu:14.04 /bin/bash
|
表示容器中的進程可以在 cpu 1 和 cpu 3 上執行。
1
|
$ docker run -it --cpuset-cpus="0-2" ubuntu:14.04 /bin/bash
|
表示容器中的進程可以在 cpu 0、cpu 1 及 cpu 3 上執行。
在 NUMA 系統上,我們可以設置容器可以使用的內存節點。
例如:
1
|
$ docker run -it --cpuset-mems="1,3" ubuntu:14.04 /bin/bash
|
表示容器中的進程只能使用內存節點 1 和 3 上的內存。
1
|
$ docker run -it --cpuset-mems="0-2" ubuntu:14.04 /bin/bash
|
表示容器中的進程只能使用內存節點 0、1、2 上的內存。
CPU 資源的相對限制
默認情況下,所有的容器得到同等比例的 CPU 周期。在有多個容器競爭 CPU 時我們可以設置每個容器能使用的 CPU 時間比例。這個比例叫作共享權值,通過-c或–cpu-shares設置。Docker 默認每個容器的權值為 1024。不設置或將其設置為 0,都將使用這個默認值。系統會根據每個容器的共享權值和所有容器共享權值和比例來給容器分配 CPU 時間。
假設有三個正在運行的容器,這三個容器中的任務都是 CPU 密集型的。第一個容器的 cpu 共享權值是 1024,其它兩個容器的 cpu 共享權值是 512。第一個容器將得到 50% 的 CPU 時間,而其它兩個容器就只能各得到 25% 的 CPU 時間了。如果再添加第四個 cpu 共享值為 1024 的容器,每個容器得到的 CPU 時間將重新計算。第一個容器的CPU 時間變為 33%,其它容器分得的 CPU 時間分別為 16.5%、16.5%、33%。
必須注意的是,這個比例只有在 CPU 密集型的任務執行時才有用。在四核的系統上,假設有四個單進程的容器,它們都能各自使用一個核的 100% CPU 時間,不管它們的 cpu 共享權值是多少。
在多核系統上,CPU 時間權值是在所有 CPU 核上計算的。即使某個容器的 CPU 時間限制少於 100%,它也能使用各個 CPU 核的 100% 時間。
例如,假設有一個不止三核的系統。用-c=512的選項啟動容器{C0},並且該容器只有一個進程,用-c=1024的啟動選項為啟動容器C2,並且該容器有兩個進程。CPU 權值的分布可能是這樣的:
1
2
3
4
|
PID container CPU CPU share
100 {C0} 0 100% of CPU0
101 {C1} 1 100% of CPU1
102 {C1} 2 100% of CPU2
|
CPU 資源的絕對限制
Linux 通過 CFS(Completely Fair Scheduler,完全公平調度器)來調度各個進程對 CPU 的使用。CFS 默認的調度周期是 100ms。
我們可以設置每個容器進程的調度周期,以及在這個周期內各個容器最多能使用多少 CPU 時間。使用–cpu-period即可設置調度周期,使用–cpu-quota即可設置在每個周期內容器能使用的 CPU 時間。兩者一般配合使用。
例如:
1
|
$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:16.04 /bin/bash
|
將 CFS 調度的周期設為 50000,將容器在每個周期內的 CPU 配額設置為 25000,表示該容器每 50ms 可以得到 50% 的 CPU 運行時間。
1
|
$ docker run -it --cpu-period=10000 --cpu-quota=20000 ubuntu:16.04 /bin/bash
|
將容器的 CPU 配額設置為 CFS 周期的兩倍,CPU 使用時間怎么會比周期大呢?其實很好解釋,給容器分配兩個 vCPU 就可以了。該配置表示容器可以在每個周期內使用兩個 vCPU 的 100% 時間。
CFS 周期的有效范圍是 1ms~1s,對應的–cpu-period的數值范圍是 1000~1000000。而容器的 CPU 配額必須不小於 1ms,即–cpu-quota的值必須 >= 1000。可以看出這兩個選項的單位都是 us。
正確的理解“絕對”
注意前面我們用–cpu-quota設置容器在一個調度周期內能使用的 CPU 時間時實際上設置的是一個上限。並不是說容器一定會使用這么長的 CPU 時間。比如,我們先啟動一個容器,將其綁定到 cpu 1 上執行。給其–cpu-quota和–cpu-period都設置為 50000。
1
|
$ docker run --rm --name test01 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 deadloop:busybox-1.25.1-glibc
|
調度周期為 50000,容器在每個周期內最多能使用 50000 cpu 時間。
再用docker stats test01可以觀察到該容器對 CPU 的使用率在100%左右。然后,我們再以同樣的參數啟動另一個容器。
1
|
$ docker run --rm --name test02 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 deadloop:busybox-1.25.1-glibc
|
再用docker stats test01 test02可以觀察到這兩個容器,每個容器對 cpu 的使用率在 50% 左右。說明容器並沒有在每個周期內使用 50000 的 cpu 時間。
使用docker stop test02命令結束第二個容器,再加一個參數-c 2048啟動它:
1
|
$ docker run --rm --name test02 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 -c 2048 deadloop:busybox-1.25.1-glibc
|
再用docker stats test01命令可以觀察到第一個容器的 CPU 使用率在 33% 左右,第二個容器的 CPU 使用率在 66% 左右。因為第二個容器的共享值是 2048,第一個容器的默認共享值是 1024,所以第二個容器在每個周期內能使用的 CPU 時間是第一個容器的兩倍。