Docker內核調優和Linux內核調優的這些區別你知道麼?

Docker內核調優和Linux內核調優的這些區別你知道麼?

Docker

在傳統的虛擬機領域,通過調節一些系統參數來提供(高)系統性能是一種常規手段。例如,對於一個被頻繁訪問的服務器來說,可以通過設置net.ipv4.ip_local_port_range = 1024 65000(默認32768 61000),來允許系統開放更多的端口。

本文今天討論的重點不放在對 Linux內核調優的討論上來,以下鏈接中關於傳統領域內核調優的討論較為細緻,感興趣的讀者可以學習一下:http://colobu.com/2014/09/18/linux-tcpip-tuning/ 。

本文主要通過對比 docker與 linux內核調優的不同,介紹下 docker 容器的內核調優。

Docker內核調優與 Linux內核調優的不同

Docker 允許在啟動容器時指定 --sysctl 參數來設置系統參數,通過這些參數來調整系統性能,下面重點說下其與 linux 調整系統參數的不同之處。

總體來說,容器比 linux 可調整項要少,容器的可調整參數需要滿足 3個條件:

1. 未被 docker限制

Docker 通過一個 ValidateSysctl 函數來限制 sysctl 參數可以傳入的項,源碼如下:

// docker/opts/opts.go

func ValidateSysctl(val string) (string, error) { validSysctlMap := map[string]bool{ "kernel.msgmax": true, "kernel.msgmnb": true, "kernel.msgmni": true,

"kernel.sem": true,

"kernel.shmall": true,

"kernel.shmmax": true, "kernel.shmmni": true, "kernel.shm_rmid_forced": true,

}

validSysctlPrefixes := []string{

"net.",

"fs.mqueue.",

}

...

也就是說,docker 允許調整的只有上面列出的 kernel.xxx 部分,以及以 net.和 fs.mqueue為前綴的部分,如果試圖調整其他項,則會報 whitelist 驗證不通過錯誤:

root@hzwangxing01:~/tmp# docker run -it --sysctl kernel.acpi_video_flags=0 \

hub.c.163.com/public/debian:7.9 bash

invalid argument"kernel.acpi_video_flags=0"for--

sysctl: sysctl'kernel.acpi_video_flags=0'is not whitelisted

2. 容器中可以看見該配置項

並不是所有宿主機上可見的配置項,在容器中都是可見的,例如 net.core.rmem_max參數(定義內核用於所有類型的連接的最大接收緩衝大小):

root@hzwangxing01:~/tmp# sysctl -a | grep rmem_max

net.core.rmem_max = 212992

root@hzwangxing01:~/tmp# docker run hub.c.163.com/public/debian:7.9 sysctl -a | grep rmem_max

root@hzwangxing01:~/tmp#

之所以在容器中不可見,與 docker無關,應該是 kernel namespace的 issue。

3. 該配置項可以 namespace

配置項無法 namespace化,指的是該配置項是全局的,無法為每個 namespace生成獨立的配置。

一般來說,宿主機和容器是一對多的關係,一個無法 namespace化的配置項,調整之後會影響所有其他容器以及宿主機本身,這是我們無法接受的。

典型的例子就是由於容器共享內核的特性,導致了大多數跟 kernel相關的參數項都無法 namespace化。例如:

root@hzwangxing01:~/tmp# sysctl -a | grep pid_max

kernel.pid_max =32768

root@hzwangxing01:~/tmp# docker run -d --privileged --name test hub.c.163.com/public/debian:7.9

a43e89ee85d36e250e0886331e9d6213094f31260eb9e1539b83f0e9cfc91848

root@hzwangxing01:~/tmp# docker exec test sysctl -w kernel.pid_max=86723

kernel.pid_max = 86723

root@hzwangxing01:~/tmp# sysctl -a | grep pid_max

kernel.pid_max = 86723

從上面的例子可以看出,如果在容器中設置 kernel的 pid_max屬性,相應的,宿主機的對應屬性也會被修改。

對限制條件組合的詳細說明

根據上面列舉的三個 docker設置參數的條件,簡單的畫一個圖再展開說明下:

Docker內核調優和Linux內核調優的這些區別你知道麼?

韋氏圖

上圖是一個簡單的韋氏圖:

  • dvn:滿足3個條件的屬性集,可以通過 --sysctl傳入參數設置並達到預期效果

  • dv(只滿足 d和 v,也即 d&&v&&!n):雖然別的條件滿足,但無法被 namespace化的屬性集,屬於無法修復的,除非自己修改內核,打 patch(不推薦)

  • dn:在容器中不可見,無法通過 --sysctl設置,會報錯相關文件找不到

root@hzwangxing01:~/tmp# docker run -d --sysctl net.core.rmem_max=1024

hub.c.163.com/public/debian:7.9e2353339b7c9ef52a573d92c0136a20ab7373fc7e06345575cf5efe4cf10256a

docker: Error response from daemon: invalid header field value

"oci runtime error: container_linux.go:247: starting container process caused "

process_linux.go:359: container init caused \\"open /proc/sys/net/core/rmem_max: no such file or directory\\""\n".

這類情況也是無法修復的。

  • vn:這一類是可以修復的,只需要去 docker源碼中添加白名單項即可

  • d、v、n:鑑於無法同時滿足“容器中可見”和“可 namespace化”兩個條件,這三類也是不可修復的

補充說明

這裡需要指出的一點是,可能有人會認為滿足條件 d的是經過 docker驗證的,同時支持 dvn的,很遺憾,並不是這樣。

Docker明確限定的 kernel調節項以及 fs.mqueue前綴項確實是同時符合 dvn的,但是問題主要在於過於寬泛的 net前綴項,這裡面就有一些表項不滿足 vn,這裡不再一一展開說明了。

Docker可配置項

由上面的論述可以得出一個結論,只有 dvn和 vn(需對 docker代碼稍作調整)是可以配置的,所以,所有的可配置項包括 dvn+vn,也即 v&&n,其中:

  • v很容易獲得,只需在一個運行中的容器使用 sysctl -a就可以看到所有可見配置項;

  • 在 v的基礎上,找出可以 namespace化的配置項,方法其實在上面的示例中已經使用過了,這裡再強調下:以 privileged權限啟動一個容器(確保有權限在容器中設置配置項),在容器中使用 sysctl -w設置某個配置項為不同值,並在宿主機上確認該配置是否變更,如果未發生變更,即說明該項是滿足 n的。

通過這兩步,即可獲得當前環境下的所有容器內核可調優配置集。


分享到:


相關文章: