尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

从零实现一个容器运行时:Docker的核心设计

从零实现一个容器运行时:Docker的核心设计
📅 发布时间:2026/7/7 5:04:13

前言

你有没有想过:Docker是怎么做到让一个程序看起来像在独立系统里运行的?隔离是怎么实现的?

Docker的核心技术是 Namespace + Cgroups + 联合文件系统。

今天我们用C语言从零实现一个容器运行时的核心功能:

· Namespace隔离(PID、NET、IPC、UTS、Mount)
· Cgroups资源限制(CPU、内存)
· Rootfs切换(chroot/pivot_root)
· 容器生命周期管理
· 镜像分层(联合文件系统)

---

一、容器运行时核心原理

1. 容器技术栈

```
┌─────────────────────────────────────────────────────────────┐
│ 容器 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Namespace隔离 │ │
│ │ PID | NET | IPC | UTS | Mount | User │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Cgroups资源限制 │ │
│ │ CPU | Memory | Disk I/O | Network I/O │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Rootfs (chroot/pivot_root) │ │
│ │ /bin /etc /usr /var /lib ... │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```

2. 核心概念

概念 说明
Namespace 资源隔离,让容器看到独立的PID、网络等
Cgroups 资源限制,控制CPU、内存使用上限
Rootfs 容器的根文件系统
联合文件系统 镜像分层存储(OverlayFS)
runc 容器运行时(实际执行者)

---

二、完整代码实现

1. 基础数据结构

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <sched.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <grp.h>
#include <linux/capability.h>

#define MAX_CONTAINERS 100
#define MAX_CMD_LEN 256
#define MAX_ROOTFS_LEN 512
#define STACK_SIZE (1024 * 1024)

// 容器状态
typedef enum {
CONTAINER_CREATED = 0,
CONTAINER_RUNNING,
CONTAINER_PAUSED,
CONTAINER_STOPPED,
CONTAINER_EXITED
} container_state_t;

// 容器配置
typedef struct container_config {
char name[64];
char rootfs[MAX_ROOTFS_LEN];
char cmd[MAX_CMD_LEN];
char **argv;
int argc;

// 资源限制
int cpu_limit; // CPU核心数
int memory_limit_mb; // 内存限制(MB)

// 隔离配置
int isolate_pid;
int isolate_net;
int isolate_ipc;
int isolate_uts;
int isolate_mount;
int isolate_user;

// 网络配置
char veth_host[32];
char veth_container[32];
char bridge[32];

char hostname[64];
} container_config_t;

// 容器实例
typedef struct container {
char id[64];
container_config_t config;
container_state_t state;
pid_t pid;
int pty_master;
int pty_slave;
time_t start_time;
time_t stop_time;
int exit_code;
struct container *next;
} container_t;

// 容器运行时
typedef struct container_runtime {
container_t *containers;
int container_count;
char data_dir[256];
pthread_mutex_t mutex;
int running;
} container_runtime_t;
```

2. Namespace隔离

```c
// 创建Namespace标志
#define NAMESPACE_FLAGS \
(CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC | \
CLONE_NEWUTS | CLONE_NEWNS | CLONE_NEWUSER)

// 容器进程入口
int container_main(void *arg) {
container_config_t *config = (container_config_t*)arg;

// 设置hostname
if (config->hostname[0]) {
sethostname(config->hostname, strlen(config->hostname));
}

// 挂载proc文件系统
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("tmpfs", "/dev", "tmpfs", 0, NULL);
mount("devpts", "/dev/pts", "devpts", 0, NULL);

// 切换根目录
if (chdir(config->rootfs) != 0) {
perror("chdir");
return 1;
}
if (chroot(config->rootfs) != 0) {
perror("chroot");
return 1;
}

// 执行容器命令
execvp(config->argv[0], config->argv);

perror("execvp");
return 1;
}

