docker OCI runtime(待完善)
Open Container Initiative(OCI)目前有2個標準:runtime-spec以及image-spec。前者規定了如何執行解壓過的filesystem bundle。OCI規定了如何下載OCI映象並解壓到OCI filesystem bundle,這樣OCI runtime就可以執行OCI bundle了。OCI(當前)相當於規定了容器的images和runtime的協議,只要實現了OCI的容器就可以實現其相容性和可移植性。implements中列出了部分OCI標準的實現。本文不討論windows下的實現,具體參見Open Container Initiative Runtime Specification
system bundle是個目錄,用於給runtime提供啟動容器必備的配置檔案和檔案系統。標準的容器bundle包含以下內容:
config.json:該檔案包含了容器執行的配置資訊,該檔案必須存在bundle的根目錄,且名字必須為config.json
容器的根目錄,可以由config.json中的root.path指定
下面使用runc來執行一個容器,runc是根據OCI標準生成的一個cli工具。前面兩個命令用於提取filesystem,最後一個用於生成config.json,兩者組織在一起就是一個filesystem bundle
# mkdir rootfs # docker export $(docker create busybox)| tar -C rootfs -xvf -
# runc spec
使用runc來執行這個bundle,可以使用state檢視該容器的狀態
# runc run busybox # runc state busybox { "ociVersion": "1.0.0", "id": "busybox", "pid": 41732, "status": "running", "bundle": "/home/test", "rootfs": "/home/test/rootfs", "created": "2018-12-25T14:41:58.82202891Z","owner": ""
OCI runtime包含runtime,runtime-linux,config,config-linux
- runtime規定了如下內容
- state
ociVersion:建立容器時的OCI版本
- id:容器唯一的ID
- status:容器的runtime狀態,可以為如下值
- creating:容器正在被建立(lifecycle的第2步)
- created:容器完成建立,但沒有返回錯誤且沒有執行使用者程式(lifecycle的第2步之後)
- running:容器正在執行使用者程式且沒有返回錯誤(lifecycle的第5步之後)
- stoped:容器程序退出(lifecycle的第7步)
- pid:host上看到的容器程序
- bundle:host上容器bundle目錄的絕對路徑
- annotation:容器相關的標註,可選
- state
由於runc實現了OCI runtime,使用runc state檢視上述busybox可以得到state相關的資訊
{ "ociVersion": "1.0.0", "id": "busybox", "pid": 41732, "status": "running", "bundle": "/home/test", "rootfs": "/home/test/rootfs", "created": "2018-12-25T14:41:58.82202891Z", "owner": "" }
-
- lifecycle 描述了容器從建立到退出的事件觸發點
- OCI runtime的create呼叫與bundle的路徑和id相關
- OCI runtime的必須依據config.json中的設定來建立環境,如果無法建立config.json中指定的環境,則返回錯誤。此階段主要建立config.json中的資源,並沒有執行使用者程式。該步驟之後任何多config.json的修改都不會影響容器
- runtime使用容器的唯一id來執行start容器命令
- runtine必須執行 prestart hooks,如果 prestart hooks執行失敗,則返回錯誤,並停止容器,執行第9條操作
- runtime必須執行使用者程式
- runtime必須執行poststart hooks,如果poststart hooks執行失敗,則必須記錄warning日誌,而poststart hooks和lifecycle繼續執行
- 容器程序退出,可能由錯誤退出,人為退出,程式崩潰或runtime 執行kill命令引起
- runtime使用容器的唯一id來執行delete容器操作
- 如果在容器建立階段(第2步)沒有完成某些步驟,則容器必須被銷燬
- runtime必須執行poststop hooks,如果poststop hooks執行失敗,則必須記錄warning日誌,而poststop hooks和lifecycle繼續執行
- operation runtime必須支援如下操作
- query state:
state <container-id>,參見上述state描述
- create:
create <container-id> <path-to-bundle>,runtime應該提供檢測id唯一性的功能。該操作中會用到config.json除process之外的配置屬性(因為process實在start階段用到的)。實現中可能會與本規範不一致,如在create操作之前實現了pre-create
- start:
start <container-id>,執行config.json的process中定義的程式,如果process沒有設定,則返回錯誤
- kill:
kill <container-id> <signal>,向一個非running狀態的容器傳送的訊號會被忽略。此操作用於向容器程序傳送訊號
- delete:
delete <container-id>,嘗試刪除一個非stopped的容器會返回錯誤。容器刪除後其id可能會被後續的容器使用
- query state:
- lifecycle 描述了容器從建立到退出的事件觸發點
# runc delete busybox
cannot delete container busybox that is not stopped: running
-
- hooks:定義了每個操作前後的動作,參見runtime configuration for hooks
- configuration定義了程序執行,環境變數等配置。現有json和go版本的配置,其中go中定義了與平臺(linux,solaris,windows相關的tag),如下:
// Linux is platform-specific configuration for Linux based containers. Linux *Linux `json:"linux,omitempty" platform:"linux"` // Solaris is platform-specific configuration for Solaris based containers. Solaris *Solaris `json:"solaris,omitempty" platform:"solaris"` // Windows is platform-specific configuration for Windows based containers. Windows *Windows `json:"windows,omitempty" platform:"windows"` // VM specifies configuration for virtual-machine-based containers. VM *VM `json:"vm,omitempty" platform:"vm"`
-
- Specification version:必選,指定了bundle使用的OCI的版本
- root:
- path:容器的bundle路徑,可以是相對路徑和絕對路徑,該值通常為rootfs
- readonly:當設定為true時,容器的根檔案為只讀,預設false
- mount:按照配置的順序進行掛載
- destination:容器中的掛載點,必須是絕對路徑
- source:掛載的裝置名稱,檔案或目錄名稱(bind mount時),當option中有bind或rbind時改mount型別為bind mount
- option:mount的選項,參見mount
- process:定義了容器的程序資訊
- terminal:預設false,為true時,linux系統會為該程序分配一個pseudoterminal(pts),並使用標準輸入輸出流
consoleSize:指定terminal的長寬規格,width和height
- cwd:執行命令的絕對路徑
- env:環境變數
- args:命令引數,至少需要指定一個引數,首引數即被execvp執行的檔案
根據平臺不同支援如下配置
POSIX process 支援設定POSIX和Linux平臺
-
- rlimits:設定程序的資源,如cpu,記憶體,檔案大小等,參見getrlimit。docker裡面使用--ulimit來設定單個程序的資源
- type:linux和Solaris
- soft:核心分配給該程序的資源
- hard;可配置的資源的最大值,即soft的最大值。unprivileged程序(沒有CAP_SYS_RESOURCE capability)可以將soft設定為0-hard之間的值
- rlimits:設定程序的資源,如cpu,記憶體,檔案大小等,參見getrlimit。docker裡面使用--ulimit來設定單個程序的資源
Linux process:
-
apparmorProfile:指定程序的apparmor檔案
capabilities:指定程序的
capabilities
noNewPrivileges:設定為true後可以防止程序獲取額外的許可權(如使得suid和檔案capabilities失效),該標記位在核心4.10版本之後可以在/proc/$pid/status中檢視NoNewPrivs的設定值。更多參見no_new_privs
oomScoreAdj
:給程序設定oom_score_adj值,程序的oom涉及以下3個檔案,oom_adj和oom_score_adj功能類似,oom_adj主要用於相容老版本,oomScoreAdj的功能就是設定/proc/$PID/oom_score_adj中的值(範圍-1000~1000),系統通過該值和oom_score來決定kill程序的優先順序。oom_score為只讀檔案,oom通過對系統所有程序的oom_score進行排序,值越大,越可能在記憶體不足時被kill掉。(參見linux oom機制分析和oom介紹)
/proc/$PID/oom_adj /proc/$PID/oom_score /proc/$PID/oom_score_adj
可以通過如下命令檢視系統所有程序的oom_score
ps -eo pid,comm,pmem --sort -rss | awk '{"cat /proc/"$1"/oom_score" | getline oom; print $0"\t"oom}'
-
selinuxLabel
:設定程序的SELinux 標籤,即MAC值- user 用於控制執行程序的使用者
- uid:指定容器名稱空間的user id
- gid:指定容器名稱空間的group id
- additionalGids:指定容器名稱空間中附加的group id
- hostname:指定容器程序看到的hostname
- Platform-specific configuration:包含在linux,Windows,solaris,vm等host平臺上使用namespaces,cgroup等。下面以linux為例
- Default Filesystems:如下路徑需要正確掛載到容器中,以便容器程序的正確執行
Path Type /proc proc /sys sysfs /dev/pts devpts /dev/shm tmpfs
-
-
- namespaces,為包含如下引數的陣列
- type:指定namespace型別,為ipc,mount,user,network,uts,pid,cgroup,如果沒有指定namespace type,則繼承父namespace的屬性
- path:namespace的檔案,如果沒有指定,則生成一個新的namespace
- User namespace mappings,uidMappings和gidMappings指定了user和group從host到容器的對映關係,為結構圖陣列,包含containerid,hostid和size這3個屬性
- device:列出了必須在容器中存在的裝置,為結構體陣列,有如下屬性
- type:裝置的型別
- path:容器中的全路徑
- major, minor:裝置的主裝置號和次裝置號,主裝置號表示型別,次裝置號表示分割槽,可以使用"ls -al /dev"檢視主次裝置號。設定可以參見device
- fileMode:檔案ADC訪問許可權
- uid:容器中裝置的uid
- gid:容器中裝置的gid
- cgroup:用於控制容器的資源以及裝置接入等。
- Cgroups Path:cgroup的路徑(待cgroup完善湖更新)
- namespaces,為包含如下引數的陣列
-
-
- POSIX-platform Hooks:支援使用hooks來設定lifecycle中使用者自定義動作
- hooks
- prestart:在使用者程式執行前以及容器名稱空間建立後執行,包含如下屬性的陣列:
- path:類似execv的路徑,為均對路徑
- args:類似execv的引數
- env:環境變數
- timeout:終端hooks的超時時間
- poststart:在使用者程式執行之後且在start步驟返回前執行,同 prestart的陣列一樣
- poststop:在容器刪除之後且在delete步驟返回前執行,同prestart的陣列一樣
- prestart:在使用者程式執行前以及容器名稱空間建立後執行,包含如下屬性的陣列:
- hooks
- Annotations:為key-value型別的任意字串,如果沒有annotation,該欄位可以為空,也可以不存在
- extensibility:遇到無法識別的欄位需要返回錯誤
- POSIX-platform Hooks:支援使用hooks來設定lifecycle中使用者自定義動作
- Linux Runtime:該規範規定了容器檔案描述符相關的內容。預設下runtime只會開啟stdin, stdout和stderr這3個檔案描述符
runtime包含1, config.md, config-linux.md, and runtime-linux.md.
參考:
https://cizixs.com/2017/11/05/oci-and-runc/
https://github.com/opencontainers/runtime-spec/blob/master/config.md
https://github.com/opencontainers/runtime-spec/blob/master/specs-go/config.go