Skip to content

Siaospeed/UContainer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📦 UContainer

C++20 License Platform

一个用 C++20 从零实现的轻量级 Linux 容器运行时,不依赖 Docker 或任何容器框架。UContainer 直接使用 Linux 内核机制实现了现代容器技术的核心:命名空间隔离、cgroup 资源控制、OverlayFS 分层文件系统以及虚拟网络。

✨ 功能特性

  • 命名空间隔离 — 通过 clone() 实现 UTS、PID、Mount、Network 命名空间隔离
  • OverlayFS 文件系统 — 共享只读基础镜像 + 每个容器独立的可写层,与 Docker 镜像层机制完全一致
  • cgroup v2 内存限制 — 通过 cgroup v2 层级结构由内核强制执行内存上限
  • 双栈虚拟网络 — 每个容器独立的 veth pair,通过 iptables/ip6tables 实现 IPv4 和 IPv6 NAT
  • 交互式 PTY Shell — 完整的伪终端支持,基于 epoll 的 I/O 多路复用
  • Alpine 基础镜像自动管理 — 首次运行时自动下载并解压 Alpine Linux minirootfs,所有容器共享同一份基础镜像
  • DNS 注入 — 读取宿主机 resolv.conf,过滤本地回环 DNS 存根,自动回退到公共解析器
  • 容器重置 — 丢弃容器可写层,保留共享基础镜像不变

⚛️ 运行依赖

  • Linux 内核 5.2+(cgroup v2)
  • Root 权限(clone() 命名空间标志、mountpivot_root 均需要)
  • 宿主机已安装:wgettaripiptablesip6tablesnsenter
  • CMake 3.25+,支持 C++20 的编译器(GCC 12+ 或 Clang 14+)

🛠️ 构建

# 1. 克隆代码
git clone https://github.com/Siaospeed/UContainer
cd ucontainer

# 2. 编译构建
mkdir build && cd build
cmake ..
make -j$(nproc)

📋 使用方法

# 在容器中运行交互式 Shell
sudo ./ucontainer run <container_id>

# 运行指定命令
sudo ./ucontainer run <container_id> /bin/sh -c "echo hello"

# 设置内存限制(支持 K、M、G 后缀)
sudo ./ucontainer run --memory 128M <container_id>

# 重置容器可写层
sudo ./ucontainer reset <container_id> force

容器 ID 由字母、数字、_- 组成,最长 64 个字符。每个容器在 /var/lib/ucontainer/ 下拥有独立的目录。

⚙️ 实现原理

进程隔离

UContainer 使用 clone() 并传入 CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET 标志,在隔离的命名空间中创建子进程。调用时需要手动分配并传入栈内存,默认大小为 8 MiB。需要注意的是,CLONE_NEWNET 会在内核中初始化一套完整的网络协议栈、路由表和 loopback 接口,其栈消耗远高于其他命名空间类型,栈空间不足时会导致不可预期的崩溃。

文件系统 — OverlayFS

UContainer 不为每个容器复制一份完整的基础镜像,而是使用 OverlayFS 联合挂载:

/var/lib/ucontainer/
├── images/
│   └── alpine-3.19/        ← 所有容器共享的只读下层(lower layer)
└── u_<container_id>/
    ├── upper/              ← 容器私有的可写层
    ├── work/               ← OverlayFS 内部使用
    └── merged/             ← 联合挂载点,pivot_root 的目标

基础镜像只需解压一次,所有容器共享。容器内的所有写操作都落在自己的 upper/ 目录中。删除容器只会移除 upper/ 层,基础镜像完全不受影响。这与 Docker 镜像分层机制的本质相同。

OverlayFS 挂载完成后,通过 pivot_root 将容器根目录切换到 merged/,随后用 MNT_DETACH 卸载原宿主机根目录,容器因此获得完全隔离的文件系统视图。

资源控制 — cgroup v2

