用于编译任务的非特权 LXC 容器

1. 引言:Linux LXC 容器技术

Linux 容器(LXC)是一种操作系统级虚拟化技术,通过在单一 Linux 内核上运行多个独立且隔离的系统环境,实现了轻量级虚拟化。与传统的虚拟机相比,LXC 容器具有以下优势:

  • 资源占用更低
  • 启动速度更快
  • 保持类似虚拟机的环境隔离性

本文主要介绍非特权容器(Unprivileged Containers)。这类容器以普通用户身份运行,将容器内的 root 用户映射到宿主机的非特权用户 ID,从而显著提升系统的安全性,减小潜在攻击面。

2. 故事背景

很多开发项目在其主页上提供了构建项目和安装依赖项的指导,但大多数指南都基于 Debian/Ubuntu 系统。某些项目甚至未在非 Debian 系统(如 Arch Linux)上进行测试,导致其他发行版用户在构建过程中遇到诸多困难。

另一个实际原因是,Arch Linux 的滚动更新机制较为占用磁盘空间。因此,笔者倾向于将一些不常更新的软件(如交叉编译工具链)放置在 Flatpak 或 LXC 容器中。这类工具链体积较大、更新频率低,非常适合通过 LXC 容器进行管理。

为什么不使用 Docker?

尽管 Docker 也能满足需求,但它存在以下限制:

  • 需要常驻后台进程
  • 通常需要 root 权限

相比之下,LXC 更轻量、更贴近系统层面,也更符合本文的使用场景:

  • Docker:更适合用于服务部署
  • LXC:更适合用于环境隔离与编译任务

3. 主要操作步骤

3.1 环境准备与安装

LXC 的安装过程因发行版而异,此处不再赘述,请根据所用系统自行安装。

3.2 为用户配置 SubUID/SubGID

为用于管理容器的用户分配子 UID 和子 GID:

sudo usermod -v 100000-165535 <user>  # 设置 subuid
sudo usermod -w 100000-165535 <user>  # 设置 subgid

可通过以下命令查看分配结果:

grep $USER /etc/subuid
grep $USER /etc/subgid

示例输出如下:

<user>:100000:65536
<user>:100000:65536

3.3 创建 LXC 用户配置文件

首先创建配置目录:

mkdir -p ~/.config/lxc

编辑 ~/.config/lxc/default.conf,写入如下内容:

lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx

lxc.idmap = u 0 100000 1000
lxc.idmap = g 0 100000 1000
lxc.idmap = u 1000 1000 1
lxc.idmap = g 1000 1000 1
lxc.idmap = u 1001 101001 64535
lxc.idmap = g 1001 101001 64535

lxc.mount.entry = /home/<user>/repository LXC_ROOTFS/mnt none bind,create=dir 0 0

配置说明

  • 网络部分

    lxc.net.0.type = veth
    lxc.net.0.link = br0
    lxc.net.0.flags = up
    lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
    

    此处配置使用一个外部管理的网桥(如 br0)。如果希望继续使用 LXC 默认的 lxcbr0,可保留默认配置。

  • ID 映射部分

    lxc.idmap = u 0 100000 1000
    lxc.idmap = g 0 100000 1000
    lxc.idmap = u 1000 1000 1
    lxc.idmap = g 1000 1000 1
    lxc.idmap = u 1001 101001 64535
    lxc.idmap = g 1001 101001 64535
    

    该配置实现了 UID/GID 的映射:

    • 容器内的 0–9991001–65535 分别映射到宿主机的 100000–100999101001–165535
    • 容器内的 UID 1000 直接映射到宿主机的 UID 1000
      这样做是为了在绑定挂载宿主目录时,保持文件所有权的一致性。
  • 挂载条目

    lxc.mount.entry = /home/<user>/repository LXC_ROOTFS/mnt none bind,create=dir 0 0
    

    将宿主的 /home/<user>/repository 绑定挂载到容器的 /mnt 目录,create=dir 表示若目录不存在则自动创建。

    不过其实 LXC_ROOTFS/ 前缀不加也没什么,默认就是容器内的根目录。

    💡 ~/.config/lxc/default.conf 是一个模板文件。使用 lxc-create 创建容器时,LXC 会自动将 LXC_ROOTFS 等变量替换为容器的实际路径。

3.4 配置网络权限

允许用户创建 veth 设备并连接到网桥(如 br0):

echo "<user> veth br0 10" | sudo tee -a /etc/lxc/lxc-usernet

该命令允许用户 <user> 最多创建 10 个 veth 设备对,并将其连接到 br0 网桥。

3.5 创建并启动非特权容器

以下以创建一个 Debian 容器为例:

lxc-create --name debian --template download -- --dist debian --release trixie --arch amd64
lxc-start debian
lxc-attach -n debian --clear-env --set-var TERM=linux

容器初始化操作示例

 更换为中科大镜像源以加速访问
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
apt update

 根据自己的需求装点软件
apt install wget curl git vis fastfetch vivid fish foot-terminfo gpg

 创建与宿主机同 UID 的用户
useradd -m -u 1000 -s /usr/bin/fish <user>
passwd <user>
usermod -aG sudo <user>

 复制 SSH 配置
cp -r .ssh/ .local/share/lxc/debian/rootfs/home/<user>/

 以用户身份进入容器,克隆配置仓库
lxc-attach -n debian --clear-env --set-var TERM=$TERM -- su -l $USER
git clone git@github.com:<user>/dot.git  # 我自己的配置文件仓库
rm -rf .config/ && mv dot/ .config/

✅ 一套小连招下来,系统就基本可用了!

总结

  • 将项目目录挂载到容器的 /mnt 目录下后,在容器内 cd /mnt 即可开始编译。
  • 容器的编译结果对宿主机完全可见。
  • 使用相同方法,还可以配置容器和宿主机共享 ccache 缓存(本文略)。

posted on 2025-12-14 22:40  acd407  阅读(4)  评论(0)    收藏  举报

导航