从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 upVagrantfile 中的关键动作值得留意:创建 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:
cgcreate创建 cgroup 组(cpu、cpuacct、memory 三层同时)cgset写入cpu.shares(CPU 权重)与memory.limit_in_bytes(内存上限)cgexec让容器进程带着这些限制启动
默认 CPU 权重 512、内存上限 512MB,可用环境变量临时调整。在容器内cat /proc/1/cgroup,你会看到自己挂在memory:/ps_xxx、cpu,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_exec:nsenter -t <pid> -m -u -i -n -p以目标进程的五个命名空间身份进入——nsenter与unshare是一对姐妹工具,一个用于"进入",一个用于"创建"。
为什么 PID 1 很特别?新 PID 命名空间中的第一个进程会成为 init 角色(不产生僵尸进程),bocker 中容器主进程就是 1 号进程,tests/test_run 用cat /proc/self/stat断言了这一点。
动手清单:从零到一验证你的容器知识
按顺序执行并观察输出,你就完成了"容器原理"的闭环:
vagrant up起环境 →bocker pull centos 7拉镜像bocker run img_xxx uname跑一个容器,再在容器内cat /proc/1/cgroup- 在宿主机
ls /sys/fs/cgroup/memory/找到容器组,读取memory.limit_in_bytes ip link show观察 veth 对,ip netns list观察命名空间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),仅供参考