LXC 非特权容器起不来、systemd 进不去:idmap、cgroup 委托与报错对照
LXC(Linux Containers)是 Linux 内核容器能力的用户空间接口,自 2008 年持续开发,专注系统容器:提供尽可能接近虚拟机的环境,但不跑独立内核、不模拟硬件。隔离靠 namespaces、强制访问控制(AppArmor/SELinux)和 cgroups 组合实现。LXC 是最早支持非特权容器的运行时(user namespace 进入主线之后)。
user namespace 把一组 UID/GID 做映射,容器内 UID 0 在主机上可能表现为 UID 100000。映射用 lxc.idmap 定义:
lxc.idmap = u 0 100000 65536
表示容器侧 UID 0 起的 65536 个映射到主机 UID 100000 起。LXC 配置文件每行 key = value,# 为注释。
非特权容器需要的配置
/etc/lxc/default.conf:
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
/etc/subuid 与 /etc/subgid 要为将要运行容器的每个用户写映射(如 root:100000:65536)。以非特权用户运行非特权容器需要提前委托 cgroup(cgroup2 委托模型强制):
$ systemd-run --unit=myshell --user --scope -p "Delegate=yes" lxc-start container_name
也可以用 Debian 的 lxc-unpriv-start / lxc-unpriv-attach 包装脚本,或走 /etc/systemd/system/user@.service.d/delegate.conf。
内核前提
需要 CONFIG_USER_NS。linux-hardened 内核默认只允许 root 使用 user namespace。user.max_user_namespaces 为 0 时容器会报 Failed to clone process in new user namespace,需设为正值;或 sysctl kernel.unprivileged_userns_clone=1。
常见报错与排查
1. id mapping 没分配
newuidmap failed to write mapping "newuidmap: uid range [0-65536) -> [100000-165536) not allowed"
Failed to set up id mapping
Failed to spawn container
原因通常是 /etc/subuid、/etc/subgid 没给启动容器的用户分配对应范围——谁启动就按谁查。排查命令:
tail -n+1 /etc/sub*id
Proxmox 场景里给 unprivileged 容器加 bind mount(mp0: /myZpool,mp=/datastore,backup=0,shared=1)后会出现挂载点属主 nogroup,此时可用 idmap=passthrough,让容器内 root 拥有该存储。
2. 以 systemd 服务启动非特权容器失败
用 lxc@CONTAINER_NAME.service 或自建 unit 时,若由 root 启动,/etc/subuid 和 /etc/subgid 必须匹配 root 的条目;官方建议把容器放在 /var/lib/lxc,用自带 unit。
由 root 启动但容器内 root 未映射到主机 root 的,仍是非特权容器(LXD 默认就这么做)。以非 root 用户启动可用 systemd lingering。参考讨论:Making LXC unprivileged container as systemd services。
3. systemd 在容器内起不来(RHEL7 例)
console 报:
Failed to insert module 'autofs4' / 'unix'
Failed to mount sysfs at /sys: Operation not permitted
Failed to mount proc at /proc: Operation not permitted
[!!!!!!] Failed to mount API filesystems, freezing.
原因是容器必须自带空的 /dev、/proc、/sys,且存在 /sbin/init。缺目录时 LXD 无法自动挂载,非特权 systemd 又无权自己挂,于是冻结。
开 debug 日志:
lxc config set c1 raw.lxc 'lxc.init.cmd = /sbin/init systemd.log_level=debug'
应急 shell:
lxc config set c1 raw.lxc 'lxc.init.cmd = /sbin/init emergency'
换 init 排查:
lxc config set rhel7 raw.lxc 'lxc.init.cmd = /bin/bash'
进入容器:
lxc exec rhel7 -- bash
4. cgroup v2 + 非特权容器
Debian 11 起默认统一 cgroup 层次,非 root 用户 lxc-start 报创建 cgroup Permission denied,容器内报 Failed to create /init.scope control group: Permission denied。
解决方向是给非 root 用户的启动路径加委托:systemd-run --user --scope -p Delegate=yes,或 user@.service.d/delegate.conf,或用 lxc-unpriv-start。cgroup v2 下非 root 用户启动非特权容器的委托细节仍需按发行版与 systemd 版本实测确认。
5. KEYRING 衍生步骤失败
非特权容器里服务因 seccomp 失败时,需要自定义 seccomp profile:
lxc.seccomp.profile = /etc/lxc/unpriv.seccomp
6. lxc-execute 启动失败
lxc-execute 报 Unable to open lxc.init.static(见 FS#63814),改用 lxc-start 正常。
LXD、Incus 与选型
LXD 是构建在 LXC 之上的管理器,带 daemon 与 REST API,支持大量发行版镜像,可从单机扩展到数据中心集群,统一管理容器和虚拟机。相对 Docker(应用级,偏微服务/CI)与 systemd-nspawn,LXD 适合跑完整 Linux 系统、持久化系统服务。LXD 之后由 Canonical 主导,社区分叉出 Incus;LXC 本体在 linuxcontainers.org。