每个容器在 /sys/fs/cgroup/ucontainer/<container_id>/ 下拥有独立的 cgroup 节点。根据 cgroup v2 的委托模型,必须先向父节点的 cgroup.subtree_control 写入 +memory +pids 开启控制器,再创建子目录——顺序颠倒会导致子 cgroup 中的 memory.max 写入失败。clone() 返回子进程 PID 后,在容器开始执行用户代码之前,将其加入对应的 cgroup。

网络

UContainer 为每个容器创建一对 veth:

  • vethuc0_<id> 留在宿主机,分配网关 IP
  • vethuc1_<id> 移入容器网络命名空间,重命名为 eth0

同时配置 IPv4(10.85.86.0/24)和 IPv6(fc00:8586::/64)双栈地址。通过 iptables/ip6tables MASQUERADE 规则实现出站 NAT。UContainerNetwork 的析构函数负责在容器退出时清理 veth pair 和 NAT 规则。

PTY 与终端处理

clone() 之前调用 openpty() 创建主从伪终端对。slave fd 传入容器进程,通过 TIOCSCTTY 设为其控制终端。宿主侧使用 epoll 同时监听 stdin→master 和 master→stdout,在两个方向上透传原始字节流。TerminalStateGuard(RAII)在容器运行期间将宿主终端切换为 raw 模式,并在退出时(包括异常退出)可靠地恢复原始状态。

📂 项目结构

ucontainer
├── include/
│   ├── cgroup.h               # cgroup v2 RAII 守卫 + ApplyLimits()
│   ├── terminal_state_guard.h # RAII 终端 raw 模式切换器
│   ├── ucontainer.h           # 顶层协调器
│   ├── ucontainer_config.h    # 配置结构体 + ParseArgs()
│   ├── ucontainer_network.h   # veth + iptables 生命周期管理
│   ├── ucontainer_process.h   # clone/exec/PTY/wait
│   ├── utils.h                # 日志宏、校验工具函数
│   └── third_party/CLI11/     # 纯头文件命令行参数解析库
└── src/
    ├── main.cc
    ├── ucontainer_config.cc
    ├── core/
    │   ├── ucontainer.cc
    │   ├── ucontainer_process.cc
    │   ├── ucontainer_network.cc
    │   └── cgroup.cc
    └── utils/
        └── utils.cc

▶️ 设计说明

全面使用 RAII。 CgroupGuardUContainerNetworkTerminalStateGuard 均在析构函数中清理各自持有的资源,主流程中没有任何手动清理代码。

两阶段进程启动。 UContainerProcess::Spawn() 负责调用 clone() 并返回子进程 PID;UContainerProcess::Attach() 接管 PTY 并调用 waitpid()。这种拆分使 UContainer::Run() 可以在两个阶段之间插入 cgroup 和网络配置——此时子进程已存在但尚未开始交互执行。

Config 由 UContainer 统一持有。 UContainerProcessUContainerNetwork 均持有 const UContainerConfig&。C++ 保证成员按声明顺序构造、逆序析构,config_ 声明在最前面,其生命周期覆盖所有其他成员,引用安全性有语言层面的保证。

📊 已知局限

  • 同时只能运行一个容器(固定 IP/子网段,并发运行会冲突)
  • 仅支持 x86-64 Alpine Linux
  • 资源限制仅有内存,尚无 CPU 配额和 PID 数量限制
  • 不支持容器暂停/恢复或检查点
  • 需要 root 权限,不支持 rootless 模式

🤝 贡献与协议

本项目采用 Apache License 2.0 协议开源。

你可以自由使用、修改、分发本项目,但必须:

  • 保留原作者署名 (Siaospeed)
  • 在引用时注明原项目来源

Copyright 2026 Siaospeed

欢迎提交 Issue 或 Pull Request。

About

A Linux container runtime built from scratch in C++20 — namespaces, OverlayFS, cgroup v2, and dual-stack networking without Docker or any container framework.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors