systemd服务启动后立刻退出,状态中出现 status=226/NAMESPACE,并不代表应用程序主动返回了226。这个退出码由systemd产生,表示服务进程尚未执行,管理器在准备挂载、UTS或IPC命名空间时失败。
常见触发点是 ReadOnlyPaths=、ReadWritePaths=、InaccessiblePaths=、PrivateTmp=、PrivateIPC=、ProtectSystem= 或 ProtectHome= 等沙箱选项,也可能是路径不存在、底层挂载只读,或容器不允许创建所需命名空间。

先确认失败发生在哪个阶段
先查看完整状态和本次启动日志,不要只盯着最后一行:
sudo systemctl status example.service --no-pager -l
sudo journalctl -u example.service -b --no-pager -n 100
systemd文档把226定义为 EXIT_NAMESPACE,对应挂载、UTS或IPC命名空间初始化失败。日志中常会同时出现 Failed to set up mount namespacing、Failed at step NAMESPACE 或具体路径错误。
看到226时,优先检查unit执行环境,而不是立即修改ExecStart命令。 可执行文件错误通常对应203/EXEC,工作目录错误通常对应200/CHDIR,它们与226不是同一阶段。
找到真正生效的沙箱配置
服务配置可能来自发行版unit、管理员覆盖文件和运行时属性。先读取合并后的内容:
sudo systemctl cat example.service
sudo systemctl show example.service \
-p FragmentPath -p DropInPaths \
-p PrivateTmp -p PrivateIPC -p ProtectSystem -p ProtectHome \
-p ReadOnlyPaths -p ReadWritePaths -p InaccessiblePaths
再检查unit语法:
sudo systemd-analyze verify example.service
不要只编辑 /usr/lib/systemd/system 或 /lib/systemd/system 下的厂商文件。 软件升级可能覆盖这些修改,应使用 sudo systemctl edit example.service 创建drop-in,并只覆盖已经确认有问题的选项。
核对路径、挂载和访问条件
沙箱配置引用的路径必须与实际系统一致。检查目录、挂载类型和只读状态:
sudo namei -l /srv/example/data
findmnt -T /srv/example/data
findmnt -no TARGET,OPTIONS / /run /tmp
ReadWritePaths=/srv/example/data 不会自动创建业务目录。目录缺失时,应先按服务用户和最小权限创建,而不是把整个根目录改为可写。
sudo install -d -o example -g example -m 0750 /srv/example/data
不要为了让服务启动而执行 chmod -R 777。 这会扩大写入范围,也不能解决只读挂载、路径位于沙箱外或命名空间创建受限的问题。
容器或VPS还要检查宿主限制
在LXC、OpenVZ或受限容器中,unit语法完全正确也可能无法创建挂载命名空间。先确认虚拟化环境,再做一个不改动系统挂载的能力测试:
systemd-detect-virt
sudo unshare --mount /bin/true
若 unshare 返回 Operation not permitted,问题可能来自宿主能力或容器策略。来宾系统无法通过关闭SELinux、AppArmor或反复重装systemd获得宿主没有授予的权限。 应由宿主平台调整容器能力,或在确认风险后减少该服务依赖的沙箱功能。
需要在隔离环境复现不同systemd版本时,可以使用 萤光云 创建测试实例,或用按小时计费的 LightNode 做短期验证。测试机应与生产数据和密钥分离。
用最小化覆盖恢复服务
先确定是哪一项设置触发失败,再建立针对性覆盖。例如日志明确指向不存在的只写目录时,可修正路径;若旧容器确实不支持 PrivateTmp=,才考虑在该服务的drop-in中临时关闭:
[Service]
PrivateTmp=no
保存后重新加载并启动:
sudo systemctl daemon-reload
sudo systemctl restart example.service
sudo systemctl status example.service --no-pager
一次只修改一个已确认的选项,并保留原配置备份。 同时关闭 ProtectSystem、ProtectHome、PrivateTmp 和路径限制虽然可能绕过报错,却会明显削弱服务隔离。
修改后如何验收
确认主进程已运行,并检查本次启动是否仍有NAMESPACE错误:
systemctl is-active example.service
systemctl show example.service -p MainPID -p ExecMainStatus
sudo journalctl -u example.service -b --since "5 minutes ago" --no-pager
sudo systemd-analyze security example.service
验收标准是服务稳定运行、日志不再出现命名空间初始化失败,并且没有无依据地取消其他安全限制。 业务还应完成端口、健康检查或实际读写测试,不能只以 active 作为唯一依据。
FAQ
226/NAMESPACE是应用程序返回的吗?
通常不是。它是systemd在执行应用之前准备命名空间失败时使用的退出码,应先查unit执行环境和journal日志。
可以直接关闭所有Protect和Private选项吗?
不建议。应定位单个触发项,并判断是路径错误、系统能力不足还是安全策略与业务需求冲突,再做最小修改。
修改unit后为什么仍然使用旧配置?
编辑后需要运行 systemctl daemon-reload,并确认 systemctl cat 显示的drop-in就是预期内容。若unit由生成器创建,还需检查其来源。
温馨提示
生产环境处理226/NAMESPACE时,先保存unit、drop-in和相关日志,再改配置。 沙箱选项属于安全边界,恢复启动不等于可以永久关闭隔离;最终应把临时绕过收敛为最小权限配置。


