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會使用默認的cgroup路徑

可以使用resources字段來配置cgroup,注意:只有在需要更新cgroup的時候才配置該字段內容

    "cgroupsPath": "/myRuntime/myContainer",
    "resources": {
        "memory": {
        "limit": 100000,
        "reservation": 200000
        },
        "devices": [
            {
                "allow": false,
                "access": "rwm"
            }
        ]
   }

Device whitelist:用於配置設備白名單

  • allow (boolean, REQUIRED) -允許
  • type (string, OPTIONAL) - 設備類似: a (all), c (char), or b (block). 默認為all
  • major, minor (int64, OPTIONAL) - 設備的主次號. 默認all
  • access (string, OPTIONAL) - 設備的cgroup權限.r (read), w (write), 和m (mknod).

Memory:具體可以參見cgroup memory

  • limit (int64, OPTIONAL) - 設置內存使用limit
  • reservation (int64, OPTIONAL) - 設置內存的soft limit
  • swap (int64, OPTIONAL) - 設置memory+Swap使用limit
  • kernel (int64, OPTIONAL) -  設置內存的hard limit
  • kernelTCP (int64, OPTIONAL) - 設置內核TCP buffer的hard limit
  • swapness:設置swap的使用比例
  • disableOOMKiller:是否開啟oomkiller

CPU:具體可以參見cgroup CPU

  • shares (uint64, OPTIONAL) - cgroup中task使用的cpu的相對比例
  • quota (int64, OPTIONAL) - 一個period中使用的cpu時間
  • period (uint64, OPTIONAL) - 以毫秒為單位的cpu周期 (CFS scheduler only)
  • realtimeRuntime (int64, OPTIONAL) - 以毫秒為單位的 cgroup tasks連續使用cpu資源的最長周期
  • realtimePeriod (uint64, OPTIONAL) - 實時調度的 period
  • cpus (string, OPTIONAL) - CPU列表
  • mems (string, OPTIONAL) - memory nodes列表

Block IO:

Huge page limits:

  • pageSize :大頁大小
  • limit:bytes為單位限制的大頁的使用上限

Network:

  • classID:cgroup網絡報文的標簽
  • priorities

name:網卡名稱
priority:網卡優先級

PIDs:

limit:cgroup限制的pid的數目

RDMA

Sysctl:允許在容器運行過程中修改內核參數

Seccomp:在linux內核中為應用提供了一種沙盒機制。更多參見seccomp

seccomp

defaultAction:seccomp的默認動作,允許值類型為syscalls[].action

architectures:系統調用的平台,如下

SCMP_ARCH_X86
SCMP_ARCH_X86_64
SCMP_ARCH_X32
SCMP_ARCH_ARM
SCMP_ARCH_AARCH64
SCMP_ARCH_MIPS
SCMP_ARCH_MIPS64
SCMP_ARCH_MIPS64N32
SCMP_ARCH_MIPSEL
SCMP_ARCH_MIPSEL64
SCMP_ARCH_MIPSEL64N32
SCMP_ARCH_PPC
SCMP_ARCH_PPC64
SCMP_ARCH_PPC64LE
SCMP_ARCH_S390
SCMP_ARCH_S390X
SCMP_ARCH_PARISC
SCMP_ARCH_PARISC6

syscalls:匹配seccomp的系統調用,該屬性可選

name:系統調用的名稱,至少有一個

action:seccomp的動作規則。libseccomp v2.3.2中如下:

SCMP_ACT_KILL
SCMP_ACT_TRAP
SCMP_ACT_ERRNO
SCMP_ACT_TRACE
SCMP_ACT_ALLOW

args:

index (uint, REQUIRED) - 系統調用的index
value (uint64, REQUIRED) - 系統調用參數的值
valueTwo (uint64, OPTIONAL) - 系統調用參數的值
op (string, REQUIRED) - 系統調用參數的動作。 libseccomp v2.3.2如下

SCMP_CMP_NE
SCMP_CMP_LT
SCMP_CMP_LE
SCMP_CMP_EQ
SCMP_CMP_GE
SCMP_CMP_GT
SCMP_CMP_MASKED_EQ

Rootfs Mount Propagation

rootfsPropagation:設置rootfs的mount Propagation類型,slave,private或shared

      • Linux Runtime:該規范規定了容器文件描述符相關的內容。默認下runtime只會打開stdin, stdout和stderr這3個文件描述符

Masked Paths

maskedPaths:容器無法讀取該設置的路徑

    "maskedPaths": [
        "/proc/kcore" ]

Readonly Paths

readonlyPaths:容器只讀該設置的路徑

    • 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:遇到無法識別的字段需要返回錯誤

 TIPS:

  • openshift 3.11版本的runc采用的是其自己實現的runtime,位於/usr/libexec/docker/docker-runc-current,實際與runc類似。

 

參考:

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

Rootfs Mount Propagation


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM