Docker 運行時資源限制

github:https://github.com/docker

 

github docker 內存設置爲2倍的源代碼:https://github.com/docker/libcontainer/blob/v1.2.0/cgroups/fs/memory.go#L39

原文地址:https://blog.csdn.net/shimachao/article/details/53728507

內存測試工具

rpm -Uvh http://pkgs.repoforge.org/stress/stress-1.0.2-1.el7.rf.x86_64.rpm

使用stress進行測試
stress --vm 1 --vm-bytes 150M --vm-hang 0

查看資源佔用情況可以使用 top 或者 ctop 函數。

 

 

Docker 運行時資源限制
Docker 基於 Linux 內核提供的 cgroups 功能,可以限制容器在運行時使用到的資源,比如內存、CPU、塊 I/O、網絡等。

內存限制
概述
Docker 提供的內存限制功能有以下幾點:

容器能使用的內存和交換分區大小。
容器的核心內存大小。
容器虛擬內存的交換行爲。
容器內存的軟性限制。
是否殺死佔用過多內存的容器。
容器被殺死的優先級
一般情況下,達到內存限制的容器過段時間後就會被系統殺死。

內存限制相關的參數
執行docker run命令時能使用的和內存限制相關的所有選項如下。

選項    描述
-m,--memory    內存限制,格式是數字加單位,單位可以爲 b,k,m,g。最小爲 4M
--memory-swap    內存+交換分區大小總限制。格式同上。必須必-m設置的大
--memory-reservation    內存的軟性限制。格式同上
--oom-kill-disable    是否阻止 OOM killer 殺死容器,默認沒設置
--oom-score-adj    容器被 OOM killer 殺死的優先級,範圍是[-1000, 1000],默認爲 0
--memory-swappiness    用於設置容器的虛擬內存控制行爲。值爲 0~100 之間的整數
--kernel-memory    核心內存限制。格式同上,最小爲 4M
用戶內存限制
用戶內存限制就是對容器能使用的內存和交換分區的大小作出限制。使用時要遵循兩條直觀的規則:-m,--memory選項的參數最小爲 4 M。--memory-swap不是交換分區,而是內存加交換分區的總大小,所以--memory-swap必須比-m,--memory大。在這兩條規則下,一般有四種設置方式。

你可能在進行內存限制的實驗時發現docker run命令報錯:WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.

這是因爲宿主機內核的相關功能沒有打開。按照下面的設置就行。

step 1:編輯/etc/default/grub文件,將GRUB_CMDLINE_LINUX一行改爲GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

step 2:更新 GRUB,即執行$ sudo update-grub

step 3: 重啓系統。

1. 不設置
如果不設置-m,--memory和--memory-swap,容器默認可以用完宿舍機的所有內存和 swap 分區。不過注意,如果容器佔用宿主機的所有內存和 swap 分區超過一段時間後,會被宿主機系統殺死(如果沒有設置--00m-kill-disable=true的話)。

2. 設置-m,--memory,不設置--memory-swap
給-m或--memory設置一個不小於 4M 的值,假設爲 a,不設置--memory-swap,或將--memory-swap設置爲 0。這種情況下,容器能使用的內存大小爲 a,能使用的交換分區大小也爲 a。因爲 Docker 默認容器交換分區的大小和內存相同。

如果在容器中運行一個一直不停申請內存的程序,你會觀察到該程序最終能佔用的內存大小爲 2a。

比如$ docker run -m 1G ubuntu:16.04,該容器能使用的內存大小爲 1G,能使用的 swap 分區大小也爲 1G。容器內的進程能申請到的總內存大小爲 2G。

3. 設置-m,--memory=a,--memory-swap=b,且b > a
給-m設置一個參數 a,給--memory-swap設置一個參數 b。a 時容器能使用的內存大小,b是容器能使用的 內存大小 + swap 分區大小。所以 b 必須大於 a。b -a 即爲容器能使用的 swap 分區大小。

比如$ docker run -m 1G --memory-swap 3G ubuntu:16.04,該容器能使用的內存大小爲 1G,能使用的 swap 分區大小爲 2G。容器內的進程能申請到的總內存大小爲 3G。

4. 設置-m,--memory=a,--memory-swap=-1
給-m參數設置一個正常值,而給--memory-swap設置成 -1。這種情況表示限制容器能使用的內存大小爲 a,而不限制容器能使用的 swap 分區大小。

