systemd服务无法读取环境变量的根本原因是其默认仅提供极简环境(如PATH仅含/usr/bin:/bin),不加载shell配置文件;需通过cat /proc/<PID>/environ确认实际环境,显式在service文件中用Environment=或EnvironmentFile=配置变量,并重载重启验证。

排查 systemd 服务无法读取环境变量,核心是确认“实际运行环境”和“预期环境”是否一致,并定位缺失来源。systemd 默认只提供极简环境(PATH 通常仅含 `/usr/bin:/bin`),不加载 `/etc/profile`、`~/.bashrc` 等 shell 配置文件——这是绝大多数问题的根源。
确认环境变量是否真的缺失
不能凭感觉判断,必须直接查看进程运行时的真实环境:
- 查服务当前 PID:
systemctl show --property=MainPID myapp.service | cut -d= -f2 - 读取该进程完整环境(需 root 或进程所属用户权限):
cat /proc/<PID>/environ | tr '\0' '\n' - 手动执行同一命令(如
/path/to/myapp),再运行env | grep -E "^(PATH|LD_LIBRARY_PATH|MY_VAR)",对比两者差异 - 重点关注 PATH(找不到命令)、LD_LIBRARY_PATH(so 加载失败)、自定义业务变量(如 CONFIG_DIR)是否为空或不全
检查 service 文件中是否已正确配置
systemd 服务的环境变量应显式声明在单元文件中,而非依赖系统全局配置:
- 用
systemctl cat myapp.service查看完整定义,搜索Environment=或EnvironmentFile= - 若未设置,编辑
/etc/systemd/system/myapp.service,在[Service]段添加:-
Environment="PATH=/usr/local/bin:/usr/bin:/bin"(按实际需要补全) -
Environment="LD_LIBRARY_PATH=/app/lib:/usr/local/lib"(如有私有 so 库) - 多个变量可分行写,或使用
EnvironmentFile=/etc/default/myapp统一管理
-
- 改完必须执行:
systemctl daemon-reload && systemctl restart myapp.service
排除常见误操作和隐性陷阱
有些做法看似省事,实则不可靠或引入新问题:
- 避免在
ExecStart中写bash -c "source /etc/profile && /path/to/app":systemd 不保证 bash 可用,且绕过安全上下文 - 不要依赖
/etc/environment设置 PATH:它只被 PAM 登录会话读取,systemd 服务默认忽略 - 若设了
User=nonroot,注意该用户默认 PATH 往往不含/usr/local/bin,必须显式声明 - 若用
Type=forking,确保子进程继承父进程环境;优先选Type=simple或Type=exec
快速验证是否修复成功
重启后立即交叉验证三件事:
- 运行
systemctl status myapp.service,确认状态为active (running),无 early exit - 查日志:
journalctl -u myapp.service -n 30 -o cat,搜索command not found、cannot open shared object file等关键词 - 再次执行
cat /proc/$(pidof myapp)/environ | tr '\0' '\n' | grep -E "^(PATH|LD_LIBRARY_PATH)",确认目标变量已存在且值正确


















