1. 程式人生 > 實用技巧 >Docker資源限制

Docker資源限制

前言

在使用容器時(未被Kubernetes進行管理的情況下),我們單臺主機上可能會跑幾十個容器,容器雖然都相互隔離,但是用的卻是與宿主機相同的核心,CPU、記憶體、磁碟等硬體資源。注:容器沒有核心。
預設情況下,容器沒有資源限制,可以使用主機核心排程程式允許的儘可能多的給定資源;如果不對容器資源進行限制,容器之間就會相互影響,一些佔用硬體資源較高的容器會吞噬掉所有的硬體資源,從而導致其它容器無硬體資源可用,發生停服狀態。
Docker提供了限制記憶體,CPU或磁碟IO的方法, 可以對容器所佔用的硬體資源大小以及多少進行限制,我們在使用docker create建立一個容器或者docker run執行一個容器的時候就可以來對此容器的硬體資源做限制。

Docker核心

我們在docker第一章有講到docker核心,分別為Namespace和CGroup
Namespect實現了對容器的資源隔離
CGroup實現了對容器的資源限制

我們在講Docker第四章和第五章Docker網路設定的時候有用到過Namespace的六種名稱空間;今天將會講到怎麼使用核心來呼叫CGroup對容器資源做限制

OOM介紹

out of memorty

OOM:out of memorty的簡稱,稱之為記憶體溢位

  1. 如果記憶體耗盡,記憶體將無法給予記憶體空間,核心檢測到沒有足夠的記憶體來執行重要的系統功能,它會丟擲OOM或Out of Memory異常,記憶體將會溢位,隨之會有選擇性的殺死相應的程序。
  2. 記憶體屬於不可壓縮性資源,如果執行這個程序的記憶體不夠使用,這個程序它就會一直申請記憶體資源,直到記憶體溢位。
  3. CPU屬於可壓縮性資源,所以CPU並不會出現這種情況,例如一個程序佔用了一個核心100%的CPU,那麼原本這個程序是需要佔用200%的CPU資源,如果其它程序所佔用的CPU核心並不需要多高的CPU頻率,那麼此程序就會佔用掉空閒的CPU,如果其它程序也需要他自己核心的CPU頻率,那麼此程序就只能使用對它自己所使用CPU核心100%,因此叫做可壓縮。
  4. 記憶體的有選擇性:為什麼不是殺死佔用記憶體最高的程序呢?
    舉個例子:例如我們運行了一個MySQL和一個Tomcat;這個MySQL原本是需要佔用2G的記憶體資源,但他佔用了1.9G;而Tomcat原本是需要佔用500M的記憶體空間,可他佔用了1G記憶體空間,這個時候當記憶體報異常OOM的時候,就會選擇Tomcat程序進行傳送kill -9的訊號,進行殺死以釋放記憶體。
  5. 當我們的一個重要的程序佔用的記憶體超標而導致記憶體OOM的情況下,我們不希望核心來Kill掉我們這個程序,怎麼辦?
    我們可以調整記憶體OOM後kill程序的優先順序,優先順序越高越優先殺死,則反之
    為此,Docker特地調整了docker daemon的OOM優先順序,以免它被核心的殺死,但容器的優先順序並未被調整

導致記憶體OOM

  1. 載入物件過大
  2. 相應資源過多,來不及載入
  3. 應用執行時間較長未重啟,從而一點一點佔用記憶體資源,長期積累導致佔用記憶體空間較多
  4. 程式碼存在記憶體洩漏bug

解決OOM辦法

  1. 記憶體引用上做一些處理,常用的有軟引用
  2. 記憶體中載入圖片直接在記憶體中做處理,(如邊界壓縮)
  3. 動態回收記憶體
  4. 優化Delivk虛擬機器的堆記憶體分配
  5. 自定義堆記憶體大小
  6. 定期重啟應用以釋放記憶體

壓測工具stress

下載stress

docker pull lorel/docker-stress-ng:latest
latest: Pulling from lorel/docker-stress-ng
c52e3ed763ff: Pull complete 
a3ed95caeb02: Pull complete 
7f831269c70e: Pull complete 
Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322
Status: Downloaded newer image for lorel/docker-stress-ng:latest

使用方法

docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help
--name 指定lorel/docker-stress-ng:latest所啟動的測試得容器名稱為stress
--it:開啟一個偽終端,並提供互動式
--rm:容器停止即刪除
lorel/docker-stress-ng:latest:壓測stress工具映象名稱
stress:lorel/docker-stress-ng:latest映象內所內建的命令,必須使用此命令來指定--help支援的選項

stress常用選項

--cpu N:啟動幾個子程序來做壓測,預設一個程序使用一個CPU核心,選項可簡寫為 -c N
docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help | grep  "cpu N"
 -c N, --cpu N            start N workers spinning on sqrt(rand())

--vm N:啟動幾個程序來做匿名頁壓測,選項可簡寫為 -m N
docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help | grep  "vm N"
 -m N, --vm N             start N workers spinning on anonymous mmap

--vm-bytes N:為 --vm N指定的程序提供記憶體分配,每個程序可以分配到的記憶體數量,預設為256M
docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help | grep  "vm-bytes N"
--vm-bytes N       allocate N bytes per vm worker (default 256MB)

Docker記憶體限制

限制記憶體注意事項

  1. 為需要限制容器內的應用提前做好壓測,例如Nginx容器自身所佔記憶體空間,以及預算業務量大小所需佔用的記憶體空間,進行壓測後,才能進入生產環境使用
  2. 保證宿主機記憶體資源充足,監控及時上報容器內的記憶體使用情況,一旦容器所佔用的記憶體不足,立刻對容器記憶體限制做調整或者打包此容器為映象到其它記憶體充足的機器上進行啟動
  3. 如果實體記憶體充足,儘量不要使用swap交換記憶體,swap會導致記憶體計算複雜

設定記憶體選項

注意:可限制的記憶體單位:b、k、m、g;分別對應bytes、KB、MB、GB

  1. -m or --memory=:容器能使用的最大記憶體大小,最小值為4M
  2. --memory-swap=:容器能夠使用swap記憶體的大小,使用—memory-swap選項必須要使用—memory選項,否則—memory-swap不生效
  3. --memory-swappiness:預設情況下,主機可以把容器使用的匿名頁swap出來,你可以設定一個0-100之間的值,代表swap出來的比例,如果此值設定為0,容器就會先使用實體記憶體,能不用就不用swap空間,如果設定為100,則反之,能用swap就會用,哪怕有一絲可以用到swap空間的可能性就會使用swap空間
  4. --memory-reservation:預留的一個記憶體空間,設定一個記憶體使用soft limit,如果docker發現主機記憶體不足,會執行OOM操作,這個值必須小於—memory設定的值
  5. --kernel-memory:容器能夠使用kernel memory大小,最小值為4M
  6. --oom-kill-disable:是否執行OOM的時候殺死容器,只有設定了-m或者-memory,才可以設定此值,值為flase或者true,設定為false之後當此容器的記憶體溢位的時候就會對此容器執行kill操作,否則容器會耗盡主機記憶體,而且導致主機應用被殺死,如果這個容器執行的應用非常重要,就把—oom-kill-disable設定為true,就是禁止被oom殺掉

--memory-swap詳解:
swap:交換記憶體
ram:實體記憶體

檢視記憶體大小

限制容器記憶體

使用docker的--memory選項來限制容器能夠使用實體記憶體的大小,使用stress命令的選項--vm指定啟動幾個佔用記憶體的程序和每個佔用記憶體程序所佔用的記憶體空間大小
我們指定了容器最多使用實體記憶體512M,啟動兩個佔用記憶體的程序,每個程序分別佔用512M的空間,那麼兩個程序理論上需要佔用1024的空間,我們只給了1024的空間,顯然是不夠的

docker run --name stress-memory  -it --rm -m 512M  lorel/docker-stress-ng:latest stress --vm 2 --vm-bytes 512M 
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

使用docker stats命令來檢視容器硬體資源的使用情況
可以看到我們的stress-memory容器的總記憶體為512M,使用了500多點,但為超過521M,記憶體佔用的百分比為99.3%