這時候,容器內進程能申請到的內存大小爲 a + 宿主機的 swap 大小。

Memory reservation
這種 memory reservation 機制不知道怎麼翻譯比較形象。Memory reservation 是一種軟性限制,用於節制容器內存使用。給--memory-reservation設置一個比-m小的值後,雖然容器最多可以使用-m使用的內存大小,但在宿主機內存資源緊張時,在系統的下次內存回收時,系統會回收容器的部分內存頁,強迫容器的內存佔用回到--memory-reservation設置的值大小。

沒有設置時(默認情況下)--memory-reservation的值和-m的限定的值相同。將它設置爲 0 會設置的比-m的參數大 等同於沒有設置。

Memory reservation 是一種軟性機制,它不保證任何時刻容器使用的內存不會超過--memory-reservation限定的值,它只是確保容器不會長時間佔用超過--memory-reservation限制的內存大小。

例如:

$ docker run -it -m 500M --memory-reservation 200M ubuntu:16.04 /bin/bash
1
如果容器使用了大於 200M 但小於 500M 內存時,下次系統的內存回收會嘗試將容器的內存鎖緊到 200M 以下。

例如:

$ docker run -it --memory-reservation 1G ubuntu:16.04 /bin/bash
1
容器可以使用儘可能多的內存。--memory-reservation確保容器不會長時間佔用太多內存。

OOM killer
默認情況下,在出現 out-of-memory(OOM) 錯誤時,系統會殺死容器內的進程來獲取更多空閒內存。這個殺死進程來節省內存的進程,我們姑且叫它 OOM killer。我們可以通過設置--oom-kill-disable選項來禁止 OOM killer 殺死容器內進程。但請確保只有在使用了-m/--memory選項時才使用--oom-kill-disable禁用 OOM killer。如果沒有設置-m選項,卻禁用了 OOM-killer,可能會造成出現 out-of-memory 錯誤時,系統通過殺死宿主機進程或獲取更改內存。

下面的例子限制了容器的內存爲 100M 並禁止了 OOM killer:

$ docker run -it -m 100M --oom-kill-disable ubuntu:16.04 /bin/bash
1
是正確的使用方法。

而下面這個容器沒設置內存限制,卻禁用了 OOM killer 是非常危險的:

$ docker run -it --oom-kill-disable ubuntu:16.04 /bin/bash
1
容器沒用內存限制,可能或導致系統無內存可用,並嘗試時殺死系統進程來獲取更多可用內存。

一般一個容器只有一個進程,這個唯一進程被殺死,容器也就被殺死了。我們可以通過--oom-score-adj選項來設置在系統內存不夠時,容器被殺死的優先級。負值更教不可能被殺死,而正值更有可能被殺死。

核心內存
核心內存和用戶內存不同的地方在於核心內存不能被交換出。不能交換出去的特性使得容器可以通過消耗太多內存來堵塞一些系統服務。核心內存包括:

stack pages(棧頁面)
slab pages
socket memory pressure
tcp memory pressure
可以通過設置核心內存限制來約束這些內存。例如,每個進程都要消耗一些棧頁面,通過限制核心內存,可以在覈心內存使用過多時阻止新進程被創建。

核心內存和用戶內存並不是獨立的,必須在用戶內存限制的上下文中限制核心內存。

假設用戶內存的限制值爲 U,核心內存的限制值爲 K。有三種可能地限制核心內存的方式:

U != 0,不限制核心內存。這是默認的標準設置方式
K < U,核心內存時用戶內存的子集。這種設置在部署時,每個 cgroup 的內存總量被過度使用。過度使用核心內存限制是絕不推薦的,因爲系統還是會用完不能回收的內存。在這種情況下,你可以設置 K,這樣 groups 的總數就不會超過總內存了。然後,根據系統服務的質量自有地設置 U。
K > U,因爲核心內存的變化也會導致用戶計數器的變化,容器核心內存和用戶內存都會觸發回收行爲。這種配置可以讓管理員以一種統一的視圖看待內存。對想跟蹤核心內存使用情況的用戶也是有用的。
例如:

