尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

从 chroot 到 LXC:四代容器隔离技术演进,Namespace 与 Cgroups 原理拆解

发布时间:2026/9/2 5:38:09

资讯中心
01
ARTICLE

从 chroot 到 LXC:四代容器隔离技术演进,Namespace 与 Cgroups 原理拆解

从 chroot 到 LXC:四代容器隔离技术演进,Namespace 与 Cgroups 原理拆解
摘要容器隔离能力不是 Docker 发明的——chroot、FreeBSD Jails、Linux VServer/OpenVZ 到 LXC 四代技术逐步补齐了文件系统、进程集合、资源分区与内核视图四层隔离。本文按演进顺序拆解每代技术的隔离机制与边界最后讲透 Namespace 与 Cgroups 的内核分工帮助你真正看懂容器是什么。关键词chrootFreeBSD JailsOpenVZLXCNamespaceCgroups容器隔离Linux 内核排查线上问题时你有没有遇到过这几个现象在 Pod 里执行ps看到进程 PID 是从 1 开始的和宿主机top里的进程号对不上两个容器同时监听 8080 端口居然不冲突一个容器把内存吃满被杀的是容器里的进程宿主机其他进程毫发无损容器里hostname和宿主机完全不一样但df -h看到的文件系统和宿主机又有点像。这些现象背后是两套内核机制Namespace 决定进程看得见什么Cgroups 决定进程用得了多少。但这两套机制并不是 Docker 发明的甚至不是 LXC 发明的——它们是从 1979 年的 chroot 开始一代一代演进出来的。很多用 Docker、K8s 的工程师把容器当黑盒出问题了就重启资源被抢了就加 limit。这篇不聊 Docker 怎么用把容器隔离的祖宗们从头捋一遍讲清楚每一代解决了什么问题、留下了什么边界。理解了这些K8s 的 requests/limits、Pod 的 PID 视图、JVM 容器内存参数才不再是玄学。一、Chroot一切的开端1979chroot 是 Unix 系统调用作用很直接改变正在运行的进程及其子进程的根目录。原理修改 PCB 实现限制功能chroot 的实现并不神秘。Linux 里每个进程的fs_struct结构体维护了两个路径指针root根目录和pwd当前工作目录。chroot 系统调用就是把进程的root指针替换成新的路径之后这个进程的所有路径解析/etc/passwd、/usr/lib/...都从新根开始。// 内核 fs_struct 的核心字段简化structfs_struct{structpathroot;// 进程看到的 / 指向哪里structpathpwd;// 当前工作目录// ...};被 chroot 设置根目录的程序不能访问、读取、写操作指定根目录之外的文件——不是权限不够而是它的路径解析根本到不了外面。实际用一下# 准备一个最小根目录目录结构 静态编译的 busyboxmkdir-p/tmp/jail/{bin,etc}cp/bin/busybox /tmp/jail/bin/# 进入新根/bin/busybox 是静态链接的不依赖 /lib 动态库chroot/tmp/jail /bin/busyboxsh有个关键细节必须用静态编译的 busybox。如果你 cp 一个动态链接的/bin/bash进去它会因为找不到/lib/x86_64-linux-gnu/下的动态库而直接报No such file or directory。静态链接把整个解释器和库都打进二进制里才不依赖宿主机的/lib——这也是后来容器镜像只打包二进制 依赖库思路的雏形。chroot 的坑不改变当前工作目录。chroot之后如果不chdir到新根目录进程的工作目录还在旧文件系统里依然能访问旧路径。所以标准用法是先chdir(/)再chroot(/)。经典逃逸。如果进程是 root 权限可以在新根里mknod创建一个块设备节点直接访问宿主机磁盘# 在 chroot 环境内root 权限下创建设备节点访问宿主机磁盘mknod/tmp/sda b80ddif/tmp/sdaof/tmp/leakbs512count1chroot 之后还能chdir逃出根目录先 cd 到新根外再 chroot 也是经典逃逸路径。所以chroot 从来不是安全边界它只是一个路径视图的欺骗。无法限制 CPU、内存、网络端口号。chroot 环境里的进程和宿主机进程完全共享 CPU、内存和网络栈一个进程bind了 8080另一个进程就绑不了。判断chroot 隔离了文件系统视图仅此而已。但它确立了一个重要思想不虚拟化硬件只虚拟化进程的视角——这正是容器和虚拟机的分水岭。二、FreeBSD Jails从单进程到进程集合2000chroot 隔离的是单个进程太单薄。2000 年 FreeBSD 4.0 引入 Jails基于 chroot 的操作系统层虚拟化技术jail 内的进程只能访问部分文件系统且不能影响操作系统的其他部分。解决了什么虚拟化每个 jail 是一组进程 独立 IP 独立主机名看起来像一台独立的小主机安全性jail 内进程被限制无法影响系统其他部分这是对 chroot进程级隔离的升级变成环境级隔离易维护相比完整虚拟机jail 复用宿主内核创建销毁都轻量。代价使用复杂配置一个 jail 需要手工设置 IP、挂载点、用户映射运维门槛比虚拟机还高隔离级别较弱jail 内仍是 FreeBSD 内核内核漏洞会直接影响所有 jailjail 之间的资源CPU/内存也没有硬配额。Jails 是第一个把进程集合 网络身份打包隔离的实践但它绑定 FreeBSD没能进入 Linux 生态。Linux 生态等来了自己的方案。三、Linux VServer / OpenVZ内核补丁式虚拟化2003Linux VServer 和 OpenVZ 是同一思路的两个实现类似 Jails 机制可以对计算机系统上的资源文件系统、网络地址、内存进行分区。它们以Linux 内核补丁的形式实现虚拟化、隔离、资源管理和状态检查。能力与代价资源隔离性支持 CPU 超卖多个容器共享 CPU按权重分配、内存共享内存可以超额分配靠换页兜底——这是 VPS 行业黄金时代的技术底座隔离级别较弱和 Jails 一样容器内进程共享内核无独立内核视图没有 PID 隔离、没有独立挂载表。历史遗留问题OpenVZ 的容器需要运行在打了专用补丁的内核上这意味着宿主机不能用主线内核内核升级要等 OpenVZ 团队适配。用过 OpenVZ VPS 的应该记得想升级内核版本基本不可能只能等商家。这也是它最终被 LXC 生态取代的原因之一。顺带一提2010 年代初很多人租到的便宜 VPS 其实就是 OpenVZ 容器——/proc/user_beancounters这个文件就是 OpenVZ 的资源记账接口看到它说明你在一台 OpenVZ 容器里。四、LXC现代容器的雏形20082008 年 LXCLinux Containers出现它把前几代的思路收敛成一套干净的机制使用内核控制组cgroups和内核命名空间namespace隔离轻量级地同时运行多个虚拟单元。优势通过容器隔离应用程序和操作系统每个容器有独立的 PID、挂载、网络、UTS、IPC、User 视图看起来是一台独立的 Linux实时管理资源分配近乎原生性能容器进程就是宿主机内核上的普通进程没有硬件模拟、没有 guest OS系统调用直通内核性能损耗接近零通过 cgroups 控制网络接口和容器内的资源CPU 份额、内存上限、块设备 IO、网络带宽都可以按容器粒度限制。缺陷至今仍是容器的边界所有 LXC 容器使用相同的内核容器里uname -r看到的永远是宿主机的内核版本只能在 Linux 操作系统运行因为依赖 Linux 内核的 namespace/cgroups 原语LXC 并不安全安全性取决于主机系统共享内核意味着内核漏洞如脏牛 Dirty COW一旦被利用容器隔离形同虚设。# LXC 的典型使用Ubuntu/Debian 示例sudoaptinstalllxcsudolxc-create-napp01-tdownload ---dubuntu-r22.04-aamd64sudolxc-start-napp01sudolxc-attach-napp01# 进入容器类似 docker exec# 容器里看到的内核版本和宿主机一致——这就是共享内核的直接证据lxc-attach-napp01 --uname-rLXC 首次把隔离视图与资源限制两条主线合并进主流内核实现成为现代容器的雏形。Docker 早期的 runtime 就是直接调用 lxc-start 的后来才换成了自研的 libcontainer再后来演进为 runc。五、两大基石Namespace 与 CgroupsLXC 的整套能力建立在两个内核原语上。分开拆。5.1 Namespace内核全局资源的封装Namespace 是对内核全局资源的封装每个 namespace 是一份独立的资源不同进程在各自 namespace 中对同一种资源的使用互不干扰。六类常用 namespaceNamespace隔离的资源工程影响PID进程号容器内 PID 从 1 开始ps只见本容器进程树Mount挂载点容器有独立根文件系统与挂载视图chroot 的超集Network网络栈独立 IP/端口/路由/iptables端口不再冲突UTS主机名与域名容器内hostname独立IPC消息队列/共享内存/信号量容器间进程间通信互不可见User用户 ID容器内 root 可映射为宿主机非特权用户在命令行里可以直接观察# 查看当前进程属于哪些 namespace每个都有独立的 inode 编号ls-l/proc/self/ns/# 输出示例:# lrwxrwxrwx ... ipc - ipc:[4026531839]# lrwxrwxrwx ... mnt - mnt:[4026531841]# lrwxrwxrwx ... net - net:[4026531992]# lrwxrwxrwx ... pid - pid:[4026531836]# 新建一个 Network namespace 并查看里面的网络视图unshare-nbashipaddr# 只剩 lo 回环没有 eth0 —— 独立的网络栈unshare -n bash之后你会发现ip addr里只有lo这就是新 namespace 里资源是独立的一份最直观的证明。5.2 Cgroups一组进程的资源限制Cgroups 用于限制和隔离一组进程对系统资源的使用对不同资源的具体管理由各个子系统分工完成。子系统管理内容cpuCPU 时间片权重shares与上限quotamemory内存限额超限触发 OOM 回收blkio块设备读写带宽与 IOPSnet_cls / net_prio网络流量分类标记与优先级devices设备节点访问控制GPU 挂载靠它放行pids进程/线程数上限防 fork 炸弹# cgroup 文件系统在 /sys/fs/cgroup 下按控制器分目录cat/sys/fs/cgroup/cpu/cpu.shares# CPU 权重默认 1024cat/sys/fs/cgroup/memory/memory.limit_in_bytes# 内存上限# docker 的 --cpus / --memory 参数最终就落到这些文件上dockerrun--cpus2--memory1g my-image# 等价于在容器的 cgroup 目录写入# cpu.cfs_quota_us / cpu.cfs_period_us 200000 / 100000# memory.limit_in_bytes 1073741824两个真实坑坑一JVM 不感知 cgroup。JDK 8u131 之前JVM 的-Xmx默认按宿主机内存计算——在一台 128G 的机器上容器--memory1gJVM 默认堆却能冲到 32G直接 OOM 被杀。而且被杀的还是容器内进程日志难查。解法是显式设置-Xmx或用 JDK 10 的-XX:MaxRAMPercentage75它按 cgroup 限额计算。Java 工程师排查容器 OOM 的第一课就是它。坑二pids.max 撞上线程池。如果一个应用比如 Spark Executor 或者高并发网关每请求开线程pids 控制器的pids.max会先于内存把容器卡死现象是fork: Cannot allocate memory但free -m内存还有富余。遇到这种报错先查/sys/fs/cgroup/pids/pids.max别盯着内存。六、演进脉络四代技术的边界与个人判断四代技术的隔离能力对比一句话概括Chroot1979只隔离文件系统视图限制不了 CPU、内存、网络FreeBSD Jails2000隔离进程集合与网络身份但绑定 FreeBSD、配置复杂、隔离弱Linux VServer / OpenVZ2003在 Linux 上做文件系统/网络/内存分区支持 CPU 超卖与内存共享但依赖专用内核补丁、隔离弱LXC2008用 namespace cgroups 双支柱把可见性隔离和资源配额统一进主线内核成为现代容器雏形。我的三个判断第一学容器要从 namespace/cgroups 学起而不是从 Docker 学起。Docker/K8s 是产品层namespace/cgroups 是内核层。搞懂了unshare和/sys/fs/cgroupK8s 的 requests/limits 就变成了写配置文件的琐事而不是玄学。排查 Pod 被 OOMKilled、CPU throttling最终都要回到这两套原语。第二共享内核是容器隔离强度的天花板安全边界要靠组合拳补。LXC 时代就承认容器并不安全安全性取决于主机。现代容器加了 user namespace容器内 root 映射为非特权用户、seccomp限制系统调用、capabilities最小特权、AppArmor/SELinux本质都是在补共享内核的短板。任何容器等于虚拟机的宣传都不可信。第三AI 场景的容器化要单独算账。GPU 容器的本质是 devices cgroup 放行 GPU 设备 NVIDIA Container Toolkit 注入驱动库大模型推理的显存是硬配额--memory管不到显存OOM 会直接杀进程。另外 AI 训练任务的 IO 往往是瓶颈blkio 的配额设置不好几个训练任务抢磁盘带宽整机吞吐都会塌——这比 CPU/内存问题隐蔽得多。容器技术演进 40 余年核心就一句话不虚拟化硬件只虚拟化进程的视角和预算。视角由 Namespace 给预算由 Cgroups 给两者都出自 Linux 内核本身——这才是容器轻量、快速、普及的根本原因。下一篇可以接着聊 Docker 的 runtime 演进lxc → libcontainer → runc以及镜像层是怎么构建的欢迎持续关注。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。