// 创建容器进程
pid_t create_container_process(container_config_t *config) {
char *stack = malloc(STACK_SIZE);
if (!stack) return -1;

// 创建子进程(在隔离环境中)
pid_t pid = clone(container_main, stack + STACK_SIZE,
SIGCHLD | NAMESPACE_FLAGS, config);

if (pid < 0) {
perror("clone");
free(stack);
return -1;
}

free(stack);
return pid;
}
```

3. Cgroups资源限制

```c
// Cgroup路径
void cgroup_path(char *path, const char *controller, const char *name) {
snprintf(path, 256, "/sys/fs/cgroup/%s/%s", controller, name);
}

// 创建Cgroup
int cgroup_create(const char *name) {
char path[256];
char controllers[][16] = {"cpu", "memory", "pids"};

for (int i = 0; i < 3; i++) {
cgroup_path(path, controllers[i], name);
if (mkdir(path, 0755) < 0 && errno != EEXIST) {
perror("mkdir cgroup");
return -1;
}
}
return 0;
}

// 设置CPU限制
int cgroup_set_cpu(const char *name, int cpu_limit) {
char path[256];
cgroup_path(path, "cpu", name);

char filepath[512];
snprintf(filepath, sizeof(filepath), "%s/cpu.cfs_quota_us", path);
FILE *fp = fopen(filepath, "w");
if (!fp) return -1;

// 每个CPU核心100000us,乘以核心数
fprintf(fp, "%d", cpu_limit * 100000);
fclose(fp);

// 设置周期
snprintf(filepath, sizeof(filepath), "%s/cpu.cfs_period_us", path);
fp = fopen(filepath, "w");
if (fp) {
fprintf(fp, "100000");
fclose(fp);
}

return 0;
}

// 设置内存限制
int cgroup_set_memory(const char *name, int memory_limit_mb) {
char path[256];
cgroup_path(path, "memory", name);

char filepath[512];
snprintf(filepath, sizeof(filepath), "%s/memory.limit_in_bytes", path);
FILE *fp = fopen(filepath, "w");
if (!fp) return -1;

fprintf(fp, "%d", memory_limit_mb * 1024 * 1024);
fclose(fp);

return 0;
}

// 添加进程到Cgroup
int cgroup_add_process(const char *name, pid_t pid) {
char controllers[][16] = {"cpu", "memory", "pids"};

for (int i = 0; i < 3; i++) {
char path[256], filepath[512];
cgroup_path(path, controllers[i], name);
snprintf(filepath, sizeof(filepath), "%s/cgroup.procs", path);

FILE *fp = fopen(filepath, "w");
if (!fp) return -1;
fprintf(fp, "%d", pid);
fclose(fp);
}

return 0;
}
```

4. 容器管理

```c
// 创建容器运行时
container_runtime_t *runtime_create(const char *data_dir) {
container_runtime_t *r = malloc(sizeof(container_runtime_t));
memset(r, 0, sizeof(container_runtime_t));
strcpy(r->data_dir, data_dir);
r->running = 1;
pthread_mutex_init(&r->mutex, NULL);

mkdir(data_dir, 0755);
printf("[运行时] 初始化完成,数据目录: %s\n", data_dir);
return r;
}

// 生成容器ID
void generate_container_id(char *buf) {
snprintf(buf, 64, "%d-%ld", getpid(), time(NULL));
}

// 创建容器
container_t *runtime_create_container(container_runtime_t *r,
container_config_t *config) {
pthread_mutex_lock(&r->mutex);

container_t *c = malloc(sizeof(container_t));
generate_container_id(c->id);
memcpy(&c->config, config, sizeof(container_config_t));
c->state = CONTAINER_CREATED;
c->pid = 0;
c->start_time = 0;
c->stop_time = 0;
c->exit_code = 0;
c->next = r->containers;
r->containers = c;
r->container_count++;

pthread_mutex_unlock(&r->mutex);
printf("[容器] 创建: %s (%s)\n", c->id, config->name);
return c;
}