$ docker run -it -m 500M --kernel-memory 50M ubuntu:16.04 /bin/bash
1
容器中的進程最多能使用 500M 內存,在這 500M 中,最多隻有 50M 核心內存。

$ docker run -it --kernel-memory 50M ubuntu:16.04 /bin/bash
1
沒用設置用戶內存限制,所以容器中的進程可以使用儘可能多的內存,但是最多能使用 50M 核心內存。

Swappiness
默認情況下,容器的內核可以交換出一定比例的匿名頁。--memory-swappiness就是用來設置這個比例的。--memory-swappiness可以設置爲從 0 到 100。0 表示關閉匿名頁面交換。100 表示所有的匿名頁都可以交換。默認情況下,如果不適用--memory-swappiness,則該值從父進程繼承而來。

例如:

$ docker run -it --memory-swappiness=0 ubuntu:16.04 /bin/bash
1
將--memory-swappiness設置爲 0 可以保持容器的工作集,避免交換代理的性能損失。

CPU 限制
概述
Docker 的資源限制和隔離完全基於 Linux cgroups。對 CPU 資源的限制方式也和 cgroups 相同。Docker 提供的 CPU 資源限制選項可以在多核系統上限制容器能利用哪些 vCPU。而對容器最多能使用的 CPU 時間有兩種限制方式:一是有多個 CPU 密集型的容器競爭 CPU 時,設置各個容器能使用的 CPU 時間相對比例。二是以絕對的方式設置容器在每個調度週期內最多能使用的 CPU 時間。

CPU 限制相關參數
docker run命令和 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 核上運行。

例如:

$ docker run -it --cpuset-cpus="1,3" ubuntu:14.04 /bin/bash
1
表示容器中的進程可以在 cpu 1 和 cpu 3 上執行。

$ docker run -it --cpuset-cpus="0-2" ubuntu:14.04 /bin/bash
1
表示容器中的進程可以在 cpu 0、cpu 1 及 cpu 3 上執行。

在 NUMA 系統上,我們可以設置容器可以使用的內存節點。

例如:

$ docker run -it --cpuset-mems="1,3" ubuntu:14.04 /bin/bash
1
表示容器中的進程只能使用內存節點 1 和 3 上的內存。

$ docker run -it --cpuset-mems="0-2" ubuntu:14.04 /bin/bash
1
表示容器中的進程只能使用內存節點 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 權值的分佈可能是這樣的:

PID    container    CPU CPU share
100    {C0}     0   100% of CPU0
101    {C1}     1   100% of CPU1
102    {C1}     2   100% of CPU2
1
2
3
4
CPU 資源的絕對限制
Linux 通過 CFS(Completely Fair Scheduler,完全公平調度器)來調度各個進程對 CPU 的使用。CFS 默認的調度週期是 100ms。

關於 CFS 的更多信息,參考CFS documentation on bandwidth limiting。

我們可以設置每個容器進程的調度週期,以及在這個週期內各個容器最多能使用多少 CPU 時間。使用--cpu-period即可設置調度週期,使用--cpu-quota即可設置在每個週期內容器能使用的 CPU 時間。兩者一般配合使用。

例如:

$ docker run -it --cpu-period=50000 --cpu-quota=25000 ubuntu:16.04 /bin/bash
1
將 CFS 調度的週期設爲 50000,將容器在每個週期內的 CPU 配額設置爲 25000,表示該容器每 50ms 可以得到 50% 的 CPU 運行時間。

$ docker run -it --cpu-period=10000 --cpu-quota=20000 ubuntu:16.04 /bin/bash
1
將容器的 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。

$ docker run --rm --name test01 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 deadloop:busybox-1.25.1-glibc
1
調度週期爲 50000,容器在每個週期內最多能使用 50000 cpu 時間。

再用docker stats test01可以觀察到該容器對 CPU 的使用率在100%左右。然後,我們再以同樣的參數啓動另一個容器。

$ docker run --rm --name test02 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 deadloop:busybox-1.25.1-glibc
1
再用docker stats test01 test02可以觀察到這兩個容器,每個容器對 cpu 的使用率在 50% 左右。說明容器並沒有在每個週期內使用 50000 的 cpu 時間。

使用docker stop test02命令結束第二個容器,再加一個參數-c 2048啓動它:

