Ubuntu 22.04 安装 crun 指南
在 Ubuntu 22.04 上通过 apt 在线安装与官方 GitHub 源码离线编译两种方式部署 crun 1.x OCI 运行时,并完成 crun spec/run/exec 最小 rootfs 实测验证与 Podman runtime 配置。
Ubuntu 22.04 安装 crun 指南
目标:在 Ubuntu 22.04 上安装并验证 crun(OCI 标准、C 语言实现、比 runc 更轻量、依托 cgroups v2 的低层运行时,也是 Podman 的默认运行时之一)。本文覆盖 apt 在线安装与官方 GitHub release 源码离线编译两种方案,并用最小 rootfs 对
crun run/exec做了真实回显验证。已在 Ubuntu 22.04.5 LTS(x86_64)实测通过。
💡 定位说明:crun 是「低层」运行时(low-level runtime),本身不管理镜像、不提供长驻守护进程,日常主要由 Podman、Buildah(以及 CRI 场景)按 OCI 接口调用。本文只负责在系统里安装好 crun 二进制并验证它能把 OCI bundle 跑起来。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(
jammy) - 架构:
x86_64(amd64) - 内核 / cgroup:Linux cgroups v2(unified hierarchy)
- 在线渠道版本:
crun 0.17+dfsg-1.1ubuntu0.1(Ubuntuuniverse仓库) - 离线渠道版本:
crun 1.20(官方 GitHub release 源码编译) - 同机对比对象:
runc 1.3.4-0ubuntu1~22.04.1(apt 安装) - crun 可执行文件:
/usr/bin/crun - crun 状态目录(bundle/rootfs):
/opt/crun-bundle/ - 所需权限:root(crun 运行时需要创建命名空间与操作 cgroup v2)
⚠️ 前置:
crun run/create需要 root 权限来创建 mount/pid/user 等命名空间并挂载/写入 cgroup v2。请使用 root 账号(或具有完整 sudo 的账号,密码示例q1w2e3r4)执行本文命令。
二、版本选型
crun 是基于 C 语言、遵循 OCI Runtime Spec 的运行时,与 runc(同源自 runc 的 Go 实现)竞争同一生态位,但更强调轻量和低内存占用。
2.1 版本线
- 主线/稳定版:crun 1.x(如 1.20),由
containers/crun维护,cgroups v2、systemd-cgroup、SELinux/AppArmor、seccomp、EBPF 等能力默认编译启用。 - Ubuntu 仓库版本:
universe仓库长期停留在0.17+dfsg(dfsg为 Debian 的去重打包后缀)。它功能完整、开箱即用,但比上游 1.x 旧。
两者都能正常完成 OCI 启动,选择建议:能联网、不追求最新 → 用 apt 的 0.17 最省事;需要上游最新特性 / 断网交付 → 用源码编译 1.20。
2.2 cgroups v2 与低层运行时的关系
- 现代 Ubuntu(含 22.04)默认全套启用 cgroups v2,crun 直接基于 cgroups v2 统一层级做资源限制,不依赖 systemd 也能工作(配合 systemd 时可用
--systemd-cgroup)。 - crun 没有常驻守护进程:每次调用只是
create/start/run/delete等进程级动作,非常适合被上层工具(Podman、kubelet/CRIO)拉起来后退出。
2.3 与 Podman / 其他运行时关系
- Podman 默认以 crun 为其低层运行时(可从 Podman 的
--runtime或配置文件切换,也可切回 runc)。 - 本机同装 runc 用于对照版本与差异,不影响 crun 正常工作。
版本对照表:
| 项 | crun(apt 0.17) | crun(源码 1.20) | runc(apt 1.3.4) |
|---|---|---|---|
| 实现语言 | C | C | Go |
| OCI Runtime Spec | 1.0.0 | 1.0.0(上限 1.1.0+dev) | 1.2.1 |
| cgroups v2 | 支持 | 支持 | 支持 |
| 安装方式 | apt install crun | 源码编译 | apt install runc |
| 适用 | 快速开箱 | 上游新特性 / 断网 | 对照 / 部分上层默认 |
三、在线安装(方案 A:apt)
Ubuntu 22.04 的 universe 仓库自带 crun,联网状态下一行即可装好。
3.1 更新源并安装
# Ubuntu server 服务器,root 执行
apt-get update
apt-get install -y crun
实测回显(安装摘要):
Selecting previously unselected package crun.
Preparing to unpack .../crun_0.17+dfsg-1.1ubuntu0.1_amd64.deb ...
Unpacking crun (0.17+dfsg-1.1ubuntu0.1) ...
Setting up crun (0.17+dfsg-1.1ubuntu0.1) ...
💡 apt 会自动带入运行依赖:
libc6、libcap2、libseccomp2、libsystemd0、libyajl2。装完的 crun 位于/usr/bin/crun。
3.2 验证在线版本
crun --version
实测回显:
crun version 0.17
commit: 0e9229ae34caaebcb86f1fde18de3acaf18c6d9a
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL
四、离线 / 源码安装(方案 B:官方 GitHub release 源码编译)
断网环境,或需要上游 1.x 新特性时,用官方 GitHub release 提供的源码 tar.gz 编译安装。
4.1 准备工作:编译依赖
apt-get update
apt-get install -y build-essential automake autoconf libtool pkg-config \
libseccomp-dev libcap-dev libyajl-dev libjson-c-dev libsystemd-dev
autoconf/automake/libtool:运行autogen.sh生成configure。libseccomp-dev:seccomp 过滤。libyajl-dev:JSON 解析(crun/libocispec 依赖 yajl)。libjson-c-dev:libocispec 生成的头部依赖 json-c。libsystemd-dev:systemd-cgroup 支持。
4.2 获取源码(含 libocispec 子模块)
crun 源码依赖其 libocispec(OCI schema 的 C 绑定,内含 runtime-spec/image-spec/yajl 子模块),而 GitHub 的 release tar.gz 不打包子模块源码。有两种取法:
方式一(推荐,直接拿到子模块)——用 git 拉取 release 分支的完整源码树:
cd /opt
git clone --recursive --branch 1.20 \
https://github.com/containers/crun.git crun-src
方式二(下载官方 release tar.gz,再单独补子模块)——先下载 crun-1.20.tar.gz 解压,再按需把匹配的 libocispec(及其 runtime-spec、image-spec、yajl)源码放进 crun-1.20/libocispec/ 对应子目录下即可。本文实测采用方式二,标准目录:
/opt/crun-1.20/
├── autogen.sh
├── configure.ac
└── libocispec/ # crun 依赖的子模块
├── runtime-spec/ # OCI Runtime Spec schema
├── image-spec/ # OCI Image Spec schema
├── yajl/ # 打包的 yajl
└── src/ocispec/ # 生成的 C 绑定源码
4.3 准备版本号文件
从无 .git 的 tar.gz 编译时,autotools 无法用 git describe 确定版本号,crun --version 会显示 version UNKNOWN。解决办法:在源码根目录放置 .tarball-version 后重新 autogen:
cd /opt/crun-1.20 # 或 /opt/crun-src
echo "1.20" > .tarball-version
4.4 生成配置并编译安装
cd /opt/crun-1.20
./autogen.sh # 生成 ./configure
./configure --prefix=/usr # 安装到 /usr/bin/crun
make -j$(nproc) # 编译
make install # 安装到 /usr
--prefix=/usr下,二进制装到/usr/bin/crun、man 页装到/usr/share/man/man1/crun.1。- 若此前已通过 apt 装过 crun,
make install会覆盖/usr/bin/crun(体现在版本号从 0.17 变为 1.20)。
实测编译尾部回显:
CCLD libcrun.la
CCLD crun
make[2]: Leaving directory '/opt/crun-1.20'
make[1]: Leaving directory '/opt/crun-1.20'
make install 关键回显:
libtool: install: /usr/bin/install -c crun /usr/bin/crun
/usr/bin/install -c -m 644 crun.1 '/usr/share/man/man1'
4.5 验证源码版本
crun --version
实测回显:
crun version 1.20
commit: 1.20
rundir: /run/crun
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL
💡 与 apt 版相比,源码版多出
rundir: /run/crun一行(1.x 新增),并支持crun features(输出ociVersionMax: 1.1.0+dev)等新命令。
4.6 与已装 runc 对比
若同时装了 runc,可在同一台机器直接对照:
runc --version
实测回显:
runc version 1.3.4-0ubuntu1~22.04.1
spec: 1.2.1
go: go1.24.4
libseccomp: 2.5.3
两者都遵循 OCI 接口作低层运行时;runc 自带更高 OCI spec(1.2.1),crun 由 C 实现、内存占用更小。
五、crun 配置
5.1 无守护进程、无独立配置文件
crun 采用"单次执行即退"模型:没有长驻 daemon,也没有自己是"面向全局"的独立配置文件。它的全部运行参数来自 OCI bundle 目录里的 config.json(OCI Runtime Spec),由调用方(Podman/CRI)或 crun spec 生成。
- 默认 bunde 目录:当前目录(可用
-b DIR指定)。 - 状态/运行目录:
/run/crun(crun --version中的rundir),存放运行中的容器状态。
5.2 生成默认配置:crun spec
在一个 bundle 目录里生成默认 config.json:
mkdir -p /opt/crun-bundle/rootfs
cd /opt/crun-bundle
crun spec
crun spec 帮助(实测):
Usage: spec [OPTION...] spec
OCI runtime
-b, --bundle=DIR path to the root of the bundle dir (default ".")
-f, --file=PATH destination file
--rootless spec for the rootless case
默认生成的关键字段(实测):
| config.json 字段 | 实测默认值 | 说明 |
|---|---|---|
root.path | rootfs | 相对 bundle 的 rootfs 目录(只读 readonly: true) |
process.args | ["sh"] | 首进程命令 |
process.terminal | true | 默认申请 TTY |
mounts | 7 条 | /proc、/sys、/dev 等基础挂载 |
5.3 关键字段说明(cgroups v2)
root:容器根文件系统,指向rootfs。process:首进程args、env、cwd、terminal。mounts:挂载点(/proc、/sys、/dev/pts等)。linux.cgroupsPath:cgroup v2 归属路径。不设时 crun 会放到默认层级;配--systemd-cgroup时交给 systemd 管理 scope。linux.resources:CPU/内存/IO 限制,作用于 cgroups v2。
⚠️ 非 rootless 场景
crun run需要 root:它要创建命名空间并把 cgroup v2 控制器写入/sys/fs/cgroup。rootless(crun spec --rootless+ user namespaces)需内核与子用户配置,不在本文展开。
5.4 用作 Podman 的默认运行时
在 /etc/containers/containers.conf 的 [engine.runtimes] 下把 crun 与可执行路径绑定,并作为默认 runtime(engine 段的 runtime = "crun" 即显式置为默认):
[engine.runtimes]
crun = [
"/usr/bin/crun",
]
[engine]
runtime = "crun"
⚠️ 需装好
podman本体后该配置才生效;crun 本身不依赖该文件。装好 Podman 后可用podman info --format '{{.Host.OCIRuntime.Name}}'核对当前生效的低层运行时名称。
六、验证(crun run / exec 实测)
用最小 rootfs 真实跑一次 crun,验证它能完成 OCI 启动。
6.1 准备最小 rootfs(debootstrap)
apt-get install -y debootstrap
mkdir -p /opt/crun-bundle
debootstrap --variant=minbase --arch=amd64 \
jammy /opt/crun-bundle/rootfs http://archive.ubuntu.com/ubuntu
⚠️ 前置:debootstrap 需要能访问
archive.ubuntu.com。rootfs 就绪后/opt/crun-bundle/rootfs/bin/sh -> dash即说明核心用户态已就位。
6.2 生成并微调 config.json
cd /opt/crun-bundle
crun spec
把首进程改成能打印身份的一次性命令(TTY 关掉、rootfs 可写),便于非交互回显:
cd /opt/crun-bundle
python3 - <<'PY'
import json
d=json.load(open("config.json"))
d["process"]["terminal"]=False
d["process"]["args"]=["/bin/sh","-c","echo HELLO-FROM-CRUN; cat /etc/os-release | head -2; hostname"]
d["root"]["readonly"]=False
json.dump(d,open("config.json","w"),indent=2)
PY
6.3 crun run(一次性运行)
cd /opt/crun-bundle
crun run real-test
实测回显(容器内真实执行了 Ubuntu 22.04 用户态):
HELLO-FROM-CRUN
PRETTY_NAME="Ubuntu 22.04 LTS"
NAME="Ubuntu"
crun
💡
hostname输出crun,bundle 内 rootfs 确实是 Ubuntu 22.04 的/bin/sh在 crun 管理的命名空间里运行。
6.4 crun create / start / list / state / exec / kill / delete(生命周期)
把首进程改为常驻,测试完整生命周期。先把 config.json 首进程改成 /bin/sleep 300,然后:
cd /opt/crun-bundle
crun create long-test
crun list
crun state long-test
crun start long-test
crun ps long-test
实测回显(crun list):
NAME PID STATUS BUNDLE PATH CREATED OWNER
long-test 51185 created /opt/crun-bundle 2026-10-09T09:52:36.330672Z root
crun state long-test(节选):
{
"ociVersion": "1.0.0",
"id": "long-test",
"pid": 51185,
"status": "created",
"bundle": "/opt/crun-bundle",
"rootfs": "rootfs",
"systemd-scope": "",
"owner": "root"
}
crun start 后,crun list 中 STATUS 变为 running,crun ps 显示进程 PID。
再进进程内执行命令:
crun exec long-test /bin/sh -c "echo EXEC-OK; id; cat /etc/os-release | head -1"
实测回显:
EXEC-OK
uid=0(root) gid=0(root) groups=0(root)
PRETTY_NAME="Ubuntu 22.04 LTS"
最后关停并清理:
crun kill long-test 9
crun delete -f long-test
crun list # 此时列表为空
6.5 工具速查:crun 主命令与常用参数
crun --help(实测)列出全部子命令:
COMMANDS:
create - create a container
delete - remove definition for a container
exec - exec a command in a running container
features - show the enabled features
list - list known containers
kill - send a signal to the container init process
ps - show the processes in the container
run - run a container
spec - generate a configuration file
start - start a container
state - output the state of a container
pause - pause all the processes in the container
resume - unpause the processes in the container
update - update container resource constraints
--cgroup-manager=MANAGER cgroup manager
--debug
--log=FILE
--log-level=LEVEL
--root=DIR
--systemd-cgroup use systemd cgroups
-v, -V, --version
crun run 常用参数(实测):
-b, --bundle=DIR container bundle (default ".")
-d, --detach detach from the parent
--keep do not delete the container after it exits
--no-pivot do not use pivot_root
--pid-file=FILE where to write the PID of the container
七、升级 / 卸载
7.1 升级
- apt 渠道:
apt-get update && apt-get upgrade crun(跟随 Ubuntu 仓库版本)。 - 源码渠道:拉新 release(如 1.21)重复四、4.2~4.4 的
make && make install,会覆盖旧版/usr/bin/crun。
7.2 卸载
- apt 安装版:
apt-get remove -y crun
# 卸载并清除配置文件
apt-get purge -y crun
apt-get autoremove -y
- 源码编译版(
make install进/usr/bin的二进制):
# 在源码目录反安装
cd /opt/crun-1.20
make uninstall
# 或直接删除二进制与 man 页
rm -f /usr/bin/crun /usr/share/man/man1/crun.1
💡 运行中残留状态在
/run/crun(临时目录,重启自动清空);bundle/rootfs 在/opt/crun-bundle,需要时自行rm -rf /opt/crun-bundle。
八、常见问题
8.1 编译报错 Package requirements (json-c >= 0.14) were not met
现象:./autogen.sh(libocispec 内)报找不到 json-c。
定位:config.libocispec 需要 pkg-config 能查到 json-c。
解决:
apt-get install -y libjson-c-dev
8.2 编译报错 fatal error: git-version.h 或 crun version UNKNOWN
现象:make 报 git-version.h: No such file or directory;或装完 crun --version 显示 version UNKNOWN。
定位:源码来自无 .git 的 tar.gz,autotools 无法 git describe 得到版本号。
解决:四、4.3 中写入 .tarball-version 后重新 ./autogen.sh && ./configure 再编译,版本即正常显示 1.20。
8.3 crun run 报权限 / cgroup 相关错误
现象:crun run 报命名空间或 /sys/fs/cgroup 写入失败。
定位:缺少 root 权限或 cgroup 控制器不可写。
解决:用 root 执行;确认系统为 cgroups v2(/sys/fs/cgroup/cgroup.controllers 存在)。rootless 需另行准备 user namespaces 与子用户映射。
8.4 crun 0.17 与 1.20 的区别要不要管
现象:apt 装的是 0.17,官方是 1.x。
说明:0.17 功能完整,crun run/exec 行为一致;1.x 增加 rundir 行与 features 命令、spec 上限提到 1.1.0+dev。多数日常使用两者等价,无需强求统一。
8.5 与 runc 能否共存
现象:想同时保留 runc 与 crun。
说明:完全可以。两者独立二进制、各自按 OCI 接口工作;上层工具在配置里指定用哪个(如 Podman 的 runtime = "crun" 或 --runtime)。删 crun 不影响 runc。
九、参考链接
- crun 官方仓库(源码、release):
https://github.com/containers/crun - crun 文档 / man:
https://github.com/containers/crun/blob/main/README.md - OCI Runtime Spec:
https://github.com/opencontainers/runtime-spec - Podman containers.conf 说明(配置 crun 为默认运行时):
https://github.com/containers/common/blob/main/docs/containers.conf.5.md - Ubuntu 软件源 crun 包信息:
https://packages.ubuntu.com/jammy/crun