使用htop命令來檢視資源情況

限制容器swap記憶體

設定oom時是否殺掉程序

Docker CPU限制

檢視CPU核心數以及編碼

設定CPU選項

  1. --cpu-shares:共享式CPU資源,是按比例切分CPU資源;
    比如當前系統上一共運行了兩個容器,第一個容器上權重是1024,第二個容器權重是512,
    第二個容器啟動之後沒有執行任何程序,自己身上的512都沒有用完,而第一臺容器的程序有很多,這個時候它完全可以佔用容器二的CPU空閒資源,這就是共享式CPU資源;如果容器二也跑了程序,那麼就會把自己的512給要回來,按照正常權重1024:512劃分,為自己的程序提供CPU資源。
    如果容器二不用CPU資源,那容器一就能夠給容器二的CPU資源所佔用,如果容器二也需要CPU資源,那麼就按照比例劃分,這就是CPU共享式,也證明了CPU為可壓縮性資源。
  2. --cpus:限制容器執行的核數;
    從docker1.13版本之後,docker提供了--cpus引數可以限定容器能使用的CPU核數。這個功能可以讓我們更精確地設定容器CPU使用量,是一種更容易理解也常用的手段。
  3. --cpuset-cpus:限制容器執行在指定的CPU核心;
    執行容器執行在哪個CPU核心上,例如主機有4個CPU核心,CPU核心標識為0-3,我啟動一臺容器,只想讓這臺容器執行在標識0和3的兩個CPU核心上,可以使用cpuset來指定。

限制CPU Share

啟動stress壓測工具,並使用stress命令加--cpu選項來啟動四個程序,預設一個程序佔用一顆CPU核心

docker run --name stress-share  -it --rm --cpu-shares 512  lorel/docker-stress-ng:latest stress -c 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 cpu

壓測工具會吃掉倆個核心的所有CPU資源
再次開啟一個視窗,使用htop命令來檢視硬體資源損耗情況
我們一共開了兩個程序,預設會佔用兩個cpu核心,每個核心的資源為100%,兩個也就是為200%,由於沒有指定限制在某個CPU核心上,所以它是動態的跑在四核CPU核心數,但是stress佔用CPU的資源不會超出200%

再次開啟一個視窗,使用docker top container也可以檢視到兩個程序一共消耗了多少cpu資源

限制CPU核數

我們使用docker的--cpus選項來限制cpu執行的核心數,使用stress命令的選項--cpu來限制啟動的程序數
顯示cpu只執行兩個核心數,也就是隻能執行200%CPU資源,啟動4個程序,也就是講這4個程序只能跑在200%的cpu資源上

docker run --name stress-cpus  -it --rm --cpus 2  lorel/docker-stress-ng:latest stress -c 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu

使用htop命令檢視cpu佔用資源
可以看到四個程序,但是跑在了四顆cpu上面,但是每顆cpu只運行了50%左右的資源,4*50也就是200%左右的cpu資源

使用docker top container也可以檢視到四個程序一共消耗了多少cpu資源

限制容器執行在指定核心

我們使用docker的--cpuset-cpus選項來指定cpu執行在哪個核心上,使用stress的選項--cpu來指定啟動的程序數
我們指定4個程序執行在編號為0和2的cpu上

docker run --name stress-cpuset  -it --rm --cpuset-cpus=0,2  lorel/docker-stress-ng:latest stress -c 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu

使用htop檢視系統硬體佔用資源
可以看到和預期一樣,佔用了第一顆和第三顆cpu,每個程序佔用cpu資源為50%,總資源為200%,兩顆cpu的量

※更多文章和資料|點選後方文字直達 ↓↓↓
100GPython自學資料包
阿里雲K8s實戰手冊
[阿里雲CDN排坑指南]CDN
ECS運維指南
DevOps實踐手冊
Hadoop大資料實戰手冊
Knative雲原生應用開發指南
OSS 運維實戰手冊
雲原生架構白皮書
Zabbix企業級分散式監控系統原始碼文件
Linux&Python自學資料包
10G面試題戳領