$ docker run --rm --name test02 --cpu-cpus 1 --cpu-quota=50000 --cpu-period=50000 -c 2048 deadloop:busybox-1.25.1-glibc
1
再用docker stats test01命令可以觀察到第一個容器的 CPU 使用率在 33% 左右,第二個容器的 CPU 使用率在 66% 左右。因爲第二個容器的共享值是 2048,第一個容器的默認共享值是 1024,所以第二個容器在每個週期內能使用的 CPU 時間是第一個容器的兩倍。
 

 

 

 

------------------------------------------------------------------------------------------------------------

 

原文地址:https://blog.csdn.net/horsefoot/article/details/51731543

 

docker通過cgroup來控制容器使用的資源配額,包括CPU、內存、磁盤三大方面,基本覆蓋了常見的資源配額和使用量控制。

cgroup簡介

cgroup是Control Groups的縮寫,是Linux 內核提供的一種可以限制、記錄、隔離進程組所使用的物理資源(如 cpu、memory、磁盤IO等等) 的機制,被LXC、docker等很多項目用於實現進程資源控制。cgroup將任意進程進行分組化管理的 Linux 內核功能。cgroup本身是提供將進程進行分組化管理的功能和接口的基礎結構,I/O 或內存的分配控制等具體的資源管理功能是通過這個功能來實現的。這些具體的資源管理功能稱爲cgroup子系統,有以下幾大子系統實現:

  1. blkio:設置限制每個塊設備的輸入輸出控制。例如:磁盤,光盤以及usb等等。
  2. cpu:使用調度程序爲cgroup任務提供cpu的訪問。
  3. cpuacct:產生cgroup任務的cpu資源報告。
  4. cpuset:如果是多核心的cpu,這個子系統會爲cgroup任務分配單獨的cpu和內存。
  5. devices:允許或拒絕cgroup任務對設備的訪問。
  6. freezer:暫停和恢復cgroup任務。
  7. memory:設置每個cgroup的內存限制以及產生內存資源報告。
  8. net_cls:標記每個網絡包以供cgroup方便使用。
  9. ns:命名空間子系統。
  10. perf_event:增加了對每group的監測跟蹤的能力,即可以監測屬於某個特定的group的所有線程以及運行在特定CPU上的線程。

目前docker只是用了其中一部分子系統,實現對資源配額和使用的控制。

可以使用stress工具來測試CPU和內存。使用下面的Dockerfile來創建一個基於Ubuntu的stress工具鏡像。

FROM ubuntu:14.04
RUN apt-get update &&apt-get install stress

CPU資源配額控制

CPU份額控制

docker提供了–cpu-shares參數,在創建容器時指定容器所使用的CPU份額值。使用示例:

使用命令docker run -tid –cpu-shares 100 ubuntu:stress,創建容器,則最終生成的cgroup的cpu份額配置可以下面的文件中找到:

root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/<容器的完整長ID>/cpu.shares
100

cpu-shares的值不能保證可以獲得1個vcpu或者多少GHz的CPU資源,僅僅只是一個彈性的加權值。

默認情況下,每個docker容器的cpu份額都是1024。單獨一個容器的份額是沒有意義的,只有在同時運行多個容器時,容器的cpu加權的效果才能體現出來。例如,兩個容器A、B的cpu份額分別爲1000和500,在cpu進行時間片分配的時候,容器A比容器B多一倍的機會獲得CPU的時間片,但分配的結果取決於當時主機和其他容器的運行狀態,實際上也無法保證容器A一定能獲得CPU時間片。比如容器A的進程一直是空閒的,那麼容器B是可以獲取比容器A更多的CPU時間片的。極端情況下,比如說主機上只運行了一個容器,即使它的cpu份額只有50,它也可以獨佔整個主機的cpu資源。

cgroups只在容器分配的資源緊缺時,也就是說在需要對容器使用的資源進行限制時,纔會生效。因此,無法單純根據某個容器的cpu份額來確定有多少cpu資源分配給它,資源分配結果取決於同時運行的其他容器的cpu分配和容器中進程運行情況。

CPU週期控制

docker提供了–cpu-period、–cpu-quota兩個參數控制容器可以分配到的CPU時鐘週期。–cpu-period是用來指定容器對CPU的使用要在多長時間內做一次重新分配,而–cpu-quota是用來指定在這個週期內,最多可以有多少時間用來跑這個容器。跟–cpu-shares不同的是這種配置是指定一個絕對值,而且沒有彈性在裏面,容器對CPU資源的使用絕對不會超過配置的值。