// 启动容器
int runtime_start_container(container_runtime_t *r, const char *id) {
pthread_mutex_lock(&r->mutex);

container_t *c = r->containers;
while (c) {
if (strcmp(c->id, id) == 0) break;
c = c->next;
}

if (!c) {
pthread_mutex_unlock(&r->mutex);
return -1;
}

if (c->state == CONTAINER_RUNNING) {
pthread_mutex_unlock(&r->mutex);
return -2;
}

// 创建Cgroup
cgroup_create(c->id);
if (c->config.cpu_limit > 0) {
cgroup_set_cpu(c->id, c->config.cpu_limit);
}
if (c->config.memory_limit_mb > 0) {
cgroup_set_memory(c->id, c->config.memory_limit_mb);
}

// 创建容器进程
pid_t pid = create_container_process(&c->config);
if (pid < 0) {
pthread_mutex_unlock(&r->mutex);
return -3;
}

// 添加到Cgroup
cgroup_add_process(c->id, pid);

c->pid = pid;
c->state = CONTAINER_RUNNING;
c->start_time = time(NULL);

pthread_mutex_unlock(&r->mutex);
printf("[容器] 启动: %s (PID: %d)\n", c->id, pid);
return 0;
}

// 停止容器
int runtime_stop_container(container_runtime_t *r, const char *id, int signal) {
pthread_mutex_lock(&r->mutex);

container_t *c = r->containers;
while (c) {
if (strcmp(c->id, id) == 0) break;
c = c->next;
}

if (!c) {
pthread_mutex_unlock(&r->mutex);
return -1;
}

if (c->state != CONTAINER_RUNNING) {
pthread_mutex_unlock(&r->mutex);
return -2;
}

if (kill(c->pid, signal) < 0) {
pthread_mutex_unlock(&r->mutex);
return -3;
}

c->state = CONTAINER_STOPPED;
c->stop_time = time(NULL);

pthread_mutex_unlock(&r->mutex);
printf("[容器] 停止: %s (信号: %d)\n", c->id, signal);
return 0;
}

// 删除容器
int runtime_remove_container(container_runtime_t *r, const char *id) {
pthread_mutex_lock(&r->mutex);

container_t *c = r->containers;
container_t *prev = NULL;
while (c) {
if (strcmp(c->id, id) == 0) break;
prev = c;
c = c->next;
}

if (!c) {
pthread_mutex_unlock(&r->mutex);
return -1;
}

if (c->state == CONTAINER_RUNNING) {
pthread_mutex_unlock(&r->mutex);
return -2;
}

if (prev) {
prev->next = c->next;
} else {
r->containers = c->next;
}
r->container_count--;

free(c);
pthread_mutex_unlock(&r->mutex);
printf("[容器] 删除: %s\n", id);
return 0;
}
```

5. 联合文件系统(OverlayFS模拟)

```c
// 联合挂载(模拟OverlayFS)
int setup_overlay_rootfs(const char *lower_dir, const char *upper_dir,
const char *work_dir, const char *merged_dir) {
// 创建目录
mkdir(upper_dir, 0755);
mkdir(work_dir, 0755);
mkdir(merged_dir, 0755);

char options[512];
snprintf(options, sizeof(options),
"lowerdir=%s,upperdir=%s,workdir=%s",
lower_dir, upper_dir, work_dir);

if (mount("overlay", merged_dir, "overlay", 0, options) < 0) {
perror("mount overlay");
return -1;
}

printf("[Overlay] 挂载: %s + %s -> %s\n", lower_dir, upper_dir, merged_dir);
return 0;
}

