LXC 与 Linux 系统容器

最后更新: 2026-08-23 10:41:42 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

LXC 是 Linux 隔离功能的用户空间接口。它结合 liblxc 库、命令行工具和发行版模板来创建系统容器:与主机共享内核的隔离 Linux 用户空间。

LXC 容器可以启动 init 系统、运行多个服务、维护持久化的软件包状态,并公开虚拟网络接口。因此,其运行模型更接近轻量级 Linux 计算机,而非 OCI 应用容器。不过,LXC 仍然是容器运行时,因为它不会启动客户机内核或模拟硬件。

在虚拟化栈中的定位 #

LXC 负责协调多种内核机制,而不是在单个独立子系统中实现隔离:

NamespacCiieonssniottlaai+tneesdcregrrrAvooiouctpefsssvH2ostLiclcCiinaioonsupfnnioxalefttlbiciaaKibygi+tellcunerixlresdntceareeitrrleaiBvosnoiodnctefssseccompCiionsniottlaai+tLneSesdMresrrCvoioctefss

每个容器都会获得一组选定的隔离内核视图:

机制在 LXC 容器中的作用
命名空间隔离进程 ID、挂载点、网络、IPC、主机名、用户、cgroup 视图和时钟。
cgroups v2统计并限制 CPU、内存、进程数、I/O 和设备访问。
Capabilities将传统的 root 权限拆分为可独立移除的特权。
Seccomp过滤容器进程可使用的系统调用。
AppArmor 或 SELinux约束仍可通过共享内核访问的主机资源。
用户命名空间将容器 UID 和 GID(包括容器 root)映射到非特权主机 ID。

命名空间决定进程可以看到什么,而 cgroups 决定进程可以消耗多少资源。Capabilities、seccomp 和 Linux 安全模块会施加相互独立的限制,因为仅靠命名空间隔离无法构成完整的安全策略。

LXC 组件及其生态系统 #

多个相关项目分别承担不同职责:

项目职责
LXCliblxc C 库、lxc-* 生命周期工具、配置格式和发行版模板。
LXCFS一种 FUSE 文件系统,用于呈现可感知 cgroup 的 /proc 数据,例如容器特定的 CPU 和内存信息。
Distrobuilder根据 YAML 定义构建根文件系统和镜像。
Incus更高层级的系统容器和虚拟机管理器,默认使用 LXC 作为容器运行时。

Incus 增加了守护进程和 REST API,以及托管镜像、配置文件、存储池、网络、项目、集群和迁移功能。当主机需要在没有管理守护进程的情况下直接控制本地容器时,LXC 本身仍然适用。

不得将 LXD 和 Incus 视为 LXC 的别称。LXD 最初是构建于 LXC 之上的管理器。Incus 后来从 LXD 分叉,现在由 Linux Containers 项目维护。

容器生命周期 #

download 模板从 Linux Containers 镜像服务器获取发行版根文件系统。以下命令假定主机发行版已安装 LXC,并为调用用户配置了所需的 UID/GID 范围和网络:

sh
lxc-create --name web01 --template download -- \
  --dist debian --release trixie --arch amd64

lxc-start --name web01 --daemon
lxc-info --name web01
lxc-attach --name web01

lxc-stop --name web01
lxc-destroy --name web01

默认的系统级容器位置是 /var/lib/lxc/<name>/。除非根文件系统使用其他存储后端,否则容器目录包含其配置和根文件系统。相关生命周期工具包括:

  • 使用 lxc-ls --fancy 列出容器及其状态;
  • 使用 lxc-console 连接到已配置的控制台;
  • 使用 lxc-freeze 和 lxc-unfreeze 通过 cgroup freezer 暂停和恢复执行;
  • lxc-copy 在后端存储支持时复制容器或为容器创建快照所需的 请求操作;以及
  • 使用 lxc-monitor 和 lxc-wait 观察状态变化。

LXC 配置使用 key = value 条目。简化配置可以组合身份、存储、网络、UID 映射和资源控制:

