1 介绍
1.1 什么是OCI
OCI(Open Container Initiative)即开放的容器运行时规范,目的在于定义一个容器运行时及镜像的相关标准和规范,其中包含:
- runtime-spec:容器的生命周期管理,包括容器的创建、启动、暂停、恢复和销毁等操作。规定了容器运行时应该如何使用 Linux
内核功能来实现进程隔离、资源限制和文件系统挂载等。还规定了容器配置的格式(
config.json
),这个文件描述了容器的元数据、根文件系统、网络设置、进程信息等。具体参考 runtime-spec 。 - image-spec:定义了容器镜像的格式和内容布局,描述了镜像的层次结构、元数据格式、依赖关系、配置选项等。确保不同的镜像管理工具(例如 Docker、Podman、containerd)都可以按照同一标准构建、分发和运行容器镜像。具体参考 image-spec 。
1.2 什么是runc
runc 是一个开源的 CLI 工具,用于创建和运行基于 OCI 标准的容器,它是 Docker、containerd 等容器运行时的底层实现,专门用于容器的创建、启动、停止和销毁,设计目标是为容器提供一个清亮且独立的运行时环境。
2 容器的生命周期
在 runc 里面,只有四种状态:created
、running
、paused
、stopped
四种状态,在本文章中添加了两种状态 init
和 creating
是为了更好的理解 runc 的生命周期转换过程。
2.1 init
- 容器在创建过程中首先会进入
init
状态。 - 当通过
runc create
初始化容器时,runc 会生成一个新的容器实例,并将其设置为init
状态。在这个状态下,容器的命名空间、cgroup
资源隔离等还没有完全准备好。 - 这是容器最初的状态,在
init
状态之后会进入creating
状态。
2.2 creating
- 容器从
init
过渡到creating
状态。 - 在这个状态,runc 会根据
config.json
配置文件进行命名空间、cgroup
、网络等资源的创建和初始化。 - 容器还未启动主进程,但所有的隔离环境都已准备好,处于等待启动的状态。
2.3 created
- 容器已经完成初始化,处于
created
状态。 - 在这个状态下,容器已经分配了所有资源,但还没有执行容器内的任何进程。
- 可以理解为“预启动”状态,用户可以在这个状态下做一些启动前的检查或操作。
2.4 running
- 当容器内的主进程启动后,容器会进入
running
状态。 - 容器的
running
状态意味着主进程正在执行,容器处于活跃状态。 - 容器的资源限制(如 CPU、内存)开始生效,用户可以与容器内部的进程交互。
2.5 paused
- 通过
runc pause
命令可以将容器置于paused
状态。 - 容器内部的所有进程会被挂起,不再消耗 CPU 时间,所有的 IO 操作也会暂停。
- 这通常用于临时暂停容器以释放 CPU 资源,稍后可以通过
runc resume
恢复容器的运行。
2.6 stopped
- 当容器内的主进程退出或被杀死后,容器进入
stopped
状态。 - 容器内已经没有任何进程在运行,所有的资源(
cgroup
、命名空间)仍然保留,但不会再消耗系统资源。 - 容器可以在
stopped
状态下被重新启动(如果使用的是某些运行时),也可以被删除。
3 配置容器环境
3.1 制作根文件系统
在 runc 中,根文件系统是指容器运行时的文件系统环境,它是容器内部进程的根目录。容器的根文件系统与主机系统的根文件系统是隔离的,可以为容器提供一个独立的文件系统视图,从而确保容器内部进程的独立性和安全性。
- 从 busybox官网 下载文件系统,将文件系统的内容解压到
rootfs
目录下。 - 使用 Docker 下载文件系统,将文件系统的内容放到
rootfs
目录下。
docker pull busybox
mkdir bundle && cd bundle
mkdir rootfs
docker export $(docker create busybox) | tar -C rootfs -xvf -
3.2 编写容器配置
使用下面命令创建一个 config.json
文件:
runc spec
展示文件内容
{
// OCI 规范版本,用于指定该配置文件的格式和内容遵循的标准。
"ociVersion": "1.2.0",
// 容器中要运行的进程的配置。
"process": {
// 是否为进程分配伪终端(TTY),用于交互式操作。
"terminal": true,
// 设置容器中进程的用户 ID(uid)和组 ID(gid)。
"user": {
"uid": 0, // 容器内进程将以 root 用户(uid 0)身份运行。
"gid": 0 // 容器内进程将以 root 组(gid 0)身份运行。
},
// 容器启动时运行的命令及其参数列表。
"args": [
"sh" // 容器启动后执行 `sh`,表示进入一个 shell 环境。
],
// 容器内进程的环境变量配置。
"env": [
// 设置 PATH 环境变量,指定可执行文件查找路径。
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
// 设置终端类型为 xterm。
"TERM=xterm"
],
// 容器启动时进程的工作目录,这里设置为根目录。
"cwd": "/",
// 进程的权限配置,定义容器内进程的能力(Capabilities)。
"capabilities": {
// 设置进程在 Bounding 集合中的能力。
"bounding": [
"CAP_AUDIT_WRITE", // 审计日志写入能力。
"CAP_KILL", // 发送信号杀死进程的能力。
"CAP_NET_BIND_SERVICE" // 绑定网络端口的能力。
],
// 设置进程在 Effective 集合中的能力。
"effective": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
// 设置进程在 Permitted 集合中的能力。
"permitted": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
// 设置进程在 Ambient 集合中的能力。
"ambient": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
]
},
// 设置进程的资源限制。
"rlimits": [
{
// 限制进程能够打开的文件描述符数量。
"type": "RLIMIT_NOFILE",
"hard": 1024, // 设置硬限制,即最大文件描述符数为 1024。
"soft": 1024 // 设置软限制,即文件描述符数警告值为 1024。
}
],
// 防止执行 execve 系统调用时提升进程权限。
"noNewPrivileges": true
},
// 容器的根文件系统配置。
"root": {
// 设置根文件系统的路径,即容器的根目录(默认为 "rootfs" 目录)。
"path": "rootfs",
// 将根文件系统以只读模式挂载,提升安全性。
"readonly": true
},
// 容器启动时的主机名配置。
"hostname": "runc",
// 挂载点配置,指定容器启动时的文件系统挂载点。
"mounts": [
{
"destination": "/proc", // 挂载 /proc 文件系统到容器内 /proc 目录。
"type": "proc", // 挂载类型为 proc。
"source": "proc" // 来源为 proc。
},
{
"destination": "/dev", // 挂载 /dev 目录,用于设备文件。
"type": "tmpfs", // 挂载类型为 tmpfs(内存文件系统)。
"source": "tmpfs",
"options": [
"nosuid", // 禁止 set-user-ID 和 set-group-ID 位。
"strictatime", // 严格时间戳记录模式。
"mode=755", // 目录权限设置为 755(所有者可读写执行)。
"size=65536k" // 设置 tmpfs 的大小为 64M。
]
},
{
"destination": "/dev/pts", // 挂载伪终端文件系统到 /dev/pts。
"type": "devpts", // 挂载类型为 devpts。
"source": "devpts",
"options": [
"nosuid", // 禁止 set-user-ID 和 set-group-ID 位。
"noexec", // 禁止执行权限。
"newinstance", // 创建新的伪终端实例。
"ptmxmode=0666", // 设置 /dev/ptmx 文件的权限为 0666(所有用户可读写)。
"mode=0620", // 设置伪终端设备权限为 0620(所有者可读写,组可读写)。
"gid=5" // 设置设备的组 ID 为 5。
]
},
{
"destination": "/dev/shm", // 挂载共享内存到 /dev/shm。
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev", // 禁止设备文件。
"mode=1777", // 设置目录权限为 1777(所有用户可读写)。
"size=65536k" // 设置大小为 64M。
]
},
{
"destination": "/dev/mqueue", // 挂载消息队列文件系统到 /dev/mqueue。
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev" // 禁止设备文件。
]
},
{
"destination": "/sys", // 挂载 sysfs 到 /sys,提供系统信息。
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro" // 设置挂载为只读。
]
},
{
"destination": "/sys/fs/cgroup", // 挂载 cgroup 文件系统到 /sys/fs/cgroup。
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro" // 设置挂载为只读。
]
}
],
// Linux 特有的配置选项。
"linux": {
// 资源限制配置,如设备访问控制。
"resources": {
"devices": [
{
"allow": false, // 禁止访问所有设备。
"access": "rwm" // 禁止读取、写入和访问设备。
}
]
},
// 命名空间配置,用于隔离容器与宿主机之间的资源。
"namespaces": [
{ "type": "pid" }, // 进程 ID 命名空间。
{ "type": "network" }, // 网络命名空间。
{ "type": "ipc" }, // 进程间通信命名空间。
{ "type": "uts" }, // UTS(主机名和域名)命名空间。
{ "type": "mount" }, // 挂载命名空间。
{ "type": "cgroup" } // cgroup 控制组命名空间。
],
// 屏蔽的系统路径,防止容器内进程读取这些路径。
"maskedPaths": [
"/proc/acpi",
"/proc/asound",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/sys/firmware",
"/proc/scsi"
],
// 设置为只读的系统路径。
"readonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
}
3.3 进入容器
可以通过 run
命令创建并进入这个容器。
runc run container
也可以先创建一个容器后再进入这个容器,先创建一个 sock
文件用于通信,然后重新开一个终端再创建容器。 创建 sock
文件是通过 tests/cmd/recvtty
目录下的 recvtty.go
创建。
recvtty socket.sock
runc create --console-socket socket.sock container
runc start container
runc exec -t container /bin/sh
如果是在 Docker 容器里面进行 runc 源码的查看和调试,需要执行下面脚本,目的是:检测系统支持 cgroup v2 时启用 cgroup v2 的嵌套控制,这个只有在 Docker 容器里面需要执行,在 Linux 的主机系统上时不需要的。
展示文件内容
#!/bin/bash
set -eu -o pipefail
if [ -f "/sys/fs/cgroup/cgroup.controllers" ]; then
echo >&2 "Enabling cgroup v2 nesting"
mkdir -p /sys/fs/cgroup/init
xargs -rn1 </sys/fs/cgroup/cgroup.procs >/sys/fs/cgroup/init/cgroup.procs || :
sed -e 's/ / +/g' -e 's/^/+/' </sys/fs/cgroup/cgroup.controllers \
>/sys/fs/cgroup/cgroup.subtree_control
fi
exec "$@"
4 项目结构
runc 的代码结构非常清晰,下面介绍大致结构:
contrib
:包含一些附加工具、脚本或示例。internal
:这些模块只在 runc 的其他部分中使用。libcontainer
:核心库,提供容器相关的功能和操作,包括容器的创建、管理和销毁。types
:定义各种数据结构和类型,用于描述容器的状态、配置和其他相关信息。checkpoint.go
:处理容器检查点和恢复的逻辑,允许在运行时保存容器的状态,并在需要时恢复。create.go
:处理容器创建的逻辑,包括根据配置文件创建新的容器实例。delete.go
:负责删除容器的实现,确保容器资源被正确释放。events.go
:处理事件系统,允许 runc 发送和接收事件(例如容器状态变化)。exec.go
:管理在容器中执行命令的功能,允许用户在运行的容器内执行指定的程序。features.go
:管理 runc 支持的功能特性,涉及容器的功能开启和配置。init.go
:容器初始化相关的代码,包括设置容器的基本环境和运行状态。kill.go
:处理向容器发送信号(例如终止、挂起等)的逻辑。list.go
:提供列出当前所有运行中的容器的功能。main.go
:runc 的入口点,包含主函数和主要的命令行解析逻辑。notify_socket.go
:用于处理与容器通信的通知套接字,支持与容器的控制通信。pause.go
:实现容器暂停和恢复的逻辑。ps.go
:管理进程状态,会处理容器内运行的进程信息。restore.go
:实现从检查点恢复容器的功能,与checkpoint.go
配合使用。rlimit_linux.go
:处理 Linux 下的资源限制(rlimit
),确保容器的资源使用不超过配置限制。rootless_linux.go
:处理无根用户模式下的容器运行,支持在没有 root 权限的情况下运行容器。run.go
:处理容器启动和运行的逻辑。signals.go
:管理信号处理,例如响应用户的终止信号。spec.go
:定义容器的规范(spec),描述容器的配置和元数据。start.go
:处理容器启动的逻辑。state.go
:管理容器的状态信息,包括容器的当前运行状态。tty.go
:处理终端(tty)的相关逻辑,为容器提供交互式终端支持。update.go
: 允许用户更新容器的配置或状态。utils.go
:包含一些通用的工具函数,供其他文件调用。utils_linux.go
:与 Linux 特定的功能相关的工具函数。
5 基本使用
5.1 create
runc 的 create
命令用于创建一个容器,但是不启动它。主要用于初始化容器的资源分配和配置(如根文件系统、挂载点、命令空间、Cgroups 等),之后可以使用 start
、exec
来启动容器。
命令格式:
runc create [command options] <container-id>
可选参数如下:
--bundle value, -b value
:指定bundle
的目录,如果不指定,默认为当前目录。--console-socket value
:指定一个AF_UNIX
套接字通信,用于接受指向控制台伪终端的文件描述符。--pidfd-socket value
:指定一个AF_UNIX
套接字路径,用于接收指向init
进程的文件描述符。--pid-file value
:指定一个文件路径,将进程 ID 写入该文件。--no-pivot
:不使用pivot root
机制将进程限制在rootfs
中,通常在rootfs
位于ramdisk
时使用。--no-new-keyring
:不为容器创建新的 session keyring,这将导致容器继承调用进程的 session key。--preserve-fds value
:向容器传递额外的文件描述符(默认传递 0 个),格式为stdio + $LISTEN_FDS + N
。
使用样例:
- 创建一个
sock
文件,在 runc 中sock
文件用于与外部程序通信。
recvtty socket.sock
- 创建一个容器。
runc create --console-socket socket.sock container
5.2 start
runc 的 start
命令用于启动一个已经创建的容器,它的作用是将 created
状态的容器切换到 running
状态,从而开始执行容器内的进程。
命令格式:
runc start <container-id>
使用样例:
runc start container
5.3 exec
runc 的 exec
命令用于在已经运行的容器内部执行新的进程。
命令格式:
runc exec [command options] <container-id> <command> [command options]
或者:
runc exec -p process.json <container-id>
可选参数如下:
--console-socket value
:指定一个AF_UNIX
套接字的路径,用于接收指向控制台伪终端主端的文件描述符。--pidfd-socket value
:指定一个AF_UNIX
套接字的路径,用于接收指向exec
进程的文件描述符。--cwd value
:在容器中指定新的进程的当前工作目录。--env, -e value
:为新进程设置环境变量。--tty, -t
:为新进程分配一个伪终端(pseudo-TTY
)。--user, -u value
:为新进程设置用户 ID 和组 ID 格式(格式为<uid>[:<gid>]
)。--additional-gids, -g value
:为新进程设置附加组 ID。--process, -p value
:指定一个process.json
文件路径,用于定义要执行的进程及其配置。--detach, -d
:将新进程从当前 runc 命令中分离,独立运行。--pid-file value
:指定文件路径,将进程 ID 写入该文件。--process-label value
:设置新进程的asm
标签(通常与 SELinux 相关)。--apparmor value
:为新进程设置 AppArmor 配置文件。--no-new-privs
:启用no_new_privs
选项,禁止新进程获取更高的权限。--cap, -c value
:为新进程增加能力。--preserve-fds value
:向容器传递额外的文件描述符(默认传递 0 个),格式为stdio + $LISTEN_FDS + N
。--cgroup value
:指定新进程运行在哪个(已存在的)子cgroup
中。格式为[<controller>:]<cgroup>
。--ignore-pause
:允许在暂停的容器中执行exec
。
使用样例:
runc exec -t container /bin/sh
5.4 run
runc 的 run
命令用于创建和运行一个容器。
命令格式:
runc run [command options] <container-id>
可选参数如下:
--bundle value, -b value
:指定bundle
的目录,如果不指定,默认为当前目录。--console-socket value
:指定一个AF_UNIX
套接字的路径,用于接收指向控制台伪终端主端的文件描述符。--pidfd-socket value
:指定一个AF_UNIX
套接字路径,用于接收指向init
进程的文件描述符。--pid-file value
:指定一个文件路径,将进程 ID 写入该文件。--detach, -d
:将新进程从当前 runc 命令中分离,独立运行。--keep
:容器退出后不删除容器实例(使用runc run
默认情况下容器退出后会自动删除)。--no-subreaper
:禁用 subreaper,subreaper 是 Linux 的一种机制,用于清理孤立进程(即那些没有父进程的进程)。--no-pivot
:不使用pivot root
机制将进程限制在rootfs
中,通常在rootfs
位于ramdisk
时使用。
使用样例:
runc run container
5.5 pause
runc 的 pause
命令用于暂停容器内的所有进程,将其置于 paused
状态,暂停后的容器不会继续执行任何操作,直到恢复或终止。
命令格式:
runc pause <container-id>
使用样例:
runc pause container
5.6 kill
runc 的 kill
命令用于向指定容器的 init
进程发送信号,默认信号是 SIGTERM
。该命令可以用于终止容器中的进程,控制容器的状态或进行调试。
命令格式:
runc kill <container-id> [signal]
使用样例:
runc kill container SIGKILL
常用信号及其作用
信号 | 数值 | 描述 | 常见用途 |
---|---|---|---|
SIGHUP | 1 | 终端挂起(挂起或断开连接) | 通常用于通知进程重新读取配置文件 |
SIGINT | 2 | 终端中断(通常由 Ctrl+C 发出) | 中断正在运行的程序(例如停止某个程序的执行) |
SIGQUIT | 3 | 终端退出(通常由 Ctrl+\ 发出) | 生成核心转储文件(core dump)并退出 |
SIGKILL | 9 | 强制终止进程 | 无法被捕获和忽略,立即终止进程 |
SIGUSR1 | 10 | 用户定义信号 1 | 用户自定义,用于进程间传递特定信号 |
SIGUSR2 | 12 | 用户定义信号 2 | 用户自定义,用于进程间传递特定信号 |
SIGTERM | 15 | 请求进程正常终止 | 默认信号,通常用于优雅地终止进程 |
SIGCONT | 18 | 恢复暂停的进程 | 恢复被 SIGSTOP 暂停的进程 |
SIGSTOP | 19 | 暂停进程(无法被捕获和忽略) | 强制暂停进程,类似于 Ctrl+Z |
5.7 delete
runc 的 delete
命令用于删除容器占用的资源,通常用于已经停止或分离的容器实例,删除操作不会直接停止或影响正在运行的容器,而是清理容器在停止后遗留的所有资源,比如挂载点、进程管理信息等。
命令格式:
runc delete [command options] <container-id>
参数:
--force, -f
:如果容器仍在运行,使用该选项可以强制删除容器。这会向容器的init
进程发送SIGKILL
信号,强制终止所有进程,然后清理资源。
使用样例:
runc delete -f container
5.8 list
runs 的 list
命令用于列出当前由 runc 启动的所有容器实例,并显示它们的状态信息。可以使用该命令查看哪些容器正在运行、已经停止或处于其他状态。
命令格式:
runc list [command options]
参数:
--format, -f <value>
:指定输出格式,可选 table 或 json 格式(默认值为 table)。--quiet, -q
:只显示容器的 ID,不显示其他信息(如状态、PID、创建时间等)。
使用样例:
runc list -f json -q
5.9 ps
runc 的 ps
命令用于查看指定容器中正在运行的所有进程信息,类似于 Linux 系统中的 ps
命令,但它专门用于查看容器内部的进程状态。它可以帮助用户了解某个容器内的进程是否正常运行、占用的资源情况以及进程状态(如运行中、睡眠中、僵尸进程等)。
命令格式:
runc ps [command options] <container-id> [ps options]
参数:
--format, -f <value>
:指定输出格式,可选 table 或 json 格式(默认值为 table)。
使用样例:
runc ps container
5.10 state
runc 的 state
命令用于查看指定容器的当前状态信息。它可以帮助用户了解容器的运行状态、进程信息和配置信息。
命令格式:
runc state <container-id>
使用样例:
runc state container
输出内容如下:
{
"ociVersion": "1.2.0",
"id": "container",
"pid": 21381,
"status": "running",
"bundle": "/root/bundle",
"rootfs": "/root/bundle/rootfs",
"created": "2024-10-04T15:56:26.847867629Z",
"owner": ""
}
ociVersion
:OCI 的版本。id
:容器的唯一标识符。在创建容器时,用户会指定一个 ID,该 ID 用于唯一标识主机上的这个容器实例。pid
:容器内部init
进程的 PID(进程 ID)。该 PID 表示在宿主机上该容器主进程的进程号。status
:当前容器的状态。bundle
:容器绑定的目录路径。该目录通常包含容器的config.json
文件和 rootfs 根文件系统。rootfs
: 容器的根文件系统路径。runc 运行容器时会将该路径视为容器的根目录(/
),并隔离于宿主机的文件系统。created
:容器创建的时间戳,格式为 ISO 8601 标准时间格式(UTC 时区)。owner
:容器的所有者字段。
5.11 resume
runc 的 resume
命令用于恢复先前被暂停(paused
)的容器中的所有进程。主要功能是恢复一个已经被暂停的容器。它会让容器中的所有进程从暂停状态继续执行,而不是重新启动或重建容器。当一个容器被 runc pause
暂停后,所有进程都处于“冻结”状态(通常使用 SIGSTOP
信号),无法处理外部事件或请求。使用 runc resume
命令,可以让这些进程恢复执行(类似于 SIGCONT
信号的作用),继续处理之前未完成的任务。
命令格式:
runc resume <container-id>
使用样例:
runc resume container
5.12 checkpoint
runc 的 checkpoint
命令用于将正在运行的容器的当前状态保存为检查点(checkpoint),以便之后可以使用 runc restore 命令恢复到该状态。这个命令主要用于容器迁移、调试回滚和长时间任务中断后的恢复等场景。
命令格式:
runc checkpoint [command options] <container-id>
参数:
--image-path value
:指定保存容器checkpoint
文件的路径。--work-path value
:指定保存工作文件和日志的路径。--parent-path value
:指定之前的 CRIUcheckpoint
文件路径,在pre-dump
模式下使用。--leave-running
:检查点后保持容器继续运行。--tcp-established
:允许checkpoint
操作保留已建立的 TCP 连接。--ext-unix-sk
:允许checkpoint
操作保留与外部 Unix 套接字的连接。--shell-job
:允许checkpoint
操作保存 shell 作业(shell jobs)。--lazy-pages
:使用 userfaultfd 机制进行懒加载(lazily restore)内存页。--status-fd value
:指定一个文件描述符(FD),当 lazy-pages 模式准备好时,CRIU 会向该 FD 写入一个\0
字符。--page-server value
:指定一个页服务器(page server)的ADDRESS:PORT
地址,用于传输checkpoint
的内存页。--file-locks
:处理文件锁。--pre-dump
:只保存容器的内存信息,而不停止容器。--manage-cgroups-mode value
:指定cgroup
的管理模式:soft
(默认):尽量保存cgroup
的状态,但不强制。full
:完全保存cgroup
的状态。strict
:严格保存cgroup
的状态,如果无法保存则报错。ignore
:忽略cgroup
状态,不进行保存。
--empty-ns value
:创建一个命名空间(namespace
),但不保存该命名空间的属性。--auto-dedup
:启用自动内存去重。
使用样例:
runc checkpoint --leave-running --image-path /runc/image container
5.13 restore
runc 的 restore
命令用于从之前的检查点(checkpoint
)恢复容器的状态。该命令通常用于容器的迁移或暂停后恢复场景。
命令格式:
runc restore [command options] <container-id>
参数:
--console-socket value
:指定一个AF_UNIX
套接字的路径,用于接收指向控制台伪终端主端的文件描述符。--image-path value
:指定存放容器的 ·checkpoint·(检查点)文件的路径。--work-path value
:指定用于存放工作文件和日志的路径。--tcp-established
:允许恢复时保持已建立的 TCP 连接。--ext-unix-sk
:允许恢复外部的 Unix 套接字。--shell-job
:允许恢复 shell 作业(shell jobs)。--file-locks
:处理文件锁。--manage-cgroups-mode value
:指定 cgroup 的管理模式,有以下几种模式:soft
(默认):尽量恢复cgroup
的状态,但不强制。full
:完全恢复cgroup
的状态。strict
:严格恢复cgroup
的状态,如果无法恢复则报错。ignore
:忽略cgroup
状态,不进行恢复。
--bundle value, -b value
:指定容器的bundle
目录路径,该目录包含了config.json
和rootfs
(根文件系统)。--detach, -d
:以分离模式恢复容器。--pid-file value
:指定一个文件路径,用于保存恢复后的容器的进程 ID(PID)。--no-subreaper
:禁用 subreaper,subreaper 是 Linux 的一种机制,用于清理孤立进程(即那些没有父进程的进程)。--no-pivot
:不使用pivot root
机制将进程限制在rootfs
中,通常在rootfs
位于ramdisk
时使用。--empty-ns value
:创建一个命名空间(namespace
),但不恢复该命名空间的属性。--auto-dedup
:启用自动内存去重。--lazy-pages
:使用 userfaultfd 机制,懒加载(lazily restore)内存页。--lsm-profile value
:指定一个 Linux 安全模块(LSM)的配置文件用于恢复,格式为TYPE:NAME
。--lsm-mount-context value
:指定 LSM 挂载上下文(mount context)用于恢复。
6 总结
本篇文章首先介绍了 OCI 以及 runc 是什么,OCI 是一个容器运行时规范,runc 是一个实现了 OCI 标准的 CLI 工具,用于创建和管理容器。然后还介绍了 runc 的容器的一些状态,以及它们如何相互转换。最后介绍了 runc 的基本命令的使用。在下一篇文章中将会解读 create
的源码实现。