docker資源隔離

1、本文將介紹 cgroup 如何作到內存,cpu 和 io 速率的隔離node

本文用腳本運行示例進程,來驗證 Cgroups 關於 cpu、內存、io 這三部分的隔離效果。linux

測試機器環境(docker 1.12版本)程序員

AJ3YF3v.jpg!web

aAnquq.png!web

啓動 Cgroupsweb

systemctl enable cgconfig.service 
docker

systemctl start cgconfig.servicecentos

執行 mount 命令查看 cgroup 的掛載點服務器

myeMveu.png!web

從上圖能夠看到 cgroup 掛載在/sys/fs/cgroup 目錄網絡

groups 能夠限制 blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns 等系運維

統的資源,如下是主要子系統的說明:ide

blkio 這個子系統設置限制每一個塊設備的輸入輸出控制。例如:磁盤,光盤以及 usb 等等。

cpu 這個子系統使用調度程序爲 cgroup 任務提供 cpu 的訪問。

cpuacct 產生 cgroup 任務的 cpu 資源報告。

cpuset 若是是多核心的 cpu,這個子系統會爲 cgroup 任務分配單獨的 cpu 和內存。

devices 容許或拒絕 cgroup 任務對設備的訪問。

freezer 暫停和恢復 cgroup 任務。

memory 設置每一個 cgroup 的內存限制以及產生內存資源報告。

net_cls 標記每一個網絡包以供 cgroup 方便使用,它經過使用等級識別符(classid)標記網絡數

據包,從而容許 Linux 流量控制程序(TC:Traffic Controller)識別從具體 cgroup 中生成

的數據包。

ns:命名空間子系統

cgroups 管理進程 cpu 資源

咱們先看一個限制 cpu 資源的例子:

跑一個耗 cpu 的腳本

運行一個容器,在容器內建立腳本並運行腳本,腳本內容:

JRNZzqe.png!web

ayqQfmn.png!web

將容器切換到後臺運行

ctrl + p && ctrl+q

在宿主機上 top 能夠看到這個腳本基本佔了 90%多的 cpu 資源

faMZ7j6.jpg!web

下面用 cgroups 控制這個進程的 cpu 資源

對於 centos7 來講,經過 systemd-cgls 來查看系統 cgroups tree:

#systemd-cgls

Z3U77jj.jpg!web

注:5028 就是咱們所運行的容器 pid

將 cpu.cfs_quota_us 設爲 50000,相對於 cpu.cfs_period_us 的 100000 是 50%

rymAjaN.png!web

ru6Fnen.png!web

進入容器,再次執行腳本,打開宿主機的另外一個終端執行 top 命令

而後 top 的實時統計數據以下,cpu 佔用率將近 50%,看來 cgroups 關於 cpu 的控制起了效果

F7v2uiY.jpg!web

CPU 資源控制

CPU 資源的控制也有兩種策略,一種是徹底公平調度 (CFS:Completely Fair Scheduler)

策略,提供了限額和按比例分配兩種方式進行資源控制;另外一種是實時調度(Real-Time

Scheduler)策略,針對實時進程按週期分配固定的運行時間。配置時間都以微秒(μs)爲

單位,文件名中用 us 表示。

CFS  調度策略下的配置

按權重比例設定 CPU 的分配

docker 提供了Ccpu-shares 參數,在建立容器時指定容器所使用的 CPU 份額值。例如:

使用命令 docker run -tid Ccpu-shares 100 鏡像,建立容器,則最終生成的 cgroup 的 cpu 份額

配置能夠下面的文件中找到:

# cat /sys/fs/cgroup/cpu/docker-<容器的完整長 ID>/cpu.shares

uUVJRr6.png!web

cpu-shares 的值不能保證能夠得到 1 個 vcpu 或者多少 GHz 的 CPU 資源,僅僅只是一個加權

值。

