Docker容器的內核調優

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

本文今天討論的重點不放在對 Linux內核調優的討論上來,如下連接中關於傳統領域內核調優的討論較爲細緻,感興趣的讀者能夠學習一下:http://colobu.com/2014/09/18/...docker

本文主要經過對比 docker與 linux內核調優的不一樣,介紹下 docker容器的內核調優。bash

Docker內核調優與 Linux內核調優的不一樣

Docker容許在啓動容器時指定 --sysctl參數來設置系統參數,經過這些參數來調整系統性能,下面重點說下其與 linux調整系統參數的不一樣之處。服務器

整體來講,容器比 linux可調整項要少,容器的可調整參數須要知足3個條件:tcp

1. 未被 docker限制

Docker經過一個 ValidateSysctl函數來限制 sysctl參數能夠傳入的項,源碼以下:ide

// 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生成獨立的配置。spa

通常來講,宿主機和容器是一對多的關係,一個沒法 namespace化的配置項,調整以後會影響全部其餘容器以及宿主機自己,這是咱們沒法接受的。

典型的例子就是因爲容器共享內核的特性,致使了大多數跟 kernal相關的參數項都沒法 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設置參數的條件,簡單的畫一個圖再展開說明下:

圖片描述

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

  • 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的。

經過這兩步,便可得到當前環境下的全部容器內核可調優配置集。

相關文章
相關標籤/搜索