从bocker学懂Linux容器本质:命名空间与cgroups从零到一完全指南
2026/9/19 5:27:55 网站建设 项目流程

从bocker学懂Linux容器本质:命名空间与cgroups从零到一完全指南

【免费下载链接】bockerDocker implemented in around 100 lines of bash项目地址: https://gitcode.com/gh_mirrors/bo/bocker

bocker 是一个仅用约 100 行 bash 脚本就实现 Docker 核心能力(镜像拉取、容器运行、日志、提交)的极简项目。它把 Docker 的黑盒拆开给你看:Linux 容器的全部本质,就是命名空间(namespaces)负责"看不见邻居"cgroups 负责"用不完资源",再加一个 chroot 提供的独立文件系统。读懂这一个脚本,你就真正懂了容器原理。🧩

为什么100行脚本能写出"Docker"?

很多人以为 Docker 很神秘,其实它站在三个 Linux 内核特性之上:

内核特性作用bocker 中对应代码
命名空间隔离进程、网络、PID、挂载视图unshare -fmuip
cgroups限制 CPU、内存等资源cgcreate/cgset/cgexec
根文件系统切换让容器"活"在自己的目录里chroot

Docker 做了引擎、镜像仓库、网络插件等大量工程工作;而 bocker 只用 bocker 一个脚本就把"跑一个隔离容器"的最小闭环完整走了一遍——这正是学习容器原理的最佳路径。💡

快速准备:一键搭好实验环境

bocker 需要 root 权限、btrfs 文件系统和一块叫bridge0的网桥。作者贴心地提供了 Vagrantfile,克隆仓库后执行vagrant up即可自动完成全部配置:

git clone https://gitcode.com/gh_mirrors/bo/bocker cd bocker && vagrant up

Vagrantfile 中的关键动作值得留意:创建 btrfs 卷挂载到/var/bocker(存放镜像与容器快照)、开启 IP 转发、用 iptables 给网桥做 MASQUERADE 出网、创建bridge0(IP 为10.0.0.1/24)。这些正是 README.md "Prerequisites" 一节列出的前置条件。

⚠️ bocker 以 root 运行且会改动网络接口与防火墙规则,官方建议务必在虚拟机中折腾,别在主力机上直接跑。

命名空间实操:bocker run 的隔离魔法

运行容器的核心逻辑在 bocker 的bocker_run函数里。最精华的是这一段隔离链(bocker):

cgexec -g "cpu,cpuacct,memory:$uuid" \ ip netns exec netns_"$uuid" \ unshare -fmuip --mount-proc \ chroot "$btrfs_path/$uuid" \ /bin/sh -c "/bin/mount -t proc proc /proc && $cmd"

一条命令链,层层递进,我们逐个拆解。

H3-拆解 unshare -fmuip:五种命名空间一次到位

unshare的每个字母对应一种命名空间,这是容器隔离的全部家底:

  • u(user):独立用户视图
  • m(mount):独立挂载表,容器内挂载不影响宿主机
  • p(pid):独立 PID 空间——容器里的进程自认为是 1 号进程
  • i(ipc):独立进程间通信资源
  • f(fork):立即 fork 子进程进入新空间,因为已有进程无法"迁入"命名空间
  • -n(network):独立网络栈(bocker 用ip netns exec预建好网络空间后再接管)

--mount-proc会自动为新 PID 空间挂一个专属 /proc,让容器内看到的进程列表只有自己一家人——这就是"隔离"最直观的体验。

H3-网络命名空间:veth 对 + 网桥,容器如何上网

网络部分在 bocker:为每个容器创建一对 veth 虚拟网卡,一头挂到宿主机网桥bridge0,另一头塞进容器的网络命名空间netns_xxx;然后容器内配置 IP(10.0.0.x/24)、默认网关指向10.0.0.1。再叠加 iptables 的 MASQUERADE,容器流量经网桥做地址转换直达外网——这套"veth + bridge + NAT"正是 Docker 默认 bridge 网络的原型。tests/test_run 里ping 8.8.8.8与 DNS 解析两条断言,验证的就是这条通路。

cgroups实操:给容器套上资源枷锁

隔离解决"看不见",限流解决"抢不过"。cgroups 部分在 bocker:

  1. cgcreate创建 cgroup 组(cpu、cpuacct、memory 三层同时)
  2. cgset写入cpu.shares(CPU 权重)与memory.limit_in_bytes(内存上限)
  3. cgexec让容器进程带着这些限制启动

默认 CPU 权重 512、内存上限 512MB,可用环境变量临时调整。在容器内cat /proc/1/cgroup,你会看到自己挂在memory:/ps_xxxcpu,cpuacct:/ps_xxx下;宿主机上cat /sys/fs/cgroup/memory/ps_xxx/memory.limit_in_bytes则直接读到字节数。这正是docker run --cpus --memory背后的全部真相。✅

镜像、快照与提交:分层存储的最简实现

bocker 的镜像不是 tar 包,而是btrfs 子卷

  • bocker init / 拉取镜像→ 创建一个img_xxx子卷
  • bocker run→ 用btrfs subvolume snapshot秒级复制出ps_xxx容器卷(写时复制,几乎零开销)
  • bocker commit→ 把容器子卷再快照回镜像(见 bocker)

"容器=镜像的快照"——一句话点破 Docker 镜像分层的思想内核。想系统验证所有命令行为,运行仓库自带测试入口 test 即可,它会依次跑 tests/test_run、tests/test_pull、tests/test_exec 等用例。

常见疑问快答

容器和虚拟机有什么区别?虚拟机隔离的是硬件(靠 Hypervisor),容器隔离的是操作系统视图(靠内核命名空间+cgroups),所以容器启动是毫秒级、开销极小,但也共享同一个内核。

怎么进入运行中的容器?看 bocker 的bocker_execnsenter -t <pid> -m -u -i -n -p以目标进程的五个命名空间身份进入——nsenterunshare是一对姐妹工具,一个用于"进入",一个用于"创建"。

为什么 PID 1 很特别?新 PID 命名空间中的第一个进程会成为 init 角色(不产生僵尸进程),bocker 中容器主进程就是 1 号进程,tests/test_run 用cat /proc/self/stat断言了这一点。

动手清单:从零到一验证你的容器知识

按顺序执行并观察输出,你就完成了"容器原理"的闭环:

  1. vagrant up起环境 →bocker pull centos 7拉镜像
  2. bocker run img_xxx uname跑一个容器,再在容器内cat /proc/1/cgroup
  3. 在宿主机ls /sys/fs/cgroup/memory/找到容器组,读取memory.limit_in_bytes
  4. ip link show观察 veth 对,ip netns list观察命名空间
  5. BOCKER_CPU_SHARE=1024 BOCKER_MEM_LIMIT=1024 bocker run ...验证资源参数生效

跑通这 5 步,再看 Docker 源码或文档时你会发现:所谓容器引擎,不过是把 unshare、cgroups、chroot、快照这些内核能力编排得优雅些而已。🎯

【免费下载链接】bockerDocker implemented in around 100 lines of bash项目地址: https://gitcode.com/gh_mirrors/bo/bocker

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询