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包含以下内容:
下面使用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",idbusyBoxpid41732statusrunningbundle/home/testrootfs/home/test/rootfscreated2018-12-25T14:41:58.82202891Zowner""
OCI runtime包含runtime,runtime-linux,config,config-linux
- runtime规定了如下内容
由于runc实现了OCI runtime,使用runc state查看上述busyBox可以得到state相关的信息
{ "" }
-
- 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 描述了容器从创建到退出的事件触发点
-
- 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,1)">solaris Windows is platform-specific configuration for Windows based containers. Windows *Windows `json:windows,1)">windows VM specifies configuration for virtual-machine-based containers. VM *VM `json:vm,1)">vm"`
-
- Specification version:必选,指定了bundle使用的OCI的版本
- root:
- mount:按照配置的顺序进行挂载
- process:定义了容器的进程信息
根据平台不同支持如下配置
POSIX process 支持设置POSIX和Linux平台
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介绍)
可以通过如下命令查看系统所有进程的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
可以使用resources字段来配置cgroup,注意:只有在需要更新cgroup的时候才配置该字段内容
cgroupsPath/myRuntime/myContainerresources: { memorylimit100000reservation200000 },1)">devices: [ { allow": falseaccessrwm } ] }
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
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
Masked Paths
maskedPaths:容器无法读取该设置的路径
"maskedPaths": [
"/proc/kcore"
]
Readonly Paths
readonlyPaths:容器只读该设置的路径
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