1. 程式人生 > >docker OCI runtime(待完善)

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包含runtimeruntime-linuxconfigconfig-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:容器相關的標註,可選

由於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 描述了容器從建立到退出的事件觸發點
      1. OCI runtime的create呼叫與bundle的路徑和id相關
      2. OCI runtime的必須依據config.json中的設定來建立環境,如果無法建立config.json中指定的環境,則返回錯誤。此階段主要建立config.json中的資源,並沒有執行使用者程式。該步驟之後任何多config.json的修改都不會影響容器
      3. runtime使用容器的唯一id來執行start容器命令
      4. runtine必須執行 prestart hooks,如果 prestart hooks執行失敗,則返回錯誤,並停止容器,執行第9條操作
      5. runtime必須執行使用者程式
      6. runtime必須執行poststart hooks,如果poststart hooks執行失敗,則必須記錄warning日誌,而poststart hooks和lifecycle繼續執行
      7. 容器程序退出,可能由錯誤退出,人為退出,程式崩潰或runtime 執行kill命令引起
      8. runtime使用容器的唯一id來執行delete容器操作
      9. 如果在容器建立階段(第2步)沒有完成某些步驟,則容器必須被銷燬
      10. 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可能會被後續的容器使用
# runc delete busybox
cannot delete container busybox that is not stopped: running
  • configuration定義了程序執行,環境變數等配置。現有jsongo版本的配置,其中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之間的值

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完善湖更新)

 

 

    • POSIX-platform Hooks:支援使用hooks來設定lifecycle中使用者自定義動作
      • hooks
        • prestart:在使用者程式執行前以及容器名稱空間建立後執行,包含如下屬性的陣列:
          • path:類似execv的路徑,為均對路徑
          • args:類似execv的引數
          • env:環境變數
          • timeout:終端hooks的超時時間
        • poststart:在使用者程式執行之後且在start步驟返回前執行,同 prestart的陣列一樣
        • poststop:在容器刪除之後且在delete步驟返回前執行,同prestart的陣列一樣
    • Annotations:為key-value型別的任意字串,如果沒有annotation,該欄位可以為空,也可以不存在
    • extensibility:遇到無法識別的欄位需要返回錯誤

 

 

  • Linux Runtime:該規範規定了容器檔案描述符相關的內容。預設下runtime只會開啟stdin, stdout和stderr這3個檔案描述符

 

runtime包含1config.mdconfig-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