該加權值是一個整數(必須大於等於 2)表示相對權重,最後除以權重總和算出相對比例,

按比例分配 CPU 時間。

默認狀況下,每一個 docker 容器的 cpu 份額都是 1024。單獨一個容器的份額是沒有意義的,

只有在同時運行多個容器時,容器的 cpu 加權的效果才能體現出來。例如,兩個容器 A、B

的 cpu 份額分別爲 1000 和 500,在 cpu 進行時間片分配的時候,容器 A 比容器 B 多一倍的

機會得到 CPU 的時間片。若是容器 A 的進程一直是空閒的,那麼容器 B 是能夠獲取比容器

A 更多的 CPU 時間片的。極端狀況下,好比說主機上只運行了一個容器,即便它的 cpu 份額

只有 50,它也能夠獨佔整個主機的 cpu 資源。

cgroups 只在容器分配的資源緊缺時,也就是說在須要對容器使用的資源進行限制時,纔會

生效。所以,沒法單純根據某個容器的 cpu 份額來肯定有多少 cpu 資源分配給它,資源分配

結果取決於同時運行的其餘容器的 cpu 分配和容器中進程運行狀況。

cpu-shares 演示案例:

先刪除 docker 主機上運行的容器

QrMNfe2.png!web

Docker 經過--cpu-shares 指定 CPU 份額

運行一個容器指定 cpu 份額爲 1024

UriQJrI.png!web

注:

--cpu-shares 指定 CPU 份額,默認就是 1024

--cpuset-cpus 能夠綁定 CPU。例如,指定容器在--cpuset-cpus 0,1 或--cpuset-cpus 0-3

--cpu 是 stress 命令的選項表示產生 n 個進程 每一個進程都反覆不停的計算隨機數的平方根

stress 命令是 linux 下的一個壓力測試工具。

在 docker 宿主機上打開一個 terminal 執行 top

qIZB3am.jpg!web

而後再啓動一個容器, --cpu-shares 爲 512 。

baIfamA.png!web

查看 top 的顯示結果

E3EZNrm.jpg!web

能夠看到 container1 的 CPU 佔比爲 1024/(1024+512)=2/3,container2 的 CPU 佔比爲

512/(1024+512)=1/3

將 container1 的 cpu.shares 改成 512,

#echo 「512」 > /sys/fs/cgroup/cpu/docker-<容器的完整長 ID>/cpu.shares

zqU7jaB.png!web

能夠看到兩個容器的 CPU 佔比趨於平均

yyqaUn2.png!web

設定 CPU 使用週期使用時間上限

cgroups 裏,能夠用 cpu.cfs_period_us 和 cpu.cfs_quota_us 來限制該組中的全部進程在單

位時間裏可使用的 cpu 時間。cpu.cfs_period_us 就是時間週期,默認爲 100000,即百毫

秒。cpu.cfs_quota_us 就是在這期間內可以使用的 cpu 時間,默認 -1,即無限制。

cpu.cfs_period_us :設定時間週期(單位爲微秒(μs)),必須與 cfs_quota_us 配合使用。

cpu.cfs_quota_us :設定週期內最多可以使用的時間(單位爲微秒(μs))。這裏的配置指 task

對單個 cpu 的使用上限。

舉個例子,若是容器進程須要每 1 秒使用單個 CPU 的 0.2 秒時間,能夠將 cpu-period 設置爲

1000000(即 1 秒),cpu-quota 設置爲 200000(0.2 秒)。

固然,在多核狀況下,若 cfs_quota_us 是 cfs_period_us 的兩倍,就表示在兩個核上

徹底使用 CPU,例如若是容許容器進程須要徹底佔用兩個 CPU,則能夠將 cpu-period 設置爲

100000(即 0.1 秒),cpu-quota 設置爲 200000(0.2 秒)。

使用示例:

使用命令 docker run 建立容器

2y2qQfF.jpg!web

在宿主機上執行 top

qUV7B3Z.png!web

從上圖能夠看到基本佔了 100%的 cpu 資源

則最終生成的 cgroup 的 cpu 週期配置能夠下面的目錄中找到:

/sys/fs/cgroup/cpu/docker-<容器的完整長 ID>/

NNnYNbE.png!web

修改容器的 cpu.cfs_period_us 和 cpu.cfs_quota_us 值

mQvEZza.jpg!web

執行 top 查看 cpu 資源

UzyuuaJ.png!web

從上圖能夠看到基本佔了 50%的 cpu 資源

RT  調度策略下的配置 實時調度策略與公平調度策略中的按週期分配時間的方法相似,也是

在週期內分配一個固定的運行時間。

cpu.rt_period_us :設定週期時間。

cpu.rt_runtime_us :設定週期中的運行時間。

NVr2Irb.jpg!web

cpuset - CPU 綁定

對多核 CPU 的服務器,docker 還能夠控制容器運行限定使用哪些 cpu 內核和內存節點,即

使用Ccpuset-cpus 和Ccpuset-mems 參數。對具備 NUMA 拓撲(具備多 CPU、多內存節點)的

服務器尤爲有用,能夠對須要高性能計算的容器進行性能最優的配置。若是服務器只有一個

內存節點,則Ccpuset-mems 的配置基本上不會有明顯效果

注:

如今的機器上都是有多個 CPU 和多個內存塊的。之前咱們都是將內存塊當作是一大塊內存,

全部 CPU 到這個共享內存的訪問消息是同樣的。可是隨着處理器的增長,共享內存可能會

致使內存訪問衝突愈來愈厲害,且若是內存訪問達到瓶頸的時候,性能就不能隨之增長。

NUMA(Non-Uniform Memory Access)就是這樣的環境下引入的一個模型。好比一臺機

器是有2個處理器,有4個內存塊。咱們將1個處理器和兩個內存塊合起來,稱爲一個NUMA

node,這樣這個機器就會有兩個 NUMA node。在物理分佈上,NUMA node 的處理器和內

存塊的物理距離更小,所以訪問也更快。好比這臺機器會分左右兩個處理器(cpu1, cpu2),

在每一個處理器兩邊放兩個內存塊(memory1.1, memory1.2, memory2.1,memory2.2),這樣

NUMA node1 的 cpu1 訪問 memory1.1 和 memory1.2 就比訪問 memory2.1 和 memory2.2

更快。因此使用 NUMA 的模式若是能儘可能保證本 node 內的 CPU 只訪問本 node 內的內存

塊,那這樣的效率就是最高的。

使用示例:

feQrmin.jpg!web

表示建立的容器只能用 0、一、2 這三個內核。最終生成的 cgroup 的 cpu 內核配置以下:

QZfq6fj.png!web

cpuset.cpus:在這個文件中填寫 cgroup 可以使用的 CPU 編號,如 0-2,16 表明 0、一、2 和 16

這 4 個 CPU。

cpuset.mems:與 CPU 相似,表示 cgroup 可以使用的 memory node,格式同上

經過 docker exec <容器 ID> taskset -c -p 1(容器內部第一個進程編號通常爲 1),能夠看到容器

中進程與 CPU 內核的綁定關係,能夠認爲達到了綁定 CPU 內核的目的。

總結:

CPU 配額控制參數的混合使用

當上面這些參數中時,cpu-shares 控制只發生在容器競爭同一個內核的時間片時,若是經過

cpuset-cpus 指定容器 A 使用內核 0,容器 B 只是用內核 1,在主機上只有這兩個容器使用對

應內核的狀況,它們各自佔用所有的內核資源,cpu-shares 沒有明顯效果。

cpu-period、cpu-quota 這兩個參數通常聯合使用,在單核狀況或者經過 cpuset-cpus 強制容

器使用一個 cpu 內核的狀況下,即便 cpu-quota 超過 cpu-period,也不會使容器使用更多的

