runc源码解读(一)——runc create
runc 是一个用于运行和管理容器的命令行工具,是 Open Container Initiative (OCI) 运行时规范的参考实现。
runc create是
runc的一个子命令,用于创建容器实例,但并不立即启动容器。以下是对
runc create` 的详细讲解,包括其作用、功能、使用场景以及相关细节。
1. runc create
的核心功能
runc create
的主要功能是根据指定的容器配置文件(通常是 config.json
)创建一个容器实例,并将其置于 “created” 状态。这意味着容器已经初始化,但尚未开始运行。以下是其核心作用:
- 初始化容器环境:根据 OCI 运行时规范中的
config.json
文件,设置容器的运行时环境,包括命名空间(namespace)、cgroup、根文件系统、挂载点、用户权限等。 - 分配资源:为容器分配必要的系统资源(如 CPU、内存、PID 等),但不执行容器内的主进程。
- 创建容器实例:生成一个容器实例,分配唯一的容器 ID,并将其状态记录在运行时环境中。
- 准备运行:将容器置于可运行状态,等待后续的
runc start
命令来启动容器。
简单来说,runc create
是容器生命周期中的第一步,它完成了容器的初始化工作,但不会实际运行容器内的进程。
2. runc create
的工作流程
runc create
的执行过程可以分解为以下几个步骤:
-
读取配置文件:
runc create
会读取当前工作目录下的config.json
文件(或通过--bundle
参数指定的目录中的配置文件)。config.json
包含容器的配置信息,例如:- 根文件系统路径(
rootfs
) - 命名空间设置(
pid
,network
,mount
,uts
等) - 资源限制(通过 cgroups 设置 CPU、内存等)
- 环境变量、命令行参数、挂载点等
- 根文件系统路径(
-
验证配置:
- 检查
config.json
是否符合 OCI 运行时规范。 - 确保必要的文件系统、镜像和其他依赖项存在。
- 检查
-
创建容器实例:
- 为容器生成一个唯一的容器 ID(通常由用户通过
--id
参数指定)。 - 初始化容器的运行时环境,包括:
- 设置 Linux 命名空间(隔离进程、网络、文件系统等)。
- 配置 cgroups(限制资源使用)。
- 设置用户和权限(例如运行容器的 UID/GID)。
- 挂载文件系统(包括根文件系统和其他挂载点)。
- 为容器生成一个唯一的容器 ID(通常由用户通过
-
记录状态:
- 将容器的状态保存到运行时状态文件中(通常位于
runc
的状态目录,如/run/runc/<container-id>/state.json
)。 - 容器进入 “created” 状态,等待后续操作(如
runc start
)。
- 将容器的状态保存到运行时状态文件中(通常位于
-
不执行主进程:
runc create
不会运行容器内的主进程(config.json
中指定的process
部分)。主进程的执行需要通过runc start
触发。
3. runc create
的典型使用场景
runc create
通常用于以下场景:
-
容器编排工具的底层实现:
- 像 Docker、Podman 或 Kubernetes 这样的高级容器管理工具通常在底层调用
runc
来管理容器生命周期。 runc create
被用来初始化容器,准备好环境后由编排工具决定何时启动。
- 像 Docker、Podman 或 Kubernetes 这样的高级容器管理工具通常在底层调用
-
调试和开发:
- 开发人员可能需要手动创建容器以检查配置是否正确,或者在启动前调整容器环境。
- 例如,可以在
runc create
后检查容器状态、挂载点或 cgroups 配置。
-
分离创建和启动:
- 在某些场景下,容器创建和启动需要分开处理。例如,某些系统可能需要先分配资源并检查状态,然后再决定是否启动容器。
runc create
提供了这种灵活性,允许用户在启动前进行干预。
-
低级容器管理:
- 对于需要直接与 OCI 运行时交互的场景,
runc create
提供了底层的容器创建能力,适合高级用户或需要定制化管理的场景。
- 对于需要直接与 OCI 运行时交互的场景,
4. runc create
的命令格式和参数
runc create
的基本命令格式如下:
runc create [options] <container-id>
常用选项
--bundle <path>
:指定包含config.json
的目录路径(默认为当前目录)。--pid-file <path>
:指定一个文件路径,用于存储创建的容器的 PID(进程 ID)。在容器创建后,PID 会被写入该文件。--no-pivot
:禁用 pivot_root(某些场景下用于调试,防止更改根文件系统)。--no-new-keyring
:禁用创建新的密钥环(keyring),用于某些特定的权限管理场景。--console-socket <path>
:指定用于传递控制台的 socket 文件路径(通常用于交互式终端)。
示例
假设有一个包含 config.json
和 rootfs
的目录 /mycontainer
,可以通过以下命令创建容器:
runc create --bundle /mycontainer my-container-id
my-container-id
是用户指定的容器 ID。/mycontainer
包含config.json
和容器根文件系统。
执行后,容器会被创建并进入 “created” 状态。可以通过以下命令检查状态:
runc state my-container-id
输出示例:
{"id": "my-container-id","status": "created",...
}
随后,可以使用 runc start my-container-id
启动容器。
5. runc create
的注意事项
-
配置文件正确性:
config.json
必须符合 OCI 运行时规范,否则runc create
会失败。- 可以使用
runc spec
生成一个默认的config.json
文件,然后根据需要修改。
-
权限要求:
runc create
通常需要 root 权限,因为它涉及设置命名空间、cgroups 和挂载点等系统级操作。- 如果以非 root 用户运行,可能需要配置无特权容器(例如通过 user namespaces)。
-
状态管理:
- 创建的容器状态保存在
/run/runc/<container-id>
目录下。如果容器 ID 冲突或状态文件损坏,可能导致创建失败。
- 创建的容器状态保存在
-
与
runc start
的区别:runc create
只初始化容器,不运行主进程。runc start
会启动容器内的主进程,使容器进入 “running” 状态。
-
清理:
- 如果创建的容器不再需要,可以使用
runc delete <container-id>
删除容器实例,释放相关资源。
- 如果创建的容器不再需要,可以使用
6. runc create
的实际应用示例
示例 1:创建并检查容器
假设你已经准备好一个容器目录 /mycontainer
,其中包含 rootfs
和 config.json
(可以通过 runc spec
生成)。
-
创建容器:
runc create --bundle /mycontainer my-container
-
检查容器状态:
runc state my-container
-
启动容器:
runc start my-container
示例 2:与 Docker 的结合
Docker 在底层使用 runc
来管理容器。例如,当你运行 docker run
时,Docker 会:
- 调用
runc create
创建容器实例。 - 调用
runc start
启动容器。 - 管理容器的生命周期(暂停、停止、删除等)。
你可以通过以下方式模拟 Docker 的行为:
- 使用
docker export
导出一个容器文件系统。 - 创建
config.json
(通过runc spec
或手动配置)。 - 使用
runc create
和runc start
手动运行容器。
7. 常见问题与排查
-
错误:
config.json
不存在或格式错误:- 确保
--bundle
参数指定的目录包含有效的config.json
。 - 使用
runc spec
生成模板文件并检查配置。
- 确保
-
错误:权限不足:
- 确保以 root 权限运行
runc create
,或配置无特权容器。
- 确保以 root 权限运行
-
错误:容器 ID 已存在:
- 使用
runc list
查看现有容器,删除冲突的容器(runc delete <id>
)。
- 使用
-
容器创建后无法启动:
- 检查
config.json
中的配置(如根文件系统路径是否正确)。 - 使用
runc events <container-id>
查看容器事件日志。
- 检查
8. 总结
runc create
是 runc
提供的一个核心命令,用于初始化容器实例并将其置于 “created” 状态。它是容器生命周期管理的起点,负责设置容器运行所需的各种资源和环境,但不执行容器内的主进程。通过 runc create
,用户可以灵活地控制容器创建过程,适用于调试、开发或与高级容器管理工具的集成。
关键点
- 功能:创建容器实例,初始化环境,进入 “created” 状态。
- 输入:需要
config.json
和容器根文件系统。 - 输出:一个待启动的容器实例,状态保存在运行时目录。
- 使用场景:容器编排、调试、自定义容器管理。
- 后续步骤:通常结合
runc start
、runc delete
等命令使用。