四、Linux 内核容器技术深度解析系列-9-linux-kernel-container-runtime
·
Linux 内核容器技术:容器运行时与系统调用
文档信息
- 系列: Linux 内核容器技术深度解析
- 第四篇: 容器运行时与系统调用
- 版本: V1.0
- 创建日期: 2026 年 3 月 10 日
- 预计阅读时间: 4 小时
- 技术难度: ⭐⭐⭐⭐⭐ (专家级)
- 前置知识: Linux 系统编程、进程管理、Namespace 与 CGroups
目录
- 容器运行时架构
- [OCI 标准与规范](#oci 标准与规范)
- [runc 核心原理](#runc 核心原理)
- [containerd 架构](#containerd 架构)
- 系统调用深度解析
- 安全加固技术
容器运行时架构
容器运行时分类
高层运行时 (High-Level Runtime):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
代表:Docker Engine, containerd
职责:
├─ 镜像管理
├─ 容器生命周期
├─ 网络配置
└─ 存储管理
示例架构:
Docker Engine
├─ CLI (docker 命令)
├─ Daemon (守护进程)
├─ containerd (容器管理)
└─ runc (容器运行)
底层运行时 (Low-Level Runtime):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
代表:runc, crun, kata-runtime
职责:
├─ 创建 Namespace
├─ 设置 CGroups
├─ 配置文件系统
└─ 启动容器进程
调用链:
containerd → runc → Linux 内核
运行时对比:
runc:
├─ Docker 开发
├─ OCI 参考实现
├─ 成熟稳定
└─ 使用最广泛
crun:
├─ C 语言编写
├─ 启动更快
├─ 内存占用更少
└─ Podman 默认
kata-runtime:
├─ 轻量级 VM
├─ 强隔离
├─ 安全性高
└─ 性能开销 5-10%
容器生命周期管理
容器创建流程:
1. docker run nginx
↓
2. Docker Daemon 接收请求
↓
3. 调用 containerd
↓
4. containerd 创建 Task
↓
5. containerd 调用 runc
↓
6. runc 创建容器
├─ 创建 Namespace
├─ 设置 CGroups
├─ 配置 Rootfs
└─ 启动进程
↓
7. 返回容器 ID
状态转换:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
created → running → paused → stopped
↑ ↓ ↓ ↓
└─────────┘ └────────┘
restart remove
OCI 标准与规范
OCI 规范体系
OCI (Open Container Initiative):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
由 Linux 基金会托管
目标:制定容器行业标准
三大规范:
1. Runtime Specification (runtime-spec)
定义:容器运行时标准
内容:
├─ 容器配置格式 (config.json)
├─ 生命周期管理
└─ 操作接口
2. Image Specification (image-spec)
定义:容器镜像标准
内容:
├─ 镜像格式
├─ 分层存储
└─ 清单文件
3. Distribution Specification
定义:镜像分发标准
内容:
├─ Registry API
├─ 镜像推送/拉取
└─ 签名验证
config.json 示例:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{
"ociVersion": "1.0.2",
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": ["bash"],
"cwd": "/"
},
"root": {
"path": "rootfs",
"readonly": true
},
"hostname": "container",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
}
],
"linux": {
"namespaces": [
{"type": "pid"},
{"type": "network"},
{"type": "mount"},
{"type": "uts"},
{"type": "ipc"}
],
"cgroupsPath": "/docker/container1",
"resources": {
"memory": {
"limit": 536870912
},
"cpu": {
"quota": 50000,
"period": 100000
}
}
}
}
runc 核心原理
runc 架构
runc 组件:
libcontainer:
├─ Namespace 管理
├─ CGroups 配置
├─ 文件系统设置
└─ 设备访问控制
命令接口:
├─ create: 创建容器
├─ start: 启动容器
├─ run: 创建并启动
├─ exec: 执行命令
├─ stop: 停止容器
└─ delete: 删除容器
工作流程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
runc create mycontainer
↓
1. 读取 config.json
↓
2. 创建 Namespace
clone(flags)
↓
3. 设置 CGroups
cgroups.Create()
↓
4. 配置 Rootfs
mount(rootfs)
↓
5. 启动容器进程
exec()
runc 核心代码解析
Namespace 创建:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// libcontainer/container_linux.go
func (c *container) newParentProcess() (parentProcess, error) {
cmd := exec.Command(c.initPath, "init")
// 设置 Namespace
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWPID |
syscall.CLONE_NEWNET |
syscall.CLONE_NEWNS |
syscall.CLONE_NEWUTS |
syscall.CLONE_NEWIPC,
}
return &initProcess{cmd: cmd}, nil
}
CGroups 配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// libcontainer/cgroups/systemd.go
func (s *Manager) Apply(cgroups *configs.Cgroup) error {
// 创建 CGroups 目录
path := filepath.Join("/sys/fs/cgroup", cgroups.Path)
os.MkdirAll(path, 0755)
// 设置内存限制
if cgroups.Resources.MemoryLimit > 0 {
ioutil.WriteFile(
filepath.Join(path, "memory.limit_in_bytes"),
[]byte(strconv.FormatInt(cgroups.Resources.MemoryLimit, 10)),
0700,
)
}
// 设置 CPU 限制
if cgroups.Resources.CpuQuota > 0 {
ioutil.WriteFile(
filepath.Join(path, "cpu.cfs_quota_us"),
[]byte(strconv.FormatInt(cgroups.Resources.CpuQuota, 10)),
0700,
)
}
return nil
}
文件系统挂载:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// libcontainer/rootfs_linux.go
func mountRootfs(rootfs string, mounts []configs.Mount) error {
for _, m := range mounts {
// 挂载 proc
if m.Device == "proc" {
syscall.Mount("proc",
filepath.Join(rootfs, m.Destination),
"proc", 0, "")
}
// 挂载 sysfs
if m.Device == "sysfs" {
syscall.Mount("sysfs",
filepath.Join(rootfs, m.Destination),
"sysfs", 0, "")
}
}
return nil
}
containerd 架构
containerd 设计
containerd 架构:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─────────────────────────────────────────┐
│ Client (gRPC) │
└─────────────┬───────────────────────────┘
│
┌─────────────▼───────────────────────────┐
│ containerd Daemon │
│ ┌──────────┐ ┌──────────┐ │
│ │ Images │ │ Tasks │ │
│ └──────────┘ └────────── │
│ ┌──────────┐ ┌──────────┐ │
│ │Snapshotter│ │ Events │ │
│ └────────── └──────────┘ │
└─────────────┬───────────────────────────┘
│
┌─────────────▼───────────────────────────┐
│ containerd-shim │
└─────────────┬───────────────────────────┘
│
┌─────────────▼───────────────────────────┐
│ runc │
└─────────────────────────────────────────┘
核心组件:
Images Service:
├─ 镜像拉取
├─ 镜像管理
└─ 分层存储
Snapshotter:
├─ 文件系统快照
├─ OverlayFS
└─ 写时复制
Tasks Service:
├─ 容器生命周期
├─ 进程管理
└─ 状态监控
Events:
├─ 事件发布
├─ 订阅机制
└─ 监控集成
containerd 使用
命令行操作:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 拉取镜像
$ ctr images pull docker.io/library/nginx:latest
# 运行容器
$ ctr run docker.io/library/nginx:latest my-nginx
# 查看容器
$ ctr tasks ls
# 执行命令
$ ctr tasks exec --exec-id exec1 my-nginx
# 查看日志
$ ctr tasks exec my-nginx cat /var/log/nginx/access.log
Go SDK 使用:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
package main
import (
"github.com/containerd/containerd"
"golang.org/x/net/context"
)
func main() {
// 连接 containerd
client, _ := containerd.New("/run/containerd/containerd.sock")
defer client.Close()
// 拉取镜像
ctx := context.Background()
image, _ := client.Pull(ctx, "docker.io/library/nginx:latest")
// 创建容器
container, _ := client.NewContainer(
ctx,
"my-nginx",
containerd.WithImage(image),
containerd.WithNewSpec(),
)
// 启动容器
task, _ := container.NewTask(ctx, containerd.Stdio)
task.Start(ctx)
}
系统调用深度解析
容器相关系统调用
进程创建类:
clone():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sched.h>
int clone(int (*fn)(void *), void *stack,
int flags, void *arg, ...);
flags 参数:
├─ CLONE_NEWPID 0x20000000 PID Namespace
├─ CLONE_NEWNET 0x40000000 NET Namespace
├─ CLONE_NEWNS 0x00020000 MNT Namespace
├─ CLONE_NEWUTS 0x04000000 UTS Namespace
├─ CLONE_NEWIPC 0x08000000 IPC Namespace
├─ CLONE_NEWUSER 0x10000000 USER Namespace
├─ CLONE_NEWCGROUP 0x02000000 CGroup Namespace
└─ SIGCHLD 0x00000011 发送信号
示例:
int flags = CLONE_NEWPID | CLONE_NEWNET | SIGCHLD;
pid_t pid = clone(child_func, stack, flags, NULL);
unshare():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sched.h>
int unshare(int flags);
功能:当前进程脱离 Namespace
示例:
unshare(CLONE_NEWPID | CLONE_NEWNS);
文件系统类:
mount():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sys/mount.h>
int mount(const char *source, const char *target,
const char *filesystemtype,
unsigned long mountflags,
const void *data);
容器中的应用:
// 挂载 proc
mount("proc", "/rootfs/proc", "proc", 0, NULL);
// 挂载 sysfs
mount("sysfs", "/rootfs/sys", "sysfs", 0, NULL);
// 挂载 tmpfs
mount("tmpfs", "/rootfs/tmp", "tmpfs", 0, "size=100m");
chroot():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <unistd.h>
int chroot(const char *path);
功能:改变根目录
示例:
chroot("/var/lib/container/rootfs");
chdir("/");
进程控制类:
execve():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <unistd.h>
int execve(const char *filename,
char *const argv[],
char *const envp[]);
功能:执行容器 init 进程
示例:
execve("/bin/bash", ["bash", "-l"], env);
pivot_root():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sys/syscall.h>
syscall(SYS_pivot_root,
const char *new_root,
const char *put_old);
功能:切换根文件系统 (比 chroot 更安全)
示例:
pivot_root("/rootfs", "/rootfs/.old_root");
CGroups 类:
setrlimit():
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <sys/resource.h>
int setrlimit(int resource,
const struct rlimit *rlim);
功能:设置资源限制
示例:
struct rlimit rl;
rl.rlim_cur = 100; // 软限制
rl.rlim_max = 200; // 硬限制
setrlimit(RLIMIT_NOFILE, &rl); // 文件描述符限制
系统调用追踪
使用 strace 追踪:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 追踪容器创建
$ strace -f -e trace=process,network docker run nginx
输出示例:
clone(child_stack=NULL,
flags=CLONE_NEWPID|CLONE_NEWNET|CLONE_NEWNS|SIGCHLD) = 12345
mount("proc", "/proc", "proc", 0, NULL) = 0
chroot("/var/lib/docker/overlay2/xxx") = 0
execve("/bin/nginx", ["nginx"], ...) = 0
使用 bpftrace 追踪:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 追踪所有 clone 调用
$ sudo bpftrace -e '
tracepoint:syscalls:sys_enter_clone
/comm == "runc"/
{
printf("PID %d cloning with flags %d\n", pid, args->flags);
}'
# 追踪 mount 调用
$ sudo bpftrace -e '
tracepoint:syscalls:sys_enter_mount
{
printf("Mounting %s -> %s\n",
str(args->source),
str(args->target));
}'
安全加固技术
容器安全层次
安全层次 1: Namespace 隔离
基础隔离:
├─ PID Namespace: 进程隔离
├─ NET Namespace: 网络隔离
├─ MNT Namespace: 文件系统隔离
└─ USER Namespace: 权限隔离
增强措施:
├─ 禁用特权模式
├─ 删除 capabilities
└─ 只读根文件系统
安全层次 2: CGroups 限制
资源限制:
├─ CPU 配额
├─ 内存限制
├─ I/O 带宽
└─ 进程数
防止攻击:
├─ 防止 DoS
├─ 防止资源耗尽
└─ QoS 保障
安全层次 3: Capabilities
Linux Capabilities:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CAP_CHOWN: 修改文件所有者
CAP_DAC_OVERRIDE: 绕过文件权限检查
CAP_NET_RAW: 使用原始 socket
CAP_SYS_ADMIN: 超级管理员权限
... (共 40+ 种)
Docker 默认:
├─ 保留部分 capabilities
├─ 删除危险 capabilities
└─ 可自定义
配置示例:
$ docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
安全层次 4: Seccomp
Seccomp-BPF:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
功能:限制系统调用
配置示例:
{
"defaultAction": "SCMP_ACT_ERRNO",
"syscalls": [
{
"names": ["accept", "bind", "connect"],
"action": "SCMP_ACT_ALLOW"
}
]
}
应用:
$ docker run --security-opt seccomp=profile.json nginx
安全层次 5: AppArmor/SELinux
AppArmor 配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#include <tunables/global>
profile docker-container flags=(attach_disconnected) {
#include <abstractions/base>
network inet tcp,
network inet udp,
/bin/nginx ix,
/usr/share/nginx/** r,
deny /etc/shadow rw,
}
应用:
$ docker run --security-opt apparmor=docker-container nginx
安全最佳实践
1. 最小权限原则
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 非 root 运行
$ docker run --user 1000:1000 nginx
# 只读文件系统
$ docker run --read-only nginx
# 删除所有 capabilities
$ docker run --cap-drop=ALL nginx
# 禁用特权
$ docker run --privileged=false nginx
2. 资源限制
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# CPU 限制
$ docker run --cpus="0.5" nginx
# 内存限制
$ docker run -m="512m" nginx
# 进程数限制
$ docker run --pids-limit=100 nginx
3. 网络隔离
配置:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 自定义网络
$ docker network create isolated
# 网络策略
$ docker run --network=isolated nginx
# 禁止外网
$ docker run --sysctl net.ipv4.conf.all.route_localnet=0 nginx
4. 镜像安全
措施:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ 使用官方镜像
✓ 定期更新
✓ 漏洞扫描
✓ 最小化镜像
✓ 签名验证
示例:
$ docker scan nginx
$ docker trust sign nginx
5. 运行时监控
监控工具:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
├─ Falco: 行为检测
├─ Aqua Security: 容器安全
├─ Sysdig: 系统调用监控
└─ OSSEC: 入侵检测
配置 Falco 规则:
- rule: Shell in container
desc: Detect shell process
condition: (proc.name = bash)
output: "Shell detected (user=%user.name)"
priority: WARNING
总结
容器运行时核心技术
关键组件:
├─ OCI 规范:行业标准
├─ runc: 底层运行时
├─ containerd: 高层管理
└─ Docker: 完整引擎
系统调用:
├─ clone/unshare: Namespace
├─ mount/chroot: 文件系统
├─ execve: 进程执行
└─ setrlimit: 资源限制
安全体系:
├─ Namespace 隔离
├─ CGroups 限制
├─ Capabilities 权限
├─ Seccomp 系统调用过滤
└─ AppArmor/SELinux 强制访问
技术发展趋势
短期趋势:
├─ containerd 成为标准
├─ CGroups v2 普及
├─ Seccomp 默认启用
└─ 安全容器兴起
中期趋势:
├─ eBPF 深度集成
├─ WebAssembly 容器
├─ 无服务器容器
└─ 边缘容器
长期趋势:
├─ 量子容器
├─ 生物计算容器
├─ 星际容器网络
└─ 意识上传容器
本文档属于 Linux 内核容器技术深度解析系列
第四篇:容器运行时与系统调用
版本:V1.0
最后更新:2026 年 3 月
技术难度:⭐⭐⭐⭐⭐
系列完结撒花!🎉
更多推荐



所有评论(0)