CPU 資源。

cpuset-cpus、cpuset-mems 只在多核、多內存節點上的服務器上有效,而且必須與實際的物

理配置匹配,不然也沒法達到資源控制的目的。

在系統具備多個 CPU 內核的狀況下,須要經過 cpuset-cpus 爲容器 CPU 內核才能比較方便地進行測試。

內存配額控制

和 CPU 控制同樣,docker 也提供了若干參數來控制容器的內存使用配額,能夠控制容器的

swap 大小、可用內存大小等各類內存方面的控制。主要有如下參數:

Docker 提供參數-m, --memory=""限制容器的內存使用量,若是不設置-m,則默認容器內存

是不設限的,容器可使用主機上的全部空閒內存

內存配額控制使用示例

設置容器的內存上限,參考命令以下所示

#docker run -dit --memory 128m 鏡像

默認狀況下,除了Cmemory 指定的內存大小之外,docker 還爲容器分配了一樣大小的 swap

分區,也就是說,上面的命令建立出的容器實際上最多可使用 256MB 內存,而不是 128MB內存。若是須要自定義 swap 分區大小,則能夠經過聯合使用CmemoryCswap 參數來實現控制。

yUNfqez.png!web

能夠發現,使用 256MB 進行壓力測試時,因爲超過了內存上限(128MB 內存+128MB swap), 進程被 OOM(out of memory)殺死。

使用 250MB 進行壓力測試時,進程能夠正常運行。

re6ZFvi.png!web

經過 docker stats 能夠查看到容器的內存已經滿負載了。

#docker stats test2

yUn2amM.png!web

對上面的命令建立的容器,能夠查看到在 cgroups 的配置文件中,查看到容器的內存大小爲

128MB (128×1024×1024=134217728B), 內 存 和 swap 加 起 來 大 小 爲 256MB

(256×1024×1024=268435456B)。

#cat /sys/fs/cgroup/memory/docker-<容器的完整 ID>/memory.limit_in_bytes

134217728

#cat  /sys/fs/cgroup/memory/docker-< 容 器 的 完 整 ID>/memory.memsw.limit_in_bytes

268435456

YjyYj2z.jpg!web

盤 磁盤 IO  配額控制

主要包括如下參數:

--device-read-bps:限制此設備上的讀速度(bytes per second),單位能夠是 kb、mb 或者 gb。

--device-read-iops:經過每秒讀 IO 次數來限制指定設備的讀速度。

--device-write-bps :限制此設備上的寫速度(bytes per second),單位能夠是 kb、mb 或者 gb。

--device-write-iops:經過每秒寫 IO 次數來限制指定設備的寫速度。

--blkio-weight:容器默認磁盤 IO 的加權值,有效值範圍爲 10-1000。

--blkio-weight-device: 針對特定設備的 IO 加權控制。其格式爲 DEVICE_NAME:WEIGHT

磁盤 IO 配額控制示例

blkio-weight

使用下面的命令建立兩個Cblkio-weight 值不一樣的容器:

在容器中同時執行下面的 dd 命令,進行測試

mmiIbmf.png!web

注:oflag=direct 規避掉文件系統的 cache,把寫請求直接封裝成 io 指令發到硬盤

2、學習 Docker 也有一段時間了,瞭解了 Docker 的基本實現原理,也知道了 Docker 的使

用方法,這裏對 Docker 的一些典型應用場景作一個總結

一、配置簡化

這是 Docker 的主要使用場景。將應用的全部配置工做寫入 Dockerfile 中,建立好鏡像,

之後就能夠無限次使用這個鏡像進行應用部署了。這大大簡化了應用的部署,不須要爲每次

部署都進行繁瑣的配置工做,實現了一次打包,屢次部署。這大大加快了應用的開發效率,

使得程序員能夠快速搭建起開發測試環境,不用關注繁瑣的配置工做,而是將全部精力都盡

