默認狀況下容器可使用的主機 CPU 資源是不受限制的。和內存資源的使用同樣,若是不對容器可使用的 CPU 資源進行限制,一旦發生容器內程序異常使用 CPU 的狀況,極可能把整個主機的 CPU 資源耗盡,從而致使更大的災難。本文將介紹如何限制容器可使用的 CPU 資源。 web
本文的 demo 中會繼續使用《Docker: 限制容器可用的內存》一文中建立的 docker 鏡像 u-stress 進行壓力測試,文中就再也不過多的解釋了。docker
在 docker 1.13 及更高的版本上,可以很容易的限制容器可使用的主機 CPU 個數。只須要經過 --cpus 選項指定容器可使用的 CPU 個數就能夠了,而且還能夠指定如 1.5 之類的小數。接下來咱們在一臺有四個 CPU 且負載很低的主機上進行 demo 演示:緩存
經過下面的命令建立容器,--cpus=2 表示容器最多可使用主機上兩個 CPU:bash
$ docker run -it --rm --cpus=2 u-stress:latest /bin/bash
而後由 stress 命令建立四個繁忙的進程消耗 CPU 資源:工具
# stress -c 4
咱們先來看看 docker stats 命令的輸出:學習
容器 CPU 的負載爲 200%,它的含義爲單個 CPU 負載的兩倍。咱們也能夠把它理解爲有兩顆 CPU 在 100% 的爲它工做。測試
再讓咱們經過 top 命令看看主機 CPU 的真實負載狀況:ui
哈哈,有點大跌眼鏡!實際的狀況並非兩個 CPU 負載 100%,而另外兩個負載 0%。四個 CPU 的負載都是 50%,加起來容器消耗的 CPU 總量就是兩個 CPU 100% 的負載。spa
看來對於進程來講是沒有 CPU 個數這一律唸的,內核只能經過進程消耗的 CPU 時間片來統計出進程佔用 CPU 的百分比。這也是咱們看到的各類工具中都使用百分比來講明 CPU 使用率的緣由。操作系統
嚴謹起見,咱們看看 docker 的官方文檔中是如何解釋 --cpus 選項的:
Specify how much of the available CPU resources a container can use.
果真,人家用的是 "how much",不可數的!而且 --cpus 選項支持設爲小數也從側面說明了對 CPU 的計量只能是百分比。
看來筆者在本文中寫的 "CPU 個數" 都是不許確的。既然不許確,爲何還要用?固然是爲了容易理解。何況筆者認爲在 --cpus 選項的上下文中理解爲 "CPU 個數" 並無問題(有興趣的同窗能夠讀讀 --cpus 選項的由來,人家的初衷也是要表示 CPU 個數的)。
雖然 --cpus 選項用起來很爽,但它畢竟是 1.13 纔開始支持的。對於更早的版本完成一樣的功能咱們須要配合使用兩個選項:--cpu-period 和 --cpu-quota(1.13 及以後的版本仍然支持這兩個選項)。下面的命令實現相同的結果:
$ docker run -it --rm --cpu-period=100000 --cpu-quota=200000 u-stress:latest /bin/bash
這樣的配置選項是否是讓人很傻眼呀!100000 是什麼?200000 又是什麼? 它們的單位是微秒,100000 表示 100 毫秒,200000 表示 200 毫秒。它們在這裏的含義是:在每 100 毫秒的時間裏,運行進程使用的 CPU 時間最多爲 200 毫秒(須要兩個 CPU 各執行 100 毫秒)。要想完全搞明白這兩個選項的同窗能夠參考:CFS BandWith Control。咱們要知道這兩個選項纔是事實的真相,可是真相每每很殘忍!還好 --cpus 選項成功的解救了咱們,其實它就是包裝了 --cpu-period 和 --cpu-quota。
經過 --cpus 選項咱們沒法讓容器始終在一個或某幾個 CPU 上運行,可是經過 --cpuset-cpus 選項卻能夠作到!這是很是有意義的,由於如今的多核系統中每一個核心都有本身的緩存,若是頻繁的調度進程在不一樣的核心上執行勢必會帶來緩存失效等開銷。下面咱們就演示如何設置容器使用固定的 CPU,下面的命令爲容器設置了 --cpuset-cpus 選項,指定運行容器的 CPU 編號爲 1:
$ docker run -it --rm --cpuset-cpus="1" u-stress:latest /bin/bash
再啓動壓力測試命令:
# stress -c 4
而後查看主機 CPU 的負載狀況:
此次只有 Cpu1 達到了 100%,其它的 CPU 並未被容器使用。咱們還能夠反覆的執行 stress -c 4 命令,可是始終都是 Cpu1 在幹活。
再看看容器的 CPU 負載,也是隻有 100%:
--cpuset-cpus 選項還能夠一次指定多個 CPU:
$ docker run -it --rm --cpuset-cpus="1,3" u-stress:latest /bin/bash
此次咱們指定了 1,3 兩個 CPU,運行 stress -c 4 命令,而後檢查主機的 CPU 負載:
Cpu1 和 Cpu3 的負載都達到了 100%。
容器的 CPU 負載也達到了 200%:
--cpuset-cpus 選項的一個缺點是必須指定 CPU 在操做系統中的編號,這對於動態調度的環境(沒法預測容器會在哪些主機上運行,只能經過程序動態的檢測系統中的 CPU 編號,並生成 docker run 命令)會帶來一些不便。
==============
當 CPU 資源充足時,設置 CPU 的權重是沒有意義的。只有在容器爭用 CPU 資源的狀況下, CPU 的權重才能讓不一樣的容器分到不一樣的 CPU 用量。--cpu-shares 選項用來設置 CPU 權重,它的默認值爲 1024。咱們能夠把它設置爲 2 表示很低的權重,可是設置爲 0 表示使用默認值 1024。
下面咱們分別運行兩個容器,指定它們都使用 Cpu0,並分別設置 --cpu-shares 爲 512 和 1024:
$ docker run -it --rm --cpuset-cpus="0" --cpu-shares=512 u-stress:latest /bin/bash` $ docker run -it --rm --cpuset-cpus="0" --cpu-shares=1024 u-stress:latest /bin/bash
在兩個容器中都運行 stress -c 4 命令。
此時主機 Cpu0 的負載爲 100%:
容器中 CPU 的負載爲:
兩個容器分享一個 CPU,因此總量應該是 100%。具體每一個容器分得的負載則取決於 --cpu-shares 選項的設置!咱們的設置分別是 512 和 1024,則它們分得的比例爲 1:2。在本例中若是想讓兩個容器各佔 50%,只要把 --cpu-shares 選項設爲相同的值就能夠了。
====
相比限制容器用的內存,限制 CPU 的選項要簡潔不少。可是簡潔絕對不是簡單,大多數把複雜東西整簡單的過程都會丟失細節或是模糊一些概念,好比從 --cpu-period 和 --cpu-quota 選項到 --cpus 選項的進化。對於使用者來講這固然是好事,能夠減緩咱們的學習曲線,快速入手。