Containerd Rootless模式完整配置与使用指南
- 2天前
引言
容器技术已成为现代应用部署的核心基础设施,但传统容器架构依赖root权限运行的设计存在显著安全隐患⸺一旦容器隔离被突破,攻击者可能直接获取宿主机的完全控制权。Containerd作为主流容器运行时,自v1.4版本起正式支持Rootless模式,通过非特权用户运行容器组件,从根源上降低特权滥用风险。本文基于实际操作场景,详细梳理Rootless模式的原理、环境准备、配置流程及使用技巧,为落地实践提供完整参考。
Rootless核心原理
Rootless模式的核心依赖Linux内核的用户命名空间(User Namespace)特性,该特性自Linux内核3.8版本起引入,支持将一个用户命名空间内的UID/GID范围映射到父命名空间的另一个UID/GID范围。在Containerd的Rootless模式中:
- 组件非特权启动:Containerd守护进程不再以root身份运行,而是通过普通用户启动,避免核心组件拥有宿主机特权。
- UID/GID映射配置:借助
newuidmap和newgidmap工具(RootlessKit依赖组件),将容器内的root用户(UID 0)映射到宿主机普通用户的一段子UID/GID范围(默认100000-165535),容器内特权操作被限制在该映射范围内。 - 运行时隔离执行:容器运行时(runc)在独立的用户命名空间内执行,所有文件操作、进程管理等行为均通过映射权限生效,无法直接操作宿主机敏感资源。
关键区别:传统模式中容器内root直接对应宿主机root,而Rootless模式下容器内root仅等效于宿主机的普通映射用户,即使容器逃逸也无法获取宿主机特权。
前提条件
要在Containerd中启用Rootless模式,需满足以下基础环境要求:
- 除Ubuntu 和 Debian 内核外,其他操作系统的内核版本需要在5.11 以上。
- 需要启用 cgroup 🔗 需要 cgroup v2 和 systemd
- 已经安装好containerd环境
安装及配置
依赖组件安装
Ubuntu/Debian系列
# 安装Rootless核心依赖
sudo apt update && sudo apt install -y rootlesskit
CentOS/RHEL系列
# 安装依赖组件
sudo yum install -y rootlesskit
下载Rootless配置工具
通过官方脚本快速配置Rootless环境,需在root用户下执行:
wget https://raw.githubusercontent.com/containerd/nerdctl/refs/heads/main/extras/rootless/containerd-rootless-setuptool.sh -O /usr/local/bin/containerd-rootless-setuptool.sh
wget https://raw.githubusercontent.com/containerd/nerdctl/refs/heads/main/extras/rootless/containerd-rootless.sh -O /usr/local/bin/containerd-rootless.sh
chmod +x /usr/local/bin/containerd-rootless-setuptool.sh
chmod +x /usr/local/bin/containerd-rootless.sh
创建并配置专用用户
为避免权限冲突,建议创建专门用于运行Rootless Containerd的普通用户(此处以testuser为例):
# 1. root用户下创建用户并设置密码
sudo useradd -m testuser # -m参数自动创建用户主目录
sudo passwd testuser # 输入密码并确认
# 2. 切换到testuser用户
su - testuser
# 3. 配置XDG_RUNTIME_DIR环境变量(容器运行时依赖)
echo "export XDG_RUNTIME_DIR=/run/user/$(id -u)" >> ~/.bashrc
source ~/.bashrc # 立即生效
# 4. 验证环境变量
echo $XDG_RUNTIME_DIR # 应输出/run/user/[testuser的UID]
执行Rootless初始化
在testuser用户下执行初始化脚本,自动配置UID/GID映射、服务文件等:
# 执行安装初始化(需保持testuser用户身份)
containerd-rootless-setuptool.sh install
# 初始化成功后,启动Rootless Containerd服务
systemctl --user start containerd
# 设置开机自启(用户级服务)
systemctl --user enable containerd
# 验证服务状态
systemctl --user status containerd # 应显示active (running)
手动配置UID/GID映射(特殊场景,可选)
若用户UID超过65536,或初始化脚本提示映射范围不足,需手动配置/etc/subuid和/etc/subgid(需root用户操作),规则为“用户名:起始UID:映射范围”:
# 编辑subuid文件(UID映射)
sudo vim /etc/subuid
# 添加以下内容(示例:testuser映射165536-231071)
admin:100000:65536
testuser:165536:65536
# 编辑subgid文件(GID映射,与UID映射保持一致)
sudo vim /etc/subgid
# 添加对应内容
admin:100000:65536
testuser:165536:65536
# 配置后切换到testuser用户,重启服务生效
su - testuser
systemctl --user restart containerd
映射范围需连续且不重叠,每个用户默认分配65536个ID(16位),确保起始UID=前一个用户起始UID+65536。
Rootless模式使用方法
Rootless模式支持nerdctl(推荐,Containerd官方客户端)和ctr两种工具,操作需在创建的普通用户(testuser)下执行。
使用nerdctl操作(推荐)
nerdctl对Rootless模式支持更友好,语法与docker类似,无需额外配置即可直接使用
# 1. 拉取测试镜像(以alpine为例)
nerdctl pull swr.cn-east-3.myhuaweicloud.com/lomtom-common/alpine:3.20
# 2. 运行交互式容器(--rm退出后自动删除容器)
nerdctl run --rm -it swr.cn-east-3.myhuaweicloud.com/lomtom-common/alpine:3.20 sh
# 3. 验证容器内用户(应显示root,但实际映射为宿主机testuser)
id # 输出uid=0(root) gid=0(root) groups=0(root)...
# 4. 退出容器
exit
使用ctr操作
ctr需先进入Rootless模式的用户命名空间才能正常操作,步骤如下:
# 1. 获取Rootless Containerd的子进程PID(用于进入命名空间)
CHILD_PID=$(cat /run/user/$(id -u)/containerd-rootless/child_pid)
# 2. 进入用户命名空间(--preserve-credentials保留权限上下文)
nsenter -U --preserve-credentials -m -n -t $CHILD_PID
# 3. 拉取镜像
ctr image pull swr.cn-east-3.myhuaweicloud.com/lomtom-common/alpine:3.20
# 4. 运行容器(--cgroup "" 适配Rootless cgroup配置)
ctr run --rm -t --cgroup "" swr.cn-east-3.myhuaweicloud.com/lomtom-common/alpine:3.20 alpine-sh sh
# 5. 退出容器和命名空间
exit
exit
Rootless模式验证
通过以下步骤确认Rootless模式已正确生效,避免权限配置错误:
# 1. 验证Containerd进程用户(应为testuser,而非root)
ps -ef | grep containerd | grep -v grep
# 输出示例:testuser 1234 567 0 10:00 ? 00:00:05 containerd
# 2. 验证UID映射关系(容器内root对应宿主机testuser的映射范围)
cat /proc/$(pgrep containerd)/uid_map
# 输出示例: 1 165536 65536
# 3. 验证服务运行状态(用户级服务正常运行)
systemctl --user status containerd | grep "active (running)"
# 4. 验证容器
nerdctl run --rm swr.cn-east-3.myhuaweicloud.com/lomtom-common/alpine:3.20 cat /proc/self/uid_map
# 输出示例:
0 1001 1
1 165536 65536(165536=起始sub UID,65536=范围)
总结
Containerd的Rootless模式通过Linux用户命名空间技术实现了容器的非特权运行,从根本上降低了容器逃逸和特权升级风险,特别适用于多租户环境和安全敏感场景。本文详细讲解了从环境准备、安装配置到基础操作、问题排查的完整流程,核心要点包括:确保内核版本和依赖组件兼容、正确配置UID/GID映射、根据内核版本选择合适的存储驱动、解决特权端口和资源限制等常见问题。