// 镜像拉取(模拟)
int pull_image(const char *image_name, const char *target_dir) {
char path[256];
snprintf(path, sizeof(path), "%s/%s", target_dir, image_name);
mkdir(path, 0755);

// 创建基本rootfs结构
mkdir(path, 0755);
mkdir(path, 0755);
mkdir(path, 0755);
mkdir(path, 0755);
mkdir(path, 0755);

// 创建基本的/etc/hosts
char hosts_path[512];
snprintf(hosts_path, sizeof(hosts_path), "%s/etc/hosts", path);
FILE *fp = fopen(hosts_path, "w");
if (fp) {
fprintf(fp, "127.0.0.1 localhost\n");
fclose(fp);
}

printf("[镜像] 拉取: %s -> %s\n", image_name, path);
return 0;
}
```

6. 测试代码

```c
void test_runtime() {
printf("=== 容器运行时测试 ===\n\n");

container_runtime_t *r = runtime_create("./containers");

// 配置容器
container_config_t config;
memset(&config, 0, sizeof(config));
strcpy(config.name, "test-container");
strcpy(config.rootfs, "./rootfs");
strcpy(config.cmd, "/bin/sh");
config.argv = malloc(sizeof(char*) * 3);
config.argv[0] = "/bin/sh";
config.argv[1] = "-c";
config.argv[2] = "echo 'Hello from container!' && sleep 10";
config.argc = 3;
config.cpu_limit = 1;
config.memory_limit_mb = 256;
strcpy(config.hostname, "container");

// 创建容器
container_t *c = runtime_create_container(r, &config);

// 启动容器
runtime_start_container(r, c->id);

sleep(2);

// 显示状态
printf("\n=== 容器状态 ===\n");
printf("ID: %s\n", c->id);
printf("状态: %d\n", c->state);
printf("PID: %d\n", c->pid);

// 停止容器
sleep(5);
runtime_stop_container(r, c->id, SIGTERM);

// 删除容器
runtime_remove_container(r, c->id);

free(config.argv);
free(r);
}

int main() {
test_runtime();
return 0;
}
```

---

三、编译和运行

```bash
gcc -o runtime runtime.c -lpthread
./runtime
```

---

四、Docker vs 本实现

特性 本实现 Docker
Namespace隔离 ✅ ✅
Cgroups限制 ✅ ✅
联合文件系统 模拟 OverlayFS
容器生命周期 基础 完整
镜像管理 基础 完整
网络管理 无 Bridge/Host/Overlay
镜像仓库 无 Docker Hub

---

五、总结

通过这篇文章,你学会了:

· 容器的核心技术(Namespace + Cgroups)
· 进程隔离实现
· 资源限制(CPU/内存)
· 根文件系统切换
· 容器生命周期管理

容器运行时是云原生的基石。掌握它,你就理解了Docker、Podman、CRI的底层设计。

下一篇预告:《从零实现一个Kubernetes调度器:Pod调度与资源分配》

---

评论区分享一下你对容器技术的理解~

相关新闻

  • 城市美学视角:科技融于山水,叁仟智慧灯杆重塑杭州夜间城市风貌
  • 触觉引导模型选型指南:环境适配四维解构法
  • 批量生成文章的字数失控与无配图问题,我的临时 workaround

最新新闻

  • VMware扩展虚拟机磁盘大小一键命令
  • 「 简记往来」第二十六篇:llms.txt——2026年官网新标配
  • Java计算机毕设之基于 SpringBoot+Vue 的智慧养老院服务管理系统的设计与实现 基于前后端分离的养老机构综合管理系统(完整前后端代码+说明文档+LW,调试定制等)
  • 软考中高级备考避坑指南|十四年机构真实通过率与高效上岸方案
  • Linux Shell全面学习实操总结
  • 如何免费高效下载全网音乐:开源工具MusicDownload完整指南

日新闻

  • Android逆向分析全能助手:集成化工具链与自动化工作流设计
  • 面搜索(Faceted Search)原理与工程实践指南
  • 神经网络调参避坑指南:从5个常见Loss曲线形态定位超参数问题

周新闻

  • 基于YOLOv12的番茄成熟度智能检测系统开发
  • 终极RimWorld模组管理指南:用RimSort告别模组冲突烦恼
  • AI Agent框架开发:从理论到实践的完整指南

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号