ini
lxc.uts.name = web01
lxc.rootfs.path = dir:/var/lib/lxc/web01/rootfs

lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up

lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536

lxc.cgroup2.memory.max = 2147483648
lxc.cgroup2.pids.max = 1024
lxc.cgroup2.cpu.max = 200000 100000

配置取决于主机。UID/GID 范围必须与从属 ID 分配一致,网络设备必须存在,并且运行中的内核必须支持相应的 cgroup 值。LXC 会将许多 cgroup 设置直接传递给内核,而不是将其规范化为运行时特定的资源模型。

特权容器与非特权容器 #

UID 映射决定容器 root 是否同时也是主机 root:

  • 在特权容器中,容器内的 UID 0 从 主机内核的视角看也是 UID 0。命名空间、移除 capabilities、seccomp 和强制访问控制可以减少访问权限,但上游 LXC 明确表示不会将特权容器视为对 root 安全。
  • 在非特权容器中,UID 0 会映射到非零的主机 UID,例如 100000. 因此,用户命名空间可防止容器 root 拥有 普通主机资源。

例如,映射 u 0 100000 65536 将容器 UID 0 至 65535 映射到主机 UID 100000 至 165535。newuidmap 和 newgidmap 安装由 /etc/subuid 和 /etc/subgid 授权的映射。非特权网络还可以使用权限范围严格受限的 lxc-user-nic 辅助程序创建获准的虚拟接口。

对于不需要主机级身份或设备访问的工作负载,应默认使用非特权容器。用户命名空间无法消除共享内核风险:可通过获准系统调用触发的内核漏洞仍可能跨越容器边界。

存储 #

根文件系统可以是目录、镜像文件、块设备或受支持的写时复制后端。根据构建选项和主机配置,lxc-create 支持目录、Btrfs、LVM、环回文件、ZFS 和 Ceph RBD 等底层存储。

后端选择会改变运行行为:

后端运行属性
目录设置最少且可直接访问文件,但复制容器时需要复制其文件。
Btrfs 或 ZFS当主机文件系统经过相应配置时,可使用原生快照和高效克隆。
LVM thin pool提供块设备隔离、精简配置和快照支持。
环回文件无需专用逻辑卷的文件系统镜像,但代价是增加一层存储。
Ceph RBD适用于已集成 Ceph 的主机的网络后端块存储。
OverlayFS在一个或多个下层之上的可写上层;适用于临时根文件系统或克隆的根文件系统。

ID 映射挂载可以通过容器的 UID/GID 映射公开文件系统所有权,而无需递归更改每个 inode。采用前必须确认内核、文件系统和 LXC 均提供支持。

网络 #

LXC 可以创建多种网络接口:

  • veth 创建一对以太网接口,通常将主机端连接到 lxcbr0 等网桥;
  • vlan 在主机父接口上创建 VLAN 接口;
  • macvlan 和 ipvlan 以不同的 第 2 层或第 3 层语义将容器连接到父接口;
  • phys 将物理接口移入容器的网络命名空间;
  • empty 创建仅包含回环接口的隔离网络命名空间;以及
  • none 保留主机网络命名空间。

网桥提供连通性,而不提供租户安全性。连接到同一第 2 层网段的容器可能尝试地址欺骗或发送恶意控制流量。因此,不受信任的租户需要使用网桥隔离、主机端过滤和显式 IPv6 路由器通告控制。

资源和设备控制 #

LXC 7.0 仅支持 cgroups v2。运维人员可以通过 lxc.cgroup2.* 写入控制器值,例如:

  • 使用 memory.max 和 memory.high 控制内存限制和压力;
  • 使用 cpu.max 和 cpuset.cpus 控制 CPU 带宽和放置;
  • 使用 pids.max 限制 fork 炸弹;以及
  • 针对受支持块设备的 I/O 控制器设置。

