docker容器資源配額控制詳解
docker通過(guò)cgroup來(lái)控制容器使用的資源配額,包括CPU、內(nèi)存、磁盤三大方面,基本覆蓋了常見(jiàn)的資源配額和使用量控制。
cgroup簡(jiǎn)介
cgroup是Control Groups的縮寫,是Linux 內(nèi)核提供的一種可以限制、記錄、隔離進(jìn)程組所使用的物理資源(如 cpu、memory、磁盤IO等等) 的機(jī)制,被LXC、docker等很多項(xiàng)目用于實(shí)現(xiàn)進(jìn)程資源控制。cgroup將任意進(jìn)程進(jìn)行分組化管理的 Linux 內(nèi)核功能。cgroup本身是提供將進(jìn)程進(jìn)行分組化管理的功能和接口的基礎(chǔ)結(jié)構(gòu),I/O 或內(nèi)存的分配控制等具體的資源管理功能是通過(guò)這個(gè)功能來(lái)實(shí)現(xiàn)的。這些具體的資源管理功能稱為cgroup子系統(tǒng),有以下幾大子系統(tǒng)實(shí)現(xiàn):
- blkio:設(shè)置限制每個(gè)塊設(shè)備的輸入輸出控制。例如:磁盤,光盤以及usb等等。
- cpu:使用調(diào)度程序?yàn)閏group任務(wù)提供cpu的訪問(wèn)。
- cpuacct:產(chǎn)生cgroup任務(wù)的cpu資源報(bào)告。
- cpuset:如果是多核心的cpu,這個(gè)子系統(tǒng)會(huì)為cgroup任務(wù)分配單獨(dú)的cpu和內(nèi)存。
- devices:允許或拒絕cgroup任務(wù)對(duì)設(shè)備的訪問(wèn)。
- freezer:暫停和恢復(fù)cgroup任務(wù)。
- memory:設(shè)置每個(gè)cgroup的內(nèi)存限制以及產(chǎn)生內(nèi)存資源報(bào)告。
- net_cls:標(biāo)記每個(gè)網(wǎng)絡(luò)包以供cgroup方便使用。
- ns:命名空間子系統(tǒng)。
- perf_event:增加了對(duì)每group的監(jiān)測(cè)跟蹤的能力,即可以監(jiān)測(cè)屬于某個(gè)特定的group的所有線程以及運(yùn)行在特定CPU上的線程。
目前docker只是用了其中一部分子系統(tǒng),實(shí)現(xiàn)對(duì)資源配額和使用的控制。
可以使用stress工具來(lái)測(cè)試CPU和內(nèi)存。使用下面的Dockerfile來(lái)創(chuàng)建一個(gè)基于Ubuntu的stress工具鏡像。
FROM ubuntu:14.04 RUN apt-get update &&apt-get install stress
CPU資源配額控制
CPU份額控制
docker提供了–cpu-shares
參數(shù),在創(chuàng)建容器時(shí)指定容器所使用的CPU份額值。使用示例:
使用命令docker run -tid –cpu-shares 100 ubuntu:stress
,創(chuàng)建容器,則最終生成的cgroup的cpu份額配置可以下面的文件中找到:
root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/<容器的完整長(zhǎng)ID>/cpu.shares 100
cpu-shares的值不能保證可以獲得1個(gè)vcpu或者多少GHz的CPU資源,僅僅只是一個(gè)彈性的加權(quán)值。
默認(rèn)情況下,每個(gè)docker容器的cpu份額都是1024。單獨(dú)一個(gè)容器的份額是沒(méi)有意義的,只有在同時(shí)運(yùn)行多個(gè)容器時(shí),容器的cpu加權(quán)的效果才能體現(xiàn)出來(lái)。例如,兩個(gè)容器A、B的cpu份額分別為1000和500,在cpu進(jìn)行時(shí)間片分配的時(shí)候,容器A比容器B多一倍的機(jī)會(huì)獲得CPU的時(shí)間片,但分配的結(jié)果取決于當(dāng)時(shí)主機(jī)和其他容器的運(yùn)行狀態(tài),實(shí)際上也無(wú)法保證容器A一定能獲得CPU時(shí)間片。比如容器A的進(jìn)程一直是空閑的,那么容器B是可以獲取比容器A更多的CPU時(shí)間片的。極端情況下,比如說(shuō)主機(jī)上只運(yùn)行了一個(gè)容器,即使它的cpu份額只有50,它也可以獨(dú)占整個(gè)主機(jī)的cpu資源。
cgroups只在容器分配的資源緊缺時(shí),也就是說(shuō)在需要對(duì)容器使用的資源進(jìn)行限制時(shí),才會(huì)生效。因此,無(wú)法單純根據(jù)某個(gè)容器的cpu份額來(lái)確定有多少cpu資源分配給它,資源分配結(jié)果取決于同時(shí)運(yùn)行的其他容器的cpu分配和容器中進(jìn)程運(yùn)行情況。
CPU周期控制
docker提供了–cpu-period、–cpu-quota兩個(gè)參數(shù)控制容器可以分配到的CPU時(shí)鐘周期。–cpu-period是用來(lái)指定容器對(duì)CPU的使用要在多長(zhǎng)時(shí)間內(nèi)做一次重新分配,而–cpu-quota是用來(lái)指定在這個(gè)周期內(nèi),最多可以有多少時(shí)間用來(lái)跑這個(gè)容器。跟–cpu-shares不同的是這種配置是指定一個(gè)絕對(duì)值,而且沒(méi)有彈性在里面,容器對(duì)CPU資源的使用絕對(duì)不會(huì)超過(guò)配置的值。
cpu-period和cpu-quota的單位為微秒(μs)。cpu-period的最小值為1000微秒,最大值為1秒(10^6 μs),默認(rèn)值為0.1秒(100000 μs)。cpu-quota的值默認(rèn)為-1,表示不做控制。
舉個(gè)例子,如果容器進(jìn)程需要每1秒使用單個(gè)CPU的0.2秒時(shí)間,可以將cpu-period設(shè)置為1000000(即1秒),cpu-quota設(shè)置為200000(0.2秒)。當(dāng)然,在多核情況下,如果允許容器進(jìn)程需要完全占用兩個(gè)CPU,則可以將cpu-period設(shè)置為100000(即0.1秒),cpu-quota設(shè)置為200000(0.2秒)。
使用示例:
使用命令docker run -tid –cpu-period 100000 –cpu-quota 200000 ubuntu
,創(chuàng)建容器,則最終生成的cgroup的cpu周期配置可以下面的文件中找到:
root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/<容器的完整長(zhǎng)ID>/cpu.cfs_period_us 100000 root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/<容器的完整長(zhǎng)ID>/cpu.cfs_quota_us 200000
關(guān)于cpu-shares、cpu-period、cpu-quota這些配置的詳細(xì)介紹,大家可以深入閱讀RedHat文檔中關(guān)于CPU的這一章。
CPU core控制
對(duì)多核CPU的服務(wù)器,docker還可以控制容器運(yùn)行限定使用哪些cpu內(nèi)核和內(nèi)存節(jié)點(diǎn),即使用–cpuset-cpus和–cpuset-mems參數(shù)。對(duì)具有NUMA拓?fù)洌ň哂卸郈PU、多內(nèi)存節(jié)點(diǎn))的服務(wù)器尤其有用,可以對(duì)需要高性能計(jì)算的容器進(jìn)行性能最優(yōu)的配置。如果服務(wù)器只有一個(gè)內(nèi)存節(jié)點(diǎn),則–cpuset-mems的配置基本上不會(huì)有明顯效果。
使用示例:
命令docker run -tid –name cpu1 –cpuset-cpus 0-2 ubuntu,表示創(chuàng)建的容器只能用0、1、2這三個(gè)內(nèi)核。最終生成的cgroup的cpu內(nèi)核配置如下:
root@ubuntu:~# cat /sys/fs/cgroup/cpuset/docker/<容器的完整長(zhǎng)ID>/cpuset.cpus 0-2
通過(guò)docker exec <容器ID> taskset -c -p 1(容器內(nèi)部第一個(gè)進(jìn)程編號(hào)一般為1),可以看到容器中進(jìn)程與CPU內(nèi)核的綁定關(guān)系,可以認(rèn)為達(dá)到了綁定CPU內(nèi)核的目的。
CPU配額控制參數(shù)的混合使用
當(dāng)上面這些參數(shù)中時(shí),cpu-shares控制只發(fā)生在容器競(jìng)爭(zhēng)同一個(gè)內(nèi)核的時(shí)間片時(shí),如果通過(guò)cpuset-cpus指定容器A使用內(nèi)核0,容器B只是用內(nèi)核1,在主機(jī)上只有這兩個(gè)容器使用對(duì)應(yīng)內(nèi)核的情況,它們各自占用全部的內(nèi)核資源,cpu-shares沒(méi)有明顯效果。
cpu-period、cpu-quota這兩個(gè)參數(shù)一般聯(lián)合使用,在單核情況或者通過(guò)cpuset-cpus強(qiáng)制容器使用一個(gè)cpu內(nèi)核的情況下,即使cpu-quota超過(guò)cpu-period,也不會(huì)使容器使用更多的CPU資源。
cpuset-cpus、cpuset-mems只在多核、多內(nèi)存節(jié)點(diǎn)上的服務(wù)器上有效,并且必須與實(shí)際的物理配置匹配,否則也無(wú)法達(dá)到資源控制的目的。
在系統(tǒng)具有多個(gè)CPU內(nèi)核的情況下,需要通過(guò)cpuset-cpus為容器CPU內(nèi)核才能比較方便地進(jìn)行測(cè)試。
試用下列命令創(chuàng)建測(cè)試用的容器:
docker run -tid –name cpu2 –cpuset-cpus 3 –cpu-shares 512 ubuntu:stress stress -c 10 docker run -tid –name cpu3 –cpuset-cpus 3 –cpu-shares 1024 ubuntu:stress stress -c 10
上面的ubuntu:stress鏡像安裝了stress工具來(lái)測(cè)試CPU和內(nèi)存的負(fù)載。兩個(gè)容器的命令stress -c 10&,這個(gè)命令將會(huì)給系統(tǒng)一個(gè)隨機(jī)負(fù)載,產(chǎn)生10個(gè)進(jìn)程,每個(gè)進(jìn)程都反復(fù)不停的計(jì)算由rand()產(chǎn)生隨機(jī)數(shù)的平方根,直到資源耗盡。
觀察到宿主機(jī)上的CPU試用率如下圖所示,第三個(gè)內(nèi)核的使用率接近100%,并且一批進(jìn)程的CPU使用率明顯存在2:1的使用比例的對(duì)比:
容器cpu2的CPU使用如下所示:
容器cpu3的CPU使用如下圖示:
分別進(jìn)入容器后,使用top命令可以明顯地看出容器之間的資源使用對(duì)比,并且也達(dá)到了綁定CPU內(nèi)核的目的。
注意:如果使用nsenter之類的工具進(jìn)入容器,再使用stress -c 10進(jìn)行測(cè)試,就可以發(fā)現(xiàn)cpuset-cpus的限制是可以被突破的,從而使stress測(cè)試進(jìn)程使用宿主機(jī)的所有CPU內(nèi)核。這是因?yàn)閚senter使用掛載的方式直接進(jìn)入了容器的命名空間,突破了命名空間中的cgroup控制。
內(nèi)存配額控制
和CPU控制一樣,docker也提供了若干參數(shù)來(lái)控制容器的內(nèi)存使用配額,可以控制容器的swap大小、可用內(nèi)存大小等各種內(nèi)存方面的控制。主要有以下參數(shù):
- memory-swappiness:控制進(jìn)程將物理內(nèi)存交換到swap分區(qū)的傾向,默認(rèn)系數(shù)為60。系數(shù)越小,就越傾向于使用物理內(nèi)存。值范圍為0-100。當(dāng)值為100時(shí),表示盡量使用swap分區(qū);當(dāng)值為0時(shí),表示禁用容器 swap 功能(這點(diǎn)不同于宿主機(jī),宿主機(jī) swappiness 設(shè)置為 0 也不保證 swap 不會(huì)被使用)。
- –kernel-memory:內(nèi)核內(nèi)存,不會(huì)被交換到swap上。一般情況下,不建議修改,可以直接參考docker的官方文檔。
- –memory:設(shè)置容器使用的最大內(nèi)存上限。默認(rèn)單位為byte,可以使用K、G、M等帶單位的字符串。
- –memory-reservation:?jiǎn)⒂脧椥缘膬?nèi)存共享,當(dāng)宿主機(jī)資源充足時(shí),允許容器盡量多地使用內(nèi)存,當(dāng)檢測(cè)到內(nèi)存競(jìng)爭(zhēng)或者低內(nèi)存時(shí),強(qiáng)制將容器的內(nèi)存降低到memory-reservation所指定的內(nèi)存大小。按照官方說(shuō)法,不設(shè)置此選項(xiàng)時(shí),有可能出現(xiàn)某些容器長(zhǎng)時(shí)間占用大量?jī)?nèi)存,導(dǎo)致性能上的損失。
- –memory-swap:等于內(nèi)存和swap分區(qū)大小的總和,設(shè)置為-1時(shí),表示swap分區(qū)的大小是無(wú)限的。默認(rèn)單位為byte,可以使用K、G、M等帶單位的字符串。如果–memory-swap的設(shè)置值小于–memory的值,則使用默認(rèn)值,為–memory-swap值的兩倍。
默認(rèn)情況下,容器可以使用主機(jī)上的所有空閑內(nèi)存。
與CPU的cgroups配置類似,docker會(huì)自動(dòng)為容器在目錄/sys/fs/cgroup/memory/docker/<容器的完整長(zhǎng)ID>中創(chuàng)建相應(yīng)cgroup配置文件,例如下面的文件:
這些文件與docker的相關(guān)配置是一一對(duì)應(yīng)的,可以參考RedHat的文檔Resource_Management_Guide的內(nèi)存部分來(lái)查看它們的作用。
內(nèi)存配額控制使用示例
設(shè)置容器的內(nèi)存上限,參考命令如下所示:
docker run -tid —name mem1 —memory 128m ubuntu:stress /bin/bash
默認(rèn)情況下,除了–memory指定的內(nèi)存大小以外,docker還為容器分配了同樣大小的swap分區(qū),也就是說(shuō),上面的命令創(chuàng)建出的容器實(shí)際上最多可以使用256MB內(nèi)存,而不是128MB內(nèi)存。如果需要自定義swap分區(qū)大小,則可以通過(guò)聯(lián)合使用–memory–swap參數(shù)來(lái)實(shí)現(xiàn)控制。
對(duì)上面的命令創(chuàng)建的容器,可以查看到在cgroups的配置文件中,查看到容器的內(nèi)存大小為128MB (128×1024×1024=134217728B),內(nèi)存和swap加起來(lái)大小為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
注意:執(zhí)行上述命令時(shí),命令行可能會(huì)輸出下面的警告:
WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.
這是因?yàn)橹鳈C(jī)上默認(rèn)不啟用cgroup來(lái)控制swap分區(qū),可以參考docker官方的相應(yīng)文檔,修改grub啟動(dòng)參數(shù)。
在容器中,依次使用下面的stress命令,即可對(duì)容器的內(nèi)存進(jìn)行壓力測(cè)試,確認(rèn)內(nèi)存。
stress –vm 1 –vm-bytes 256M –vm-hang 0 & stress –vm 1 –vm-bytes 250M –vm-hang 0 &
可以發(fā)現(xiàn),使用256MB進(jìn)行壓力測(cè)試時(shí),由于超過(guò)了內(nèi)存上限(128MB內(nèi)存+128MB swap),進(jìn)程被OOM殺死。使用250MB進(jìn)行壓力測(cè)試時(shí),進(jìn)程可以正常運(yùn)行,并且通過(guò)docker stats可以查看到容器的內(nèi)存已經(jīng)滿負(fù)載了。
磁盤IO配額控制
相對(duì)于CPU和內(nèi)存的配額控制,docker對(duì)磁盤IO的控制相對(duì)不成熟,大多數(shù)都必須在有宿主機(jī)設(shè)備的情況下使用。主要包括以下參數(shù):
- –device-read-bps:限制此設(shè)備上的讀速度(bytes per second),單位可以是kb、mb或者gb。
- –device-read-iops:通過(guò)每秒讀IO次數(shù)來(lái)限制指定設(shè)備的讀速度。
- –device-write-bps :限制此設(shè)備上的寫速度(bytes per second),單位可以是kb、mb或者gb。
- –device-write-iops:通過(guò)每秒寫IO次數(shù)來(lái)限制指定設(shè)備的寫速度。
- –blkio-weight:容器默認(rèn)磁盤IO的加權(quán)值,有效值范圍為10-100。
- –blkio-weight-device: 針對(duì)特定設(shè)備的IO加權(quán)控制。其格式為DEVICE_NAME:WEIGHT
磁盤IO配額控制示例
blkio-weight
要使–blkio-weight生效,需要保證IO的調(diào)度算法為CFQ??梢允褂孟旅娴姆绞讲榭矗?br />
root@ubuntu:~# cat /sys/block/sda/queue/scheduler noop [deadline] cfq
使用下面的命令創(chuàng)建兩個(gè)–blkio-weight值不同的容器:
docker run -ti –rm –blkio-weight 100 ubuntu:stress docker run -ti –rm –blkio-weight 1000 ubuntu:stress
在容器中同時(shí)執(zhí)行下面的dd命令,進(jìn)行測(cè)試:
time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
最終輸出如下圖所示:
在我的測(cè)試環(huán)境上沒(méi)有達(dá)到理想的測(cè)試效果,通過(guò)docker官方的blkio-weight doesn't take effect in docker Docker version 1.8.1 #16173
,可以發(fā)現(xiàn)這個(gè)問(wèn)題在一些環(huán)境上存在,但docker官方也沒(méi)有給出解決辦法。
device-write-bps
使用下面的命令創(chuàng)建容器,并執(zhí)行命令驗(yàn)證寫速度的限制。
docker run -tid –name disk1 –device-write-bps /dev/sda:1mb ubuntu:stress
通過(guò)dd來(lái)驗(yàn)證寫速度,輸出如下圖示:
可以看到容器的寫磁盤速度被成功地限制到了1MB/s。device-read-bps等其他磁盤IO限制參數(shù)可以使用類似的方式進(jìn)行驗(yàn)證。
容器空間大小限制
在docker使用devicemapper作為存儲(chǔ)驅(qū)動(dòng)時(shí),默認(rèn)每個(gè)容器和鏡像的最大大小為10G。如果需要調(diào)整,可以在daemon啟動(dòng)參數(shù)中,使用dm.basesize來(lái)指定,但需要注意的是,修改這個(gè)值,不僅僅需要重啟docker daemon服務(wù),還會(huì)導(dǎo)致宿主機(jī)上的所有本地鏡像和容器都被清理掉。
使用aufs或者overlay等其他存儲(chǔ)驅(qū)動(dòng)時(shí),沒(méi)有這個(gè)限制。
~~~以上所有截圖測(cè)試環(huán)境,宿主機(jī)為Ubuntu 14.04.4,docker版本為1.10.3~~~
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
docker搭建redis主從哨兵集群的實(shí)現(xiàn)步驟
本文主要介紹了docker搭建redis主從哨兵集群的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07一次centos Docker網(wǎng)橋模式無(wú)法訪問(wèn)宿主機(jī)Redis服務(wù)的故障排除經(jīng)歷
這篇文章主要給大家介紹了關(guān)于一次centos Docker網(wǎng)橋模式無(wú)法訪問(wèn)宿主機(jī)Redis服務(wù)的故障排除經(jīng)歷,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Docker具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10如何使用Docker搭建pypi私有倉(cāng)庫(kù)
這篇文章主要介紹了如何使用Docker搭建pypi私有倉(cāng)庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11docker-maven-plugin 插件無(wú)法拉取對(duì)應(yīng)jar包問(wèn)題
這篇文章主要介紹了docker-maven-plugin 插件無(wú)法拉取問(wèn)題,總是報(bào)錯(cuò),如何解決這個(gè)問(wèn)題呢,下面小編給大家?guī)?lái)了解決方法,一起看看吧2021-09-09一篇文章學(xué)會(huì)Docker命令小結(jié)
這篇文章主要介紹了一篇文章學(xué)會(huì)Docker命令小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07docker部署crownblog項(xiàng)目到阿里云的方法步驟
這篇文章主要介紹了docker部署crownblog項(xiàng)目到阿里云的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05docker部署nginx及nginx.conf文件配置方式
這篇文章主要介紹了docker部署nginx及nginx.conf文件配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08