cpu-period和cpu-quota的單位爲微秒(μs)。cpu-period的最小值爲1000微秒,最大值爲1秒(10^6 μs),默認值爲0.1秒(100000 μs)。cpu-quota的值默認爲-1,表示不做控制。

舉個例子,如果容器進程需要每1秒使用單個CPU的0.2秒時間,可以將cpu-period設置爲1000000(即1秒),cpu-quota設置爲200000(0.2秒)。當然,在多核情況下,如果允許容器進程需要完全佔用兩個CPU,則可以將cpu-period設置爲100000(即0.1秒),cpu-quota設置爲200000(0.2秒)。

使用示例:

使用命令docker run -tid –cpu-period 100000 –cpu-quota 200000 ubuntu,創建容器,則最終生成的cgroup的cpu週期配置可以下面的文件中找到:

root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/<容器的完整長ID>/cpu.cfs_period_us
100000
root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/<容器的完整長ID>/cpu.cfs_quota_us
200000

關於cpu-shares、cpu-period、cpu-quota這些配置的詳細介紹,大家可以深入閱讀RedHat文檔中關於CPU的這一章

CPU core控制

對多核CPU的服務器,docker還可以控制容器運行限定使用哪些cpu內核和內存節點,即使用–cpuset-cpus和–cpuset-mems參數。對具有NUMA拓撲(具有多CPU、多內存節點)的服務器尤其有用,可以對需要高性能計算的容器進行性能最優的配置。如果服務器只有一個內存節點,則–cpuset-mems的配置基本上不會有明顯效果。

使用示例:

命令docker run -tid –name cpu1 –cpuset-cpus 0-2 ubuntu,表示創建的容器只能用0、1、2這三個內核。最終生成的cgroup的cpu內核配置如下:

root@ubuntu:~# cat /sys/fs/cgroup/cpuset/docker/<容器的完整長ID>/cpuset.cpus
0-2

通過docker exec <容器ID> taskset -c -p 1(容器內部第一個進程編號一般爲1),可以看到容器中進程與CPU內核的綁定關係,可以認爲達到了綁定CPU內核的目的。

quota01

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內核才能比較方便地進行測試。

試用下列命令創建測試用的容器:

 

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工具來測試CPU和內存的負載。兩個容器的命令stress -c 10&,這個命令將會給系統一個隨機負載,產生10個進程,每個進程都反覆不停的計算由rand()產生隨機數的平方根,直到資源耗盡。

觀察到宿主機上的CPU試用率如下圖所示,第三個內核的使用率接近100%,並且一批進程的CPU使用率明顯存在2:1的使用比例的對比:

quota02

容器cpu2的CPU使用如下所示:

quota03

容器cpu3的CPU使用如下圖示:

quota04

 

分別進入容器後,使用top命令可以明顯地看出容器之間的資源使用對比,並且也達到了綁定CPU內核的目的。

注意:如果使用nsenter之類的工具進入容器,再使用stress -c 10進行測試,就可以發現cpuset-cpus的限制是可以被突破的,從而使stress測試進程使用宿主機的所有CPU內核。這是因爲nsenter使用掛載的方式直接進入了容器的命名空間,突破了命名空間中的cgroup控制。

內存配額控制

和CPU控制一樣,docker也提供了若干參數來控制容器的內存使用配額,可以控制容器的swap大小、可用內存大小等各種內存方面的控制。主要有以下參數:

  • memory-swappiness:控制進程將物理內存交換到swap分區的傾向,默認係數爲60。係數越小,就越傾向於使用物理內存。值範圍爲0-100。當值爲100時,表示儘量使用swap分區;當值爲0時,表示禁用容器 swap 功能(這點不同於宿主機,宿主機 swappiness 設置爲 0 也不保證 swap 不會被使用)。
  • –kernel-memory:內核內存,不會被交換到swap上。一般情況下,不建議修改,可以直接參考docker的官方文檔。
  • –memory:設置容器使用的最大內存上限。默認單位爲byte,可以使用K、G、M等帶單位的字符串。
  • –memory-reservation:啓用彈性的內存共享,當宿主機資源充足時,允許容器儘量多地使用內存,當檢測到內存競爭或者低內存時,強制將容器的內存降低到memory-reservation所指定的內存大小。按照官方說法,不設置此選項時,有可能出現某些容器長時間佔用大量內存,導致性能上的損失。
  • –memory-swap:等於內存和swap分區大小的總和,設置爲-1時,表示swap分區的大小是無限的。默認單位爲byte,可以使用K、G、M等帶單位的字符串。如果–memory-swap的設置值小於–memory的值,則使用默認值,爲–memory-swap值的兩倍。

