你有没有过这种经历:服务器上Docker用得飞起,容器起了一个又一个,突然被人问了一句"docker run 之后到底发生了什么",你愣了半天。再追问"容器和虚拟机最本质的差别是什么",很多人就答不上来了。我当年就是这种状态,直到把LXC翻了个底朝天,那层窗户纸才算彻底捅破。
这篇想聊的LXC(Linux Containers),正是Linux内核容器能力最早的、也是最直接的封装。2013年Docker第一个版本发布时,底层默认的执行引擎就是LXC,虽然后来Docker换成了自家的libcontainer(也就是今天runC的前身),但镜像分层、命名空间隔离、资源限制这些今天大家都在用的核心设计,几乎都能在LXC时代找到源头。所以说LXC是"Linux容器基石",一点都不夸张。
这篇文章适合两类人:一类是Docker用了很久、想真正搞清楚容器底层原理的;另一类是打算在无Docker环境、嵌入式Linux或者最小化服务器上做轻量级资源隔离,需要直接上手LXC的。我会从原理讲到实操,再聊到生产环境里那些文档不会明确写的坑,整个过程以Ubuntu/Debian系为例,命令可以直接复制去验证。
1. LXC是什么:先弄清楚"容器"这个词被用烂了
很多人第一次听到LXC,第一反应是"这不就是Docker吗"或者"这不是过时技术吗"——两种理解都有偏差。LXC本身是一个"操作系统级虚拟化"方案,它直接复用Linux内核提供的隔离机制,在一台宿主机上运行多个相互隔离的Linux用户空间实例。这个用户空间实例有自己独立的进程视图、网络栈、文件系统挂载点,看起来像一台独立的Linux机器,但它没有自己的内核,用的是宿主机的内核。
1.1 从chroot到LXC:容器技术的三次进化
这事儿得从根上讲。最早的隔离手段是chroot,它的作用简单粗暴:把某个进程的根目录锁定到一个指定目录里,让进程看不到目录以外的文件。但chroot只是改了文件系统视角,进程列表、网络端口、系统用户这些仍然是全局共享的,一个进程照样可以ptrace同宿主机的其他进程,隔离等于没有。
后来出现了OpenVZ和Solaris Zones这些商业级方案,才真正开始做内核级隔离,但它们需要修改内核或者依赖特定平台,没法在普通发行版上开箱即用。LXC的价值在于:它把内核原生的namespace和cgroup组合起来,用纯用户态工具就能实现"类似轻量虚拟机"的效果。LXC的核心组件包括一组命令行工具(lxc-create、lxc-start、lxc-attach等)、一系列模板脚本,再加上内核的namespace、cgroup等机制。
用一句话概括进化路径:chroot只骗过了文件系统,namespace骗过了进程看到的整个内核视图,cgroup则保证被骗进去的进程不会抢光宿主机所有资源。
1.2 LXC、LXD、Docker、runC:一堆名字到底什么关系
这里面的技术名词太多,我先把关系捋顺。
- LXC:提供容器运行时能力的用户态工具集,包括创建、启动、停止、删除容器等命令,可以理解成"操作容器的工具箱"。
- LXD:Canonical(Ubuntu背后的公司)主导开发的LXC的"下一代管理框架",它建立在LXC之上,增加了daemon进程、REST API、存储池、快照、迁移等能力,定位更像是"容器管理平台"。
- Docker:面向应用分发的容器平台,强调镜像、分层、应用打包和标准化交付,早期底层用LXC,后来换成自研的libcontainer。
- runC:从libcontainer演进而来的OCI(Open Container Initiative)标准运行时,是Docker、Podman等工具的底层执行器。
有朋友会问:既然有了Docker,为什么还要关注LXC?我的理解是:Docker解决的是"应用怎么打包、怎么分发",LXC解决的是"多个Linux环境怎么在同一台机器上隔离共存"。前者以应用为中心,后者以系统为中心。生产环境里两种场景都有,比如我要模拟三台服务器做集群测试,用LXC比用Docker更贴近"整机"的感觉——容器里有完整的init进程,可以像操作独立服务器一样systemctl start ssh等操作。这是LXC的核心场景,也是它今天依然有价值的原因。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 隔离的秘密:namespace与cgroup到底做了什么
LXC能"骗"过容器里的进程,让它们以为自己在独立机器上,核心靠的是namespace;而能保证多个容器和平共处、不互相争抢资源,靠的是cgroup。这两样东西是LXC的命根子。
2.1 六类namespace分别管什么
Linux内核的namespace机制简单说就是:给一组进程提供"系统资源的独立视图"。目前LXC涉及的namespace主要有六类,每类管一个方面:
- Mount namespace:隔离挂载点。容器里的进程看到的文件系统挂载列表是独立的,挂载/卸载操作不影响宿主机和其他容器。
- PID namespace:隔离进程号。容器里的第一个进程PID是1,容器里看不到宿主机的进程,宿主机能看到容器内的全部进程。
- Network namespace:隔离网络栈。每个容器有自己的网卡、IP地址、路由表、iptables规则。
- UTS namespace:隔离主机名和域名。容器里执行hostname,改的就是自己那台"机器"的名字。
- IPC namespace:隔离进程间通信资源,比如System V信号量、消息队列。
- User namespace:隔离用户ID和组ID。容器里的root(UID 0)映射到宿主机上一个普通用户,这是提升安全性的关键设计。
这些namespace之间是正交的,可以单独启用。LXC创建容器时,默认会把它们全部启用。你可以做个小实验验证:进入容器后执行ps -ef,看到的进程列表非常短,最多几个进程;在宿主机上执行ps -ef,则能看到容器里的那些进程,只是它们的PID是宿主机视角的另一个值。一个进程两套PID,这就是namespace在起作用。
2.2 cgroup:让一个容器不至于吃掉整台机器
namespace解决了"看不看得见"的问题,cgroup解决的是"能用多少"的问题。cgroup的全称是控制组(Control Group),它把一组进程圈起来,对它们做资源配额限制、统计和控制。LXC里的cgroup配置通常长这样:
code复制lxc.cgroup2.memory.max = 512M
lxc.cgroup2.cpu.max = 50000 100000
第二行表示CPU配额:100000是周期(微秒,也就是100ms),50000表示在这个周期内最多跑50ms,换算过来就是最多用0.5个CPU核心。memory.max则直接限制内存上限为512MB。有了这层限制,某个容器里跑出死循环或者内存泄漏,撑死的只会是它自己,不会拖垮整台宿主机。
在展开这个话题时我多说一句:早期cgroup分v1和v2两个大版本,v2把接口统一到/sys/fs/cgroup下,LXC 4.0之后就全面支持cgroup v2了。你在新系统上看到lxc.cgroup2前缀的配置,不用慌,这是新版LXC支持的cgroup v2写法。
2.3 一次实验让你直观感受隔离
光看理论记不住,建议直接跑一遍。创建一个最简单的容器然后启动,容器内执行命令:
code复制sudo lxc-attach -n test -- /bin/bash
进去之后依次执行:
code复制hostname
ps -ef
ip addr
mount | head -5
你会发现容器里的hostname已经变成一个独立机器名,进程列表里只有bash和你手动启动的进程,网络接口是独立的eth0,挂载列表也和宿主机明显不同。这一套下来,"容器是内核视图的隔离"这句话就变成了直观体验。很多资料讲"容器本质是进程",这句话对Docker场景成立,但对LXC场景更准确的说法是:容器是一组带独立内核视图的特权进程组。
3. 虚拟机、LXC容器、Docker容器:三者的边界和选型
搞清三者的差异,不是纯粹为了满足好奇心,它直接决定你在一个项目里选什么技术方案。
3.1 本质区别:共享内核 vs 独立内核
传统的虚拟机(比如KVM、VirtualBox)里面有完整的Guest OS,包括独立内核。宿主机和虚拟机之间隔着一层Hypervisor,虚拟机的内核崩溃了,宿主机不会有事。LXC容器则完全相反:所有容器共享宿主机内核,容器里没有独立内核,只有一套用户空间文件系统。这也意味着容器内的"内核模块"其实是宿主机的,容器无法加载一个宿主机没有的驱动模块。
Docker容器和LXC容器在内核层面是同一类东西,都属于"共享宿主机内核"的进程级隔离。区别在于用户空间的内容组织方式:LXC容器默认是一个完整的系统环境(有init、systemd、sshd,像一台最小化Linux服务器),Docker容器默认只打包应用及其依赖,里面通常没有完整的init进程管理体系。
3.2 性能密度和安全边界的取舍
为什么很多人说"容器比虚拟机轻量"?核心原因在于共享内核省掉了虚拟化层的指令翻译和独立内核的开销。LXC容器启动本质上就是启动一组进程,几百毫秒就能起来,内存开销主要是容器内进程本身,不会像虚拟机那样每个Guest OS都吃几百MB甚至几GB内存。喜欢用"密度"这个词的人,喜欢LXC可以在同一台物理机上跑几十上百个系统实例。
但天下没有免费的午餐。共享内核带来的代价是安全边界变小:如果内核出现漏洞,理论上容器内提权可能影响到宿主机。虚拟机因为有了独立内核和Hypervisor隔离,即使Guest OS被打穿,攻击面也相对可控。所以安全要求极高的多租户环境,虚拟机的角色不可替代;而要求极致密度和性能的场景,LXC类方案更合适。
3.3 什么时候选LXC而不是Docker
这是很多刚接触容器的人最纠结的问题。我的经验是看你要交付什么:如果目标是把业务应用标准化交付到任意环境,让开发、测试、生产环境保持一致,选Docker几乎是唯一合理的选择,因为它的镜像生态和分发体系太成熟了。如果目标是模拟一个完整的Linux环境(比如我要测试一套需要systemd、cron、多个关联服务的业务系统),或者要在无Docker守护进程的最小系统上做资源隔离,LXC更直观顺手。
还有一个典型场景是CI/CD的加速节点。用LXD(LXC的管理层)做OpenStack等平台的虚拟化后端,或者用LXC跑构建任务,都能拿到比虚拟机高得多的密度。另外嵌入式Linux开发和IoT设备上,LXC也是做应用隔离的常见选择,因为Docker引擎在资源受限设备上反而显得笨重。
4. 从零创建并管理第一个LXC容器
下面进入实操环节。我的操作环境是Ubuntu 22.04 LTS,LXC版本5.x。不同发行版的安装命令略有差异,但核心逻辑一致。
4.1 安装与环境准备
直接安装LXC及相关工具:
code复制sudo apt update
sudo apt install -y lxc lxc-templates uidmap
uidmap用于用户命名空间映射,后面配置非root权限容器时要用。装完先检查当前内核是否支持LXC所需的各项能力:
code复制lxc-checkconfig
这个命令会逐项列出namespace、cgroup、pivot_root等特性的启用状态。如果结果里出现缺失项,大概率是内核配置问题,需要确认内核是否编译了对应的选项,不要急着往下走。实测中大多数现代发行版内核都是全绿的,但嵌入式或者定制内核需要注意。
安装完成后,系统会创建一个名为lxcbr0的网桥,默认网段是10.0.3.0/24。这是LXC的默认管理网络,容器创建后会自动接到这个网桥上。可以看一下当前的网络状态:
code复制ip addr show lxcbr0
4.2 用download模板创建Ubuntu容器
LXC创建容器的方式有很多种,最传统的是模板脚本方式。老版本用类似lxc-create -n u1 -t ubuntu这样的命令,它走的是Ubuntu官方模板脚本。现在更推荐download模板,因为它支持非常多的发行版:
code复制sudo lxc-create -n u1 -t download -- -d ubuntu -r jammy -a amd64
这条命令的意思是用download模板创建一个名字叫u1、发行版为Ubuntu、版本为jammy(22.04)、架构为amd64的容器。第一次运行会提示确认GPG指纹,输入yes即可。因为需要从远程镜像源下载rootfs,耗时取决于网络状况。
下载完成后,容器配置保存在/var/lib/lxc/u1/config,rootfs在/var/lib/lxc/u1/rootfs。可以打开config文件看看里面的内容,重点注意这一项:
code复制lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
这就是默认网络配置:容器通过veth虚拟网卡对接到lxcbr0桥接网络。veth一头在容器里显示为eth0,另一头在宿主机上显示为vethXXX,桥接进lxcbr0。
4.3 容器的启停、登录和查看状态
创建完成后,启动容器:
code复制sudo lxc-start -n u1
启动后可以用lxc-ls -f查看所有容器及状态:
code复制sudo lxc-ls -f
输出会列出容器的名称、状态、IP地址等信息。如果要进入容器操作,最直接的方式是:
code复制sudo lxc-attach -n u1 -- /bin/bash
lxc-attach类似Docker的docker exec,它直接进入容器的命名空间,在里面执行命令。这种登录方式不需要容器开启SSH服务,非常适合初始配置阶段。
控制台方式获取容器IP:
code复制sudo lxc-info -n u1 -iH
停止容器用sudo lxc-stop -n u1,删除用sudo lxc-destroy -n u1。注意删除不可逆,会连同rootfs一起清掉,操作前先确认不用再备份了。
4.4 配置容器内的用户和权限
刚创建的容器默认只有root用户,而且这个root在默认配置下对应宿主机的root,安全性存在隐患。我的建议是拿到容器第一件事就配置好普通用户和SSH登录。在容器内执行:
code复制useradd -m -s /bin/bash dev
echo 'dev:yourpassword' | chpasswd
容器内配置SSH服务(如果模板没装的话):
code复制apt update
apt install -y openssh-server
systemctl enable ssh
systemctl start ssh
然后修改/etc/ssh/sshd_config,允许root登录还是禁用root登录,看你需求。设置好后从宿主机直接SSH到容器的IP,体验和登录一台真实服务器完全一样。
这就要注意一个问题:LXC创建容器时默认不启用systemd,容器内第一个进程通常是/sbin/init的简化替代,老模板里可能没有systemd。严格意义上的"像服务器一样操作"需要用到init systemd支持,我们后面专门讲这个坑。
5. 网络不再玄学:LXC的四种网络模式与实战配置
LXC的网络配置,在相当长时间里是劝退新手的主要难点。其实搞懂核心逻辑就一句话:容器里跑着网络应用,但它没有独立硬件网卡,需要依赖虚拟网络设备把流量接到宿主机的网络栈上。怎么接,就是网络模式。
5.1 默认的lxcbr0桥接网络
最常见的模式是veth桥接,也是刚创建容器时默认采用的方案。拓扑大致是:
- 容器内有一个eth0,对应veth的一头;
- 宿主机的lxcbr0网桥,对应veth的另一头;
- LXC内置的dnsmasq进程为容器分配IP、提供DNS解析。
这种模式下,所有容器位于同一个10.0.3.0/24网段,容器之间可以互通,容器也能通过宿主机做NAT访问外网。如果你想手动指定容器IP,可以在容器config里加:
code复制lxc.net.0.ipv4.address = 10.0.3.50/24
lxc.net.0.ipv4.gateway = 10.0.3.1
改完需要重启容器才生效。这种方式的优点是省心、默认可用,缺点是外部设备无法直接访问容器,需要做端口转发。比如把宿主机的2222端口转到10.0.3.50容器的22端口:
code复制iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 10.0.3.50:22
注意这只是运行时规则,重启宿主机后失效,生产环境需要持久化规则。
5.2 veth+物理网卡桥接:让容器和宿主机同网段
如果我希望容器和宿主机处于同一局域网段,能从路由器直接分配IP、局域网内其他机器也能直接访问容器,就需要把容器接入一块物理网卡的桥接上。
实际操作:假设宿主机物理网卡名是eth0,先创建一个网桥并把物理网卡加进去:
code复制sudo ip link add name br0 type bridge
sudo ip link set eth0 master br0
sudo ip addr flush dev eth0
sudo ip addr add 192.168.1.10/24 dev br0
sudo ip link set br0 up
sudo ip link set eth0 up
这样br0取代eth0成为宿主机的网络入口,eth0成了br0的一个成员端口。然后在容器config里,把网络模式改为:
code复制lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:12:34:56
重启LXC服务或重启容器后,在容器内配置一个和宿主机同网段的静态IP,或者如果网络里有DHCP服务,直接就能自动获取地址。这是实际项目里最常见的"容器当独立服务器用"的网络方案。坑点在于:如果你是通过SSH连宿主机进行操作,物理网卡被加入网桥、IP被挪走的那一瞬间,SSH会断一下,用IPMI或本地控制台操作会安全很多。
5.3 macvlan模式和端口映射
macvlan是另一种有意思的模式。它让宿主机物理网卡直接虚拟出多个带独立MAC地址的接口,每个接口绑定给一个容器,容器直接从上层交换机/路由器获取IP。配置方式:
code复制lxc.net.0.type = macvlan
lxc.net.0.link = eth0
lxc.net.0.macvlan.mode = bridge
lxc.net.0.flags = up
背景信息是macvlan模式性能很高,因为流量直接走物理网卡,不需要经过宿主机的网桥和iptables转发。但一个明显限制是宿主机和容器之间默认无法互相通信(因为macvlan接口和自己的物理父接口不互通),如果你的应用需要容器访问宿主机服务,这个模式就不太合适。另外某些云厂商的虚拟网卡不支持macvlan,物理环境用起来更顺手。
6. 生产环境绕不开的坑:systemd、权限、存储与安全
实践到这里,你已经能创建、启动、登录容器了。但一旦真的把LXC环境投入生产使用,马上会遇到一批从文档里很难提前预知的问题。我把这几年踩过的坑集中整理一下,每一个都是真实发生过的。
6.1 容器里起systemd失败的坑
前面提到过,LXC容器默认第一个进程往往是精简过的init,而不是完整的systemd。最典型的表现是:容器里执行systemctl命令时报错——"System has not been booted with systemd as init system"。
为什么会这样?因为创建容器时,LXC的模板脚本默认把容器的init设置成/sbin/init的一个简化版,或者干脆用lxc-init代管。如果你希望容器像真实服务器一样管理服务,需要在创建容器时就指定init类型,或者手动修改config。
推荐的做法是在创建时追加--init参数:
code复制sudo lxc-create -n u1 -t download -- -d ubuntu -r jammy -a amd64 --init
加上这个参数后,容器内会安装并启用systemd作为PID 1。如果容器已经创建好了,可以改config文件加上:
code复制lxc.init.cmd = /sbin/init
然后重启容器。生效成功后,容器内执行systemctl status ssh、systemctl enable cron等操作就和真正的Ubuntu服务器完全一致了。我在实际测试中,这一步是"LXC容器能否当虚拟机用"的分水岭。
6.2 非root用户运行容器服务的权限细节
生产环境安全基线要求服务以非root运行,这在LXC环境下会遇到一个隐蔽问题:容器里的root默认对宿主机也是root权限。这等于只要容器被攻破,宿主机也跟着危险。解决方案是User namespace。
启用用户命名空间后,容器内的UID 0会映射到宿主机的一个普通用户,容器内再怎么提权,在宿主机视角也只是这个普通用户的能力。配置方式是在容器config里加:
code复制lxc.include = /usr/share/lxc/config/common.conf
lxc.maptype = unsupported
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
这里的含义是:容器内的UID 0到65535,映射到宿主机上的100000到165535之间。或者用更简单的创建方式:
code复制sudo lxc-create -n test -t download -U 100000:65536 -- -d ubuntu -r jammy -a amd64
开启之后,容器内root在宿主机上就完全不是特权用户了。这个设置会让存储权限管理变得稍微复杂一些(宿主机上看到的容器文件属主是100000开头的数字),但安全收益巨大。我在多租户场景下默认开启。
另一个权限相关的问题是容器内非root用户绑定低端口。Linux规定1024以下端口,非root无法绑定。这个限制在容器内其实由宿主机内核强制,解决办法是加sysctl net.ipv4.ip_unprivileged_port_start=0到宿主机的/etc/sysctl.conf,但这个改动会影响整机安全,一般还是建议用端口转发把宿主机高端口映射到容器内低端口,别图省事。
6.3 存储与快照:LXD存储池带来的质变
直接裸用LXC的时候,容器的rootfs就是一个普通目录,快照、克隆都要靠手动拷贝,非常原始。LXD在这方面做了大量工程化工作:引入了存储池(storage pool)概念,底层支持dir、btrfs、zfs、lvm等存储驱动。其中zfs和btrfs因为支持写时复制(CoW),做快照和克隆几乎是瞬时的,还不会占用双倍磁盘空间。
实际使用中,如果你要从LXC裸命令切换到LXD:
code复制sudo snap install lxd
sudo lxd init
初始化过程会问后端存储驱动、网桥配置等问题。如果磁盘不是btrfs,且想快速获得快照能力,选zfs是个不错的选择(注意zfs在Ubuntu上需要单独装zfsutils-linux)。初始化完成后:
code复制lxc launch ubuntu:22.04 u2
lxc snapshot u2 snapshot-20250101
lxc restore u2 snapshot-20250101
注意这里的lxc命令是LXD的客户端(LXD的二进制也叫lxc),和LXC传统命令工具集名称相同但功能完全不同。初学时很容易在这里迷失方向。我的经验是:只是想在现有服务器上跑几个隔离环境,直接用LXC传统工具就够了;一旦需要管理几十个容器、做自动化供给和频繁快照回滚,果断切到LXD。这个对比,有点像拿一堆散装脚本去对比一个带API的管理平台。
再补一个踩过的坑:使用zfs存储池时,如果宿主机内核升级后zfs模块没有同步加载,容器可能无法启动。升级内核后建议先执行sudo zpool import -a检查存储池状态,再启动LXD。内核版本和zfs模块版本不匹配引发的诡异问题,很容易被误判为容器配置错误。
6.4 AppArmor与seccomp:被安全策略挡住的诡异报错
这是LXC新手最容易一头雾水的地方。有时候容器创建正常、启动正常,但容器内某个进程就是莫名报"Permission denied",或者干脆启动失败。查了很多权限设置都没问题,最后发现是AppArmor或seccomp策略拦的。
Debian/Ubuntu的LXC包默认带AppArmor配置文件,用来限制容器的能力边界。如果某个应用需要特殊权限(比如某些内核模块的访问,或者特殊的网络操作),可能会被AppArmor挡住。排查时可以临时关闭该容器的AppArmor限制,在config里加:
code复制lxc.apparmor.profile = unconfined
重启容器试试,如果问题消失,基本能确定是AppArmor策略导致。但临时关闭只用来定位问题,不要长开着。稳妥的做法是给容器写一个自定义的AppArmor profile,只放开需要的权限。seccomp也是类似道理,它是内核级的系统调用过滤器。LXC默认会加载一套seccomp配置,限制容器内调用部分高危系统调用。如果应用报"Operation not permitted",可以临时加上:
code复制lxc.seccomp.profile = /tmp/seccomp_allow_all
这个文件内容需要参考LXC的默认配置,把默认的拒绝规则替换成允许。更推荐的做法是查看LXC日志:
code复制sudo lxc-start -n u1 --logfile /tmp/lxc.log --logpriority DEBUG
这个命令会输出非常详细的启动日志,包括哪些调用被安全策略拦截。遇到诡异问题先开debug,能省下大量无头绪排查的时间。
7. 从传统工具到LXD再回来:我的选型建议和兜底提醒
写到这,基础操作和排障都聊得差不多了。按惯例最后聊点我真实使用中的体会,可能会省掉你不少纠结。
先是选型层面的建议:纯应用容器化,比如微服务、Web服务,直接用Docker,因为镜像生态和编排体系(Kubernetes、Compose)都太成熟,没必要用LXC重新造轮子。需要传统"服务器"体验的场景,比如模拟多节点集群、开发环境隔离、嵌入式设备运行多个系统实例,用LXC/LXD。要用LXC时,如果节点规模小、配置一次就不动了,传统lxc命令完全够用;如果要频繁创建销毁环境、配合自动化脚本做测试,直接用LXD,它的lxc init+lxc start+快照回滚这套API化操作比裸命令舒服得多。
其次是安全兜底提醒。不管用哪种方案,容器内的root都不能直接等于宿主机的root,生产环境必开User namespace映射。启动容器前先检查AppArmor和seccomp策略,确认业务应用在现有安全策略下能正常运行。我在生产环境里制定的原则是:"默认全锁,按需放行"。对所有容器先保持发行版默认安全策略,业务需要啥权限,在日志里看到拦截记录后再针对单项放开,而不是图省事直接unconfined。
最后是内核版本的问题。LXC非常依赖内核特性,生产环境尽量选用较新的LTS内核(比如Ubuntu 22.04的5.15内核以上,或者24.04的6.8内核)。新内核不仅对cgroup v2支持更完整,在性能、网络、安全特性上都有明显提升。我在一台老内核(4.15)上遇到过容器网络不稳定、cgroup配额不生效的问题,升级内核后消失。内核版本与LXC版本的兼容矩阵,发布之前花几分钟查一下官方文档,值这个时间。
容器技术演进到今天,Docker的光环确实盖过了LXC,但这不代表LXC过时了。它依然是在"系统级隔离"这个维度上最纯正、最直接的Linux原生方案。理解了LXC,你就理解了namespace、cgroup、容器的本质;再回头看Docker的镜像分层、运行时、网络模型,你会发现自己看的不再是一个个孤立命令,而是一套从内核到用户空间的完整逻辑链。这份"基石"功夫,什么时候补都不晚。
