一次搞懂 Docker CPU 資源限制

docker 除了可以透過參數限制 container 的 memory 使用量,也能限制每個 container 能取得的 CPU 資源,讓系統的 CPU 可以最大化使用,又不讓高優先度的 container 損失效能,一起來研究如何設定吧!

Cpuset 限制

設定 cpuset 指定 container 只能跑在特定的 CPU 核心上。比如在 arm CPU 會有 big.LITTLE 的設計,此時可以指定 container 跑在大核或小核上。

參數

# command line
--cpuset-cpus
# docker-compose (v2)
cpuset

範例

假設我們在一個六核 CPU 上面,設定 container 只能跑在 CPU 0, CPU 1,指令可以這麼下

docker run -it --rm --cpuset-cpus="0,1" alexeiled/stress-ng stress --cpu 2  

因為我們開兩條 thread 去 stress,可以看到指定的兩顆 CPU 已經滿載

一次搞懂 Docker CPU 資源限制

除了給定 CPU 編號,也能用範圍的方式表示,比如以下指令將會使用 CPU 0, CPU 1, CPU 2

docker run -it --rm --cpuset-cpus="0-2" alexeiled/stress-ng stress --cpu 2

如果在 docker-compose v2 ,則是這樣寫

version: '2.3'
services:
  app:
    cpuset: "0,1,2" # or "0-2"

CPU period 限制

設定 CPU period 指定 container 最多能使用的 CPU 時間,可簡單看成最大能使用的 CPU 數

參數

# command line
--cpus
# docker-compose (v2)
cpus

範例

假設我們在二核 CPU 上測試,指定 container 最多只能使用 1 CPU ,但壓測時故意開 4 thread,指令如下

docker run -it --rm --cpus="1" alexeiled/stress-ng stress --cpu 4

可以看到 container 最多只能跑到 100% CPU,符合預期

df0a3a768016   test-cpus-1     100.12%    15.86MiB / 3.773GiB   0.41%     3.55kB / 0B       0B / 0B           5

如果看實體 CPU 狀況,發現 docker 會將 thread 平均分散到兩個 CPU 上面,但是各佔 50%,加起來剛好是 100% CPU = 1 CPU

一次搞懂 Docker CPU 資源限制

當然也可以給予「小數」,比如設定「3.5」,表示最多可以使用 350% (3.5 顆)CPU。

如果在 docker-compose v2 中,則是這樣寫

version: '2.3'
services:
  app:
    cpus: 1

CPU shares 限制

設定 CPU shares 可以指定當 CPU 滿載時,container 能取得多少 CPU 份額。亦可理解成當 CPU 資源不夠(滿載)的時候,container 搶奪 CPU 的能力。因此這是相對比較用的值。沒有設定時,docker 預設為 1024。

看完可能還是不太清楚,直接上範例!

參數

# command line
--cpu-shares
# docker-compose (v2)
cpu_shares

範例

假設我們在一核 CPU 上測試,其中一個 container 設定 512,另一個設定 1024,兩個 container 都嘗試用滿 CPU,此時 CPU shares 設定介入資源分配

docker run -it --rm --cpu-shares=512 --name="share-512" alexeiled/stress-ng stress --cpu 1
docker run -it --rm --cpu-shares=1024 --name="share-1024" alexeiled/stress-ng stress --cpu 1

觀察目前 container 的 CPU 使用率,發現 share-512 用約 34%,share-1024 用約 67%。

11eabb0720a7   share-512      33.83%    5.805MiB / 3.773GiB   0.15%     3.67kB / 0B       0B / 0B           2
7114a7965357   share-1024     66.81%    5.797MiB / 3.773GiB   0.15%     2.73kB / 0B       0B / 0B           2

快速算法是將 CPU 總資源除以所有的 container cpu-shares,再分別乘上各自的佔比,即可求得最終能搶奪的 CPU 資源,算式如下:

    \[CPU_{share-512} = 100\% * \frac{512}{512 + 1024} = 33.3\%\]

    \[CPU_{share-1024} = 100\% * \frac{1024}{512 + 1024} = 66.7\%\]

同理,如果一核 CPU 下有四個 container ,分別設定 cpu-shares:

container 1: 512
container 2: 512
container 3: 1024
container 4: 1024

可以透過上面算式預期最滿載時的資源分配如下:

container 1: 16.5%
container 2: 16.5%
container 3: 33%
container 4: 33%

但如果今天是四核 CPU,則四個 container 會分散到不同的核心上,這樣每個 container 都得吃到 100%

如果在 docker-compose v2 中,則是這樣寫

version: '2.3'
services:
  app:
    cpu_shares: 512

綜合應用

這些參數可以綜合起來使用,比如,我想讓 container 跑在 CPU 0, 1, 2 上,但最多只能用到 1.5 核 CPU,同時 shares 為 512,我可以這麼設定:

--cpuset-cpus="0-2"
--cpus="1.5"
--cpu-shares=512 

屆時可以觀察到,CPU 資源足夠時,container 整體最多可以吃到 150% CPU。如果是多執行緒,會分散在 CPU 0, 1, 2 上。單執行緒則會在 CPU 0, 1, 2 其中一核上跑。

如果覺得我文章內容對你有幫助的話,請在文章後面幫我按 5 個讚!讓我知道大家都喜歡什麼內容哦!

參考資料:
Runtime options with Memory, CPUs, and GPUs
Docker CPU资源限制

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。