Github开源生信云平台 DEMO
你问的这几个概念其实正好构成了 OCI 容器运行的完整链路。我按“从文件 → 运行”的顺序给你拆清楚,并重点对比你关心的:runc vs 直接执行 binary。
OCI Image ↓(umoci / 自己实现) rootfs(文件系统) ↓ + config.json OCI Runtime Bundle ↓(runc) 容器进程(隔离环境)
👉 本质就是:
一个解压后的 Linux 文件系统目录
比如:
rootfs/ ├── bin/ ├── lib/ ├── usr/ ├── etc/ └── app/your_binary
它来自哪里?
👉 来自 OCI 镜像的 layers 解压
📌 类比:
chroot
👉 这是 OCI 标准定义的“运行单位”
结构固定:
bundle/ ├── rootfs/ └── config.json
定义了:
📌 可以理解为:
👉 rootfs = 文件👉 config.json = 运行说明书
👉 作用:
把 OCI image 转换成 runtime bundle
umoci unpack --image myimage bundle/
它会做:
📌 本质:
👉 umoci = “镜像 → 可运行目录”
根据 bundle 启动容器
runc run mycontainer
它做的事情非常关键 👇
runc ≠ 执行 binaryrunc = 创建“隔离环境” + 执行 binary
👉 把 rootfs 变成“/”
容器内看到的 / 就是 rootfs/
execve("/app/your_binary")
这是你最关键的问题 👇
exec.Command("./llama.cpp")
👉 就是普通进程
runc run container
👉 是“容器进程”
在你当前 Ubuntu 上运行程序
给你创建一个“新的迷你 Linux 世界” 你在里面运行程序
结合你前面的问题:
👉 因为它只需要:
拿到 binary → 运行
而不需要:
这些场景就必须用:
你在做:
生信 pipeline / Nextflow / 调度系统
Go 调度器 └── exec binary(像 LocalAI)
✔ 性能最好❌ 无隔离
Go └── containerd / runc └── 容器运行任务
✔ 可控✔ 安全✔ 标准化
Go ├── 小任务 → 直接 exec └── 用户任务 → runc
👉 rootfs = 解压后的系统文件👉 bundle = rootfs + config.json👉 umoci = 生成 bundle👉 runc = 在隔离环境中执行程序
👉 最大区别:runc 提供“容器隔离”,直接 exec 没有
如果你想,我可以给你一个:
✅ “手写 OCI bundle + runc 启动 busybox” 的最小 demo(能让你彻底理解整个链路)