天天看點

Docker | 容器 |(二)

                        --昨夜西風凋碧樹,獨上高樓,望盡天涯路

  • 資源限制

運作在docker host上的若幹容器,每個都需要CPU、記憶體和IO資源。對于KVM、VMware等虛拟化技術,使用者可以控制配置設定多少CPU、記憶體資源給每個虛拟機。對于容器,Docker也提供了類似的機制避免某個容器占用太多的資源而影響其他容器乃至整個系統。

1.記憶體限額

與作業系統類似,容器可使用的記憶體包括兩部分:實體記憶體和swap。Docker通過下面兩個參數來控制記憶體使用量:                     

(1)-m或--memory:設定記憶體的使用限額。

(2)--memory-swap:設定記憶體+swap的使用限額

當我們使用如下指令:

docker run -m 200M --memory-swap=300M ubuntu
           

意思是允許該容器最多使用200MB記憶體和100MB 的swap。預設情況下上面兩組參數為-1,即對容器記憶體和swap的使用沒有限制

下面使用progrium/stress鏡像來學習如何為容器配置設定記憶體。該鏡像可用于對容器執行壓力測試:

Docker | 容器 |(二)

--vm 1:啟動一個記憶體工作線程

--vm-bytes 280M:每個工作線程配置設定280M記憶體

Docker | 容器 |(二)

 因為280M記憶體在可配置設定的範圍(300M)内,是以工作線程能夠正常工作,其過程時:

1.配置設定280M記憶體

2.釋放280M記憶體

3.配置設定280M記憶體

...

  一直循環

如果讓工作線程配置設定的記憶體超過300M,結果是:配置設定的記憶體超多限額,stress線程報錯,容器退出。

Docker | 容器 |(二)

如果在啟動容器時隻指定-m而不指定--memory-swap,那麼--memory-swap預設為-m的兩倍,比如:

docker run -it -m 200M ubuntu

容器最多使用200M實體記憶體和200Mswap 

2.CPU限額

預設設定下,所有的容器可以平等地使用host CPU資源并且沒有限制。

Docker可以通過-c或--cpu-shares設定容器使用CPU地權重。如果不指定預設是1024。

與記憶體限額不同,通過-c設定的cpu share并不是CPU資源的絕對數量,而是一個相對的權重值。某個容器最終能夠配置設定到的CPU資源取決于它的cpu share占所有容器cpu share總和的比例。即就是通過cpu share可以設定容器使用CPU的優先級。

比如在host中啟動兩個容器A ,B。A的cpu share是B的兩倍。當兩個cpu都需要資源時,A得到的是B的兩倍。

--cpu用來指定工作線程數,由于我目前docker host有兩個cpu,是以指定--cpu 2。

(1)啟動container_A,cpu shares為1024:

Docker | 容器 |(二)

 (2)啟動container_B,cpu shares為512:

Docker | 容器 |(二)

 (3)在host中執行top檢視cpu的使用情況,container_A是container_B的兩倍:

Docker | 容器 |(二)

(4)現在暫停container_A,然後用top顯示container_B在container_A暫停下來的時候可以占滿整個cpu:

Docker | 容器 |(二)

3.Block IO帶寬限額

Block IO是另一種可以限制容器使用的資源。Block IO指的是磁盤的讀寫,docker可以設定權重、限制bps和iops的方式控制容器讀寫磁盤的帶寬。

(1)block IO權重

預設情況下,所有的容器能平等地讀寫磁盤,可以通過--blkio-weight參數來改變block IO的優先級。--blkio-weight與-cpu-shares類似,設定的是相對權重值,預設是500。如下,container_A讀寫磁盤的帶寬是container_B的兩倍:

(2)限制bps和iops

bps:每秒讀寫的資料量;iops:每秒IO的次數

通過下面的參數控制容器的bps和iops:

--device-read-bps:限制讀某個裝置的bps

--device-write-bps:限制寫某個裝置的bps

--device-read-iops:限制讀某個裝置的iops

--device-write-iops:限制寫某個裝置的iops

顯示容器寫/dev/sda的速率為30MB/s:

通過dd測試在容器中讀寫磁盤的速度。因為容器的檔案系統是在host /dev/sda上的,在容器中寫檔案相當于對host /dev/sda進行寫操作。另外,oflag=direct指定用dircet IO方式寫檔案,這樣--device-write-bps才能生效。

結果表明bps沒有超過30MB/s(這個地方每次都會超過30,達到31.5,還沒找到原因)。

Docker | 容器 |(二)

作為對比測試,如果不限速,結果如下:

Docker | 容器 |(二)
  • 容器底層技術

cgroup和namespace是很重要的兩種實作容器的底層技術。cgroup實作資源限額,namespace實作資源隔離

(1)cgroup

cgroup全稱Control Group。Linux作業系統通過cgroup可以設定程序使用CPU、記憶體和IO資源的限額(對于--cpu-shares、-m、--device-write-bps實際上就是在配置cgroup。

運作一個容器,然後我們可以看到在/sys/fs/cgroup下找到cgroup,在/sys/fs/cgroup/cpu/docker下,Linux會為每一個容器建立一個cgroup目錄,以容器的長ID命名:

Docker | 容器 |(二)
Docker | 容器 |(二)
Docker | 容器 |(二)

目錄中包含所有與cpu相關的cgroup配置,檔案cpu.shares儲存的就是--cpu-shares的配置,值為512。同理,/sys/fs/cgroup/memory/docker和/sys/fs/cgroup/blkio/docker中儲存的是記憶體以及Block IO的cgroup配置。

(2)namespace

每個容器中,我們看到的檔案系統、網卡等資源,這些資源看上去是容器自己的。即使host上有一塊實體網卡,但是每個容器也會認為自己有一塊獨立的網卡,這種方式使得容器更像一個獨立的計算機。

Linux實作這種方式的技術是namespace。namespace管理着host中全局唯一的資源,實作了容器間資源的隔離(使得每個容器都覺得隻有自己在使用它)。

Linux使用了6中namespace,分别對應6鐘資源:Mount、UTS、IPC、PID、Network和User。

1.Mount namespace

Mount namespace讓容器看上去擁有整個檔案系統。

容器擁有自己的/目錄,可以執行mount和umount指令。這些操作隻在目前容器中生效,不會影響到host和其他容器。

2.UTS namespace

UTS namespace讓容器有自己的hostname。預設容器的hostname是它的短ID,可以通過-h或者-hostname參數設定:

Docker | 容器 |(二)

3.IPC namespace

IPC namespace讓容器擁有自己的共享記憶體和信号量(semaphore)來實作程序間通信,而不會與host和其他容器的IPC混在一起。

4.PID namespace

容器在host中以程序的形式運作。例如目前host中運作了兩個容器:

Docker | 容器 |(二)

通過ps axf可以檢視容器程序:

Docker | 容器 |(二)

所有的容器程序都挂在dockerd程序下,同時也可以看到容器自己的子程序。當進到某個容器,ps就隻能看到自己的程序了:

Docker | 容器 |(二)

而且程序的PID不同于host中對應程序的PID,容器中PID=1的程序當然也不是host的init程序。也就是說:容器擁有自己獨立的一套PID,就是PID namespace提供的功能。

5.Network namespace

Network namespace讓容器擁有自己獨立的網卡、IP、路由等資源。

6.User namespace

User namespace讓容器能夠管理好自己的使用者,host不能看到容器中建立的使用者:

Docker | 容器 |(二)

在容器中建立了使用者luffy,但是host中并不會建立相應的使用者。