默認情況下,容器可以使用主機上的所有空閒內存。

與CPU的cgroups配置類似,docker會自動爲容器在目錄/sys/fs/cgroup/memory/docker/<容器的完整長ID>中創建相應cgroup配置文件,例如下面的文件:

quota05

這些文件與docker的相關配置是一一對應的,可以參考RedHat的文檔Resource_Management_Guide的內存部分來查看它們的作用。

內存配額控制使用示例

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

docker run -tid —name mem1 —memory 128m ubuntu:stress /bin/bash

默認情況下,除了–memory指定的內存大小以外,docker還爲容器分配了同樣大小的swap分區,也就是說,上面的命令創建出的容器實際上最多可以使用256MB內存,而不是128MB內存。如果需要自定義swap分區大小,則可以通過聯合使用–memory–swap參數來實現控制。

對上面的命令創建的容器,可以查看到在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

注意:執行上述命令時,命令行可能會輸出下面的警告:

WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.

這是因爲主機上默認不啓用cgroup來控制swap分區,可以參考docker官方的相應文檔,修改grub啓動參數。

在容器中,依次使用下面的stress命令,即可對容器的內存進行壓力測試,確認內存。

stress –vm 1 –vm-bytes 256M –vm-hang 0 &
stress –vm 1 –vm-bytes 250M –vm-hang 0 &

quota06

可以發現,使用256MB進行壓力測試時,由於超過了內存上限(128MB內存+128MB swap),進程被OOM殺死。使用250MB進行壓力測試時,進程可以正常運行,並且通過docker stats可以查看到容器的內存已經滿負載了。

quota07

磁盤IO配額控制

相對於CPU和內存的配額控制,docker對磁盤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-100。
  • –blkio-weight-device: 針對特定設備的IO加權控制。其格式爲DEVICE_NAME:WEIGHT

存儲配額控制的相關參數,可以參考Red Hat文檔中blkio這一章,瞭解它們的詳細作用。

磁盤IO配額控制示例

blkio-weight

要使–blkio-weight生效,需要保證IO的調度算法爲CFQ。可以使用下面的方式查看:

root@ubuntu:~# cat /sys/block/sda/queue/scheduler
noop [deadline] cfq

使用下面的命令創建兩個–blkio-weight值不同的容器:

docker run -ti –rm –blkio-weight 100 ubuntu:stress
docker run -ti –rm –blkio-weight 1000 ubuntu:stress

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

time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct

最終輸出如下圖所示:

quota08

在我的測試環境上沒有達到理想的測試效果,通過docker官方的blkio-weight doesn’t take effect in docker Docker version 1.8.1 #16173,可以發現這個問題在一些環境上存在,但docker官方也沒有給出解決辦法。

device-write-bps

使用下面的命令創建容器,並執行命令驗證寫速度的限制。

docker run -tid –name disk1 –device-write-bps /dev/sda:1mb ubuntu:stress

通過dd來驗證寫速度,輸出如下圖示:

quota09

可以看到容器的寫磁盤速度被成功地限制到了1MB/s。device-read-bps等其他磁盤IO限制參數可以使用類似的方式進行驗證。

容器空間大小限制

在docker使用devicemapper作爲存儲驅動時,默認每個容器和鏡像的最大大小爲10G。如果需要調整,可以在daemon啓動參數中,使用dm.basesize來指定,但需要注意的是,修改這個值,不僅僅需要重啓docker daemon服務,還會導致宿主機上的所有本地鏡像和容器都被清理掉。

使用aufs或者overlay等其他存儲驅動時,沒有這個限制。

~~~以上所有截圖測試環境,宿主機爲Ubuntu 14.04.4,docker版本爲1.10.3~~~

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章