LXC 是 Linux 隔离功能的用户空间接口。它结合 liblxc 库、命令行工具和发行版模板来创建系统容器:与主机共享内核的隔离 Linux 用户空间。
LXC 容器可以启动 init 系统、运行多个服务、维护持久化的软件包状态,并公开虚拟网络接口。因此,其运行模型更接近轻量级 Linux 计算机,而非 OCI 应用容器。不过,LXC 仍然是容器运行时,因为它不会启动客户机内核或模拟硬件。
在虚拟化栈中的定位 #
LXC 负责协调多种内核机制,而不是在单个独立子系统中实现隔离:
每个容器都会获得一组选定的隔离内核视图:
| 机制 | 在 LXC 容器中的作用 |
|---|---|
| 命名空间 | 隔离进程 ID、挂载点、网络、IPC、主机名、用户、cgroup 视图和时钟。 |
| cgroups v2 | 统计并限制 CPU、内存、进程数、I/O 和设备访问。 |
| Capabilities | 将传统的 root 权限拆分为可独立移除的特权。 |
| Seccomp | 过滤容器进程可使用的系统调用。 |
| AppArmor 或 SELinux | 约束仍可通过共享内核访问的主机资源。 |
| 用户命名空间 | 将容器 UID 和 GID(包括容器 root)映射到非特权主机 ID。 |
命名空间决定进程可以看到什么,而 cgroups 决定进程可以消耗多少资源。Capabilities、seccomp 和 Linux 安全模块会施加相互独立的限制,因为仅靠命名空间隔离无法构成完整的安全策略。
LXC 组件及其生态系统 #
多个相关项目分别承担不同职责:
| 项目 | 职责 |
|---|---|
| LXC | liblxc 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 范围和网络:
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 映射和资源控制:
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 隔离采用纵深防御,而非依赖单一边界。生产配置应:
- 使用 UID/GID 范围互不重叠的非特权容器。
- 应用内存、CPU、进程数和 I/O 控制,因为 LXC 默认不会施加完整限制。
- 移除工作负载不需要的 capabilities。
- 加载适当的 seccomp 策略,并在主机发行版支持的情况下保留 AppArmor 或 SELinux 约束。
- 尽量减少绑定挂载、设备直通、共享命名空间和可写的 主机路径。
- 隔离不受信任的网段,并过滤面向主机的流量。
- 保持主机内核和 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 上阅读或评论(发表评论需要登录)