opencontainers/runc
GitHub: opencontainers/runc
runc 是符合 OCI 规范的容器运行时命令行工具,提供容器生命周期的底层管理能力。
Stars: 13119 | Forks: 2270
# runc
[](https://goreportcard.com/report/github.com/opencontainers/runc)
[](https://pkg.go.dev/github.com/opencontainers/runc)
[](https://bestpractices.coreinfrastructure.org/projects/588)
[](https://github.com/opencontainers/runc/actions?query=workflow%3Avalidate)
[](https://github.com/opencontainers/runc/actions?query=workflow%3Aci)
[](https://cirrus-ci.com/github/opencontainers/runc)
## 简介
`runc` 是一个 CLI 工具,用于根据 OCI 规范在 Linux 上生成和运行容器。
## 发布版本
你可以在 [release](https://github.com/opencontainers/runc/releases) 页面找到 `runc` 的官方发布版本。
所有发布版本均由 [本仓库根目录下的 `runc.keyring` 文件](runc.keyring) 中列出的密钥之一进行签名。
## 安全
报告流程和披露沟通已在 [此处](https://github.com/opencontainers/org/blob/master/SECURITY.md) 概述。
### 安全审计
第三方安全审计由 Cure53 执行,你可以在 [此处](https://github.com/opencontainers/runc/blob/master/docs/Security-Audit.pdf) 查看完整报告。
## 构建
`runc` 仅支持 Linux。有关最低要求的 Go 版本,请参阅 [`go.mod`](./go.mod) 的头部信息。
### 前置条件
#### 工具与库
除了 Go 之外,构建 `runc` 还需要在你的系统上安装多个工具和库。
在 Ubuntu/Debian 上,你可以使用以下命令安装所需的依赖项:
```
apt update && apt install -y make gcc linux-libc-dev libseccomp-dev pkg-config git
```
在 CentOS/Fedora 上,你可以使用以下命令安装所需的依赖项:
```
yum install -y make gcc kernel-headers libseccomp-devel pkg-config git
```
在 Alpine Linux 上,你可以使用以下命令安装所需的依赖项:
```
apk --update add bash make gcc libseccomp-dev musl-dev linux-headers git
```
以下依赖项是可选的:
* `libseccomp` - 仅在你启用 seccomp 支持时需要;要禁用,请参阅 [Build Tags](#build-tags)
### 构建
```
# 在 GOPATH/src 中创建 'github.com/opencontainers'
cd github.com/opencontainers
git clone https://github.com/opencontainers/runc
cd runc
make
sudo make install
```
你也可以使用 `go get` 安装到你的 `GOPATH` 中,假设你已经在 `src` 下创建了 `github.com` 父文件夹:
```
go get github.com/opencontainers/runc
cd $GOPATH/src/github.com/opencontainers/runc
make
sudo make install
```
`runc` 将被安装到你系统上的 `/usr/local/sbin/runc`。
#### 版本字符串自定义
你可以通过运行 `runc --version` 来查看 runc 版本。在构建时,你可以使用 `EXTRA_VERSION` make 变量将自定义字符串附加到版本后面,例如:
```
make EXTRA_VERSION="+build-1"
```
请注意包含一些分隔符以提高可读性。
#### Build Tags
`runc` 支持可选的 build tags 以编译各种特性的支持,
其中一些默认已启用(请参阅顶层 `Makefile` 中的 `BUILDTAGS`)。
要更改默认的 build tags,请为 make 设置 `BUILDTAGS` 变量,
例如要禁用 seccomp:
```
make BUILDTAGS=""
```
要向默认集合添加更多 build tags,请使用 `EXTRA_BUILDTAGS`
make 变量,例如要禁用 checkpoint/restore:
```
make EXTRA_BUILDTAGS="runc_nocriu"
```
| Build Tag | 功能 | 默认启用 | 依赖项 |
|---------------|---------------------------------------|--------------------|---------------------|
| `seccomp` | 使用 `libseccomp` 进行 Syscall 过滤。 | yes | `libseccomp` |
| `libpathrs` | 使用 [`libpathrs`][] 进行路径安全处理。 | yes | [`libpathrs`][] |
| `runc_nocriu` | **禁用** runc checkpoint/restore。 | no | `criu` |
以下 build tags 曾被使用,但现已弃用:
- **runc_nodmz** (自 runc v1.2.1 起 runc dmz 二进制文件已被移除)
- **nokmem** (自 runc v1.0.0-rc94 起内核内存设置被忽略)
- **apparmor** (自 runc v1.0.0-rc93 起该功能始终启用)
- **selinux** (自 runc v1.0.0-rc93 起该功能始终启用)
### 运行测试套件
`runc` 目前支持通过 Docker 运行其测试套件。
要运行该套件,只需输入 `make test`。
```
make test
```
还有额外的 make 目标用于在容器外运行测试,但不建议这样做,因为测试的编写预期它们可以在任何地方进行写入和删除。
你可以通过设置 `TESTFLAGS` 变量来运行特定的测试用例。
```
# make test TESTFLAGS="-run=SomeTestFunction"
```
你可以通过设置 `TESTPATH` 变量来运行特定的集成测试。
```
# make test TESTPATH="/checkpoint.bats"
```
你可以通过设置 `ROOTLESS_TESTPATH` 变量来运行特定的 rootless 集成测试。
```
# make test ROOTLESS_TESTPATH="/checkpoint.bats"
```
你可以通过设置 `CONTAINER_ENGINE_BUILD_FLAGS` 和 `CONTAINER_ENGINE_RUN_FLAGS` 变量,使用容器引擎的标志来运行测试。
```
# make test CONTAINER_ENGINE_BUILD_FLAGS="--build-arg http_proxy=http://yourproxy/" CONTAINER_ENGINE_RUN_FLAGS="-e http_proxy=http://yourproxy/"
```
### Go 依赖管理
`runc` 使用 [Go Modules](https://github.com/golang/go/wiki/Modules) 进行依赖管理。
请参阅 [Go Modules](https://github.com/golang/go/wiki/Modules) 了解如何添加或更新
新依赖。
```
# 更新 vendored 依赖
make vendor
# 验证所有依赖
make verify-dependencies
```
## 使用 runc
请注意,runc 是一个底层工具,并非为终端用户设计。它主要由其他更高层的容器软件使用。
因此,除非存在某些阻止使用 Docker 或 Podman 等工具的特定用例,否则不建议直接使用 runc。
如果你仍想使用 runc,请按以下步骤操作。
### 创建 OCI Bundle
为了使用 runc,你的容器必须采用 OCI bundle 的格式。
如果你安装了 Docker,可以使用其 `export` 方法从现有的 Docker 容器中获取根文件系统。
```
# 创建顶层 bundle 目录
mkdir /mycontainer
cd /mycontainer
# 创建 rootfs 目录
mkdir rootfs
# 通过 Docker 将 busybox 导入到 rootfs 目录
docker export $(docker create busybox) | tar -C rootfs -xvf -
```
在填充根文件系统后,只需在你的 bundle 内生成一个 `config.json` 文件格式的规范。
`runc` 提供了一个 `spec` 命令来生成基础模板规范,然后你可以对其进行编辑。
要查找规范中各字段的功能和文档,请参阅 [specs](https://github.com/opencontainers/runtime-spec) 仓库。
```
runc spec
```
### 运行容器
假设你已经完成了上一步的 OCI bundle,你可以通过两种不同的方式执行容器。
第一种方式是使用便捷命令 `run`,它将处理容器的创建、启动以及在退出后的删除。
```
# 以 root 身份运行
cd /mycontainer
runc run mycontainerid
```
如果你使用了未修改的 `runc spec` 模板,这应该会在容器内为你提供一个 `sh` 会话。
启动容器的第二种方式是使用 specs 生命周期操作。
这赋予你更多关于容器创建和运行时管理的权力。
这也会在后台启动容器,因此你必须编辑
`config.json` 以删除以下简单示例的 `terminal` 设置
(有关更多详细信息,请参阅 [runc terminal handling](docs/terminals.md))。
你的 `config.json` 中的 process 字段应如下所示,包含 `"terminal": false` 和 `"args": ["sleep", "5"]`。
```
"process": {
"terminal": false,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sleep", "5"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": {
"bounding": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"effective": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"inheritable": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"permitted": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"ambient": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
]
},
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
],
"noNewPrivileges": true
},
```
现在我们可以在你的 shell 中通过生命周期操作进行操作。
```
# 以 root 身份运行
cd /mycontainer
runc create mycontainerid
# 查看容器已创建且处于 "created" 状态
runc list
# 启动容器内的进程
runc start mycontainerid
# 5 秒后查看容器已退出且现在处于 stopped 状态
runc list
# 现在删除容器
runc delete mycontainerid
```
这允许更高层的系统在容器创建之后和/或删除之前,通过各种设置的设置来增强容器创建逻辑。例如,容器的网络栈通常在 `create` 之后但在 `start` 之前设置。
#### Rootless containers
`runc` 能够在没有 root 权限的情况下运行容器。这被称为 `rootless`。你需要向 `runc` 传递一些参数才能运行 rootless containers。请参阅下面的内容并与以前的版本进行比较。
**注意:** 为了使用此功能,必须在你的内核中编译并启用 "User Namespaces"。根据你的发行版,有多种方法可以做到这一点:
- 确认在你的内核配置中设置了 `CONFIG_USER_NS=y`(通常位于 `/proc/config.gz`)
- Arch/Debian: `echo 1 > /proc/sys/kernel/unprivileged_userns_clone`
- RHEL/CentOS 7: `echo 28633 > /proc/sys/user/max_user_namespaces`
以普通用户身份运行以下命令:
```
# 与第一个示例相同
mkdir ~/mycontainer
cd ~/mycontainer
mkdir rootfs
docker export $(docker create busybox) | tar -C rootfs -xvf -
# --rootless 参数指示 runc spec 为 rootless 容器生成配置,这将允许你以非 root 用户身份运行容器。
runc spec --rootless
# --root 参数告诉 runc 在哪里存储容器状态。它必须对用户可写。
runc --root /tmp/runc run mycontainerid
```
#### Supervisors
`runc` 可以与进程监督器 (process supervisors) 和 init 系统结合使用,以确保容器在退出时重新启动。
一个示例 systemd 单元文件如下所示。
```
[Unit]
Description=Start My Container
[Service]
Type=forking
ExecStart=/usr/local/sbin/runc run -d --pid-file /run/mycontainerid.pid mycontainerid
ExecStopPost=/usr/local/sbin/runc delete mycontainerid
WorkingDirectory=/mycontainer
PIDFile=/run/mycontainerid.pid
[Install]
WantedBy=multi-user.target
```
## 更多文档
* [Spec conformance](./docs/spec-conformance.md)
* [cgroup v2](./docs/cgroup-v2.md)
* [Checkpoint and restore](./docs/checkpoint-restore.md)
* [systemd cgroup driver](./docs/systemd.md)
* [Terminals and standard IO](./docs/terminals.md)
* [Experimental features](./docs/experimental.md)
* [Deprecated features](./docs/deprecated.md)
## 许可证
代码和文档在 [Apache 2.0 license](LICENSE) 下发布。
标签:Awesome, DNS解析, Docker, EVTX分析, Golang, Go语言, libcontainer, runc, 云计算, 基础设施, 子域名枚举, 安全编程, 安全防御评估, 容器技术, 容器标准, 容器运行时, 开放容器倡议, 开源项目, 日志审计, 程序破解, 系统安全, 系统管理, 虚拟化, 规则引擎