可能用到開發工做中去。

二、代碼流水線管理

代碼從開發環境到測試環境再到生產環境,須要通過不少次中間環節,Docker 給應用

提供了一個從開發到上線均一致的環境,開發測試人員均只需關注應用的代碼,使得代碼的

流水線變得很是簡單,這樣應用才能持續集成和發佈。

三、快速部署

在虛擬機以前,引入新的硬件資源須要消耗幾天的時間。Docker 的虛擬化技術將這個

時間降到了幾分鐘,Docker 只是建立一個容器進程而無需啓動操做系統,這個過程只須要

秒級的時間。

四、應用隔離

資源隔離對於提供共享 hosting 服務的公司是個強需求。 若是使用 VM,雖然隔離性非

常完全,但部署密度相對較低,會形成成本增長。

Docker 容器充分利用 linux 內核的 namespace 提供資源隔離功能。結合 cgroups,能夠方便

的設置每一個容器的資源配額。既能知足資源隔離的需求,又能方便的爲不一樣級別的用戶設置

不一樣級別的配額限制。

五、服務器資源整合

正如經過 VM 來整合多個應用,Docker 隔離應用的能力使得 Docker 一樣能夠整合服務

器資源。因爲沒有額外的操做系統的內存佔用,以及能在多個實例之間共享沒有使用的內存,

Docker 能夠比 VM 提供更好的服務器整合解決方案。

一般數據中心的資源利用率只有 30%,經過使用 Docker 並進行有效的資源分配能夠提升資

源的利用率。

六、多版本混合部署

隨着產品的不斷更新換代,一臺服務器上部署多個應用或者同一個應用的多個版本在企

業內部很是常見。但一臺服務器上部署同一個軟件的多個版本,文件路徑、端口等資源每每

會發生衝突,形成多個版本沒法共存的問題。

若是用 docker,這個問題將很是簡單。因爲每一個容器都有本身獨立的文件系統,因此根本不

存在文件路徑衝突的問題; 對於端口衝突問題,只須要在啓動容器時指定不一樣的端口映射即

可解決問題。

七、版本升級回滾

一次升級,每每不只僅是應用軟件自己的升級,經過還會包含依賴項的升級。 但新舊

軟件的依賴項極可能是不一樣的,甚至是有衝突的,因此在傳統的環境下作回滾通常比較困難。

若是使用 docker,咱們只須要每次應用軟件升級時製做一個新的 docker 鏡像,升級時先停

掉舊的容器, 而後把新的容器啓動。 須要回滾時,把新的容器停掉,舊的啓動便可完成回

滾,整個過程各在秒級完成,很是方便。

八、內部開發環境

在容器技術出現以前,公司每每是經過爲每一個開發人員提供一臺或者多臺虛擬機來充當

開發測試環境。開發測試環境通常負載較低,大量的系統資源都被浪費在虛擬機自己的進程

上了。

Docker容器沒有任何CPU和內存上的額外開銷,很適合用來提供公司內部的開發測試環境。

並且因爲 Docker 鏡像能夠很方便的在公司內部共享,這對開發環境的規範性也有極大的幫

助。

九、PaaS

使用 Docker 搭建大規模集羣,提供 PaaS。這一應用是最有前景的一個了,目前已有很

多創業公司在使用 Docker 作 PaaS 了,例如雲雀雲平臺。用戶只需提交代碼,全部運維工做

均由服務公司來作。並且對用戶來講,整個應用部署上線是一鍵式的,很是方便。

十、雲桌面

在每個容器內部運行一個圖形化桌面,用戶經過 RDP 或者 VNC 協議鏈接到容器。該

方案所提供的虛擬桌面相比於傳統的基於硬件虛擬化的桌面方案更輕量級,運行速率大大提

升。不過該方案仍處於實驗階段,不知是否可行。能夠參考一下 Docker-desktop 方案。

相關文章
相關標籤/搜索