进程仅仅运行在容器中并不意味着存在资源上限。如果没有显式限制,容器可以与其他负载争用主机的可用内存、CPU、进程 ID、I/O 和网络容量。

设备访问同样需要谨慎处理。在 cgroups v2 上,设备过滤通过附加到 cgroup 的 eBPF 程序强制执行,而非通过 cgroups v1 的设备控制文件。直通 GPU、磁盘或其他设备会扩大攻击面,因为容器进程随后会与主机驱动程序交互。

安全模型 #

LXC 隔离采用纵深防御,而非依赖单一边界。生产配置应:

  1. 使用 UID/GID 范围互不重叠的非特权容器。
  2. 应用内存、CPU、进程数和 I/O 控制,因为 LXC 默认不会施加完整限制。
  3. 移除工作负载不需要的 capabilities。
  4. 加载适当的 seccomp 策略,并在主机发行版支持的情况下保留 AppArmor 或 SELinux 约束。
  5. 尽量减少绑定挂载、设备直通、共享命名空间和可写的 主机路径。
  6. 隔离不受信任的网段,并过滤面向主机的流量。
  7. 保持主机内核和 LXC 软件包为最新版本,因为每个容器都共享 主机内核。

相互不信任的容器之间应避免使用重叠的从属 ID 映射,否则,与同一主机 UID 关联的内核统计和限制可能导致容器之间相互干扰。

在 LXC 内嵌套另一个容器运行时需要额外特权、特定挂载行为、cgroup 委派或安全策略例外。在 LXC 容器内运行 Docker 可以隔离生命周期和配置状态,但无法形成虚拟机级安全边界,因为两层最终使用的是同一个主机内核。

LXC、OCI 容器与虚拟机 #

LXC、OCI 运行时和虚拟机解决不同的打包与隔离问题:

属性LXC 系统容器OCI 应用容器虚拟机
典型单元包含 init 和多个服务的 Linux 用户空间应用进程及其依赖项完整操作系统
内核与主机共享与主机共享独立的客户机内核
镜像模型发行版 rootfs 或自定义系统镜像按内容寻址的分层 OCI 镜像虚拟磁盘和计算机镜像
状态模型一般为持久且可变一般会重新构建并替换一般为持久状态
管理方式直接使用 lxc-* 工具,或使用 Incus 等管理器Docker、containerd、CRI-O、Kubernetes 及相关工具Hypervisor 和虚拟机管理工具
操作系统约束与主机内核兼容的 Linux 用户空间与主机内核兼容的 Linux 用户空间虚拟硬件支持的客户机操作系统
隔离边界命名空间、用户映射、cgroups 和安全策略命名空间、用户映射、cgroups 和安全策略硬件虚拟化和 Hypervisor

当工作负载按 Linux 计算机方式运行时,应选择 LXC:工作负载需要 init 系统、多个协同运行的守护进程、原地软件包管理或操作系统级集成测试环境。

当部署单元是应用镜像,并且交付系统依赖镜像仓库、分层构建、不可变替换或 Kubernetes 时,应选择 OCI 运行时。

当工作负载需要不同的内核、非 Linux 客户机、内核模块控制,或需要针对敌对租户提供更强的隔离边界时,应选择虚拟机。性能必须根据实际工作负载测量,而不能仅根据类别推断。

项目状态 #

截至 2026 年 8 月,LXC 7.0 是当前的长期支持系列,计划支持至 2031 年 6 月。LXC 6.0 的支持将持续至 2029 年 6 月,LXC 5.0 则持续至 2027 年 6 月。

LXC 7.0 移除了对 cgroups v1 的支持,也不再支持缺少 pidfds 或新挂载 API 的内核。因此,从旧版 LXC 升级的部署必须验证主机内核能力,并迁移剩余的 cgroups v1 配置。

版本号和支持日期描述的是上游发行版。Linux 发行版可以采用不同的软件包版本、向后移植和维护策略。

参考资料 #

评论

在 GitHub 上阅读或评论(发表评论需要登录)