Linux 服务配置修改后未生效的排查

16次阅读

修改 systemd 服务文件后 daemon-reload 无效,根本原因是 systemd 加载了 /run 或 /var/run 下的缓存副本或 drop-in 覆盖;需用 systemctl cat 确认实际加载路径,检查 drop-in、Alias、Type 配置,并用 systemd-analyze verify 验证语法。

Linux 服务配置修改后未生效的排查

修改 systemd 服务文件后 systemctl daemon-reload 没用?

常见现象是改了 /etc/systemd/system/myapp.service,执行了 systemctl daemon-reload,但 systemctl show myapp 或重启服务后配置项(比如 Environment=ExecStart=)仍是旧值。

根本原因通常是:systemd 加载的是缓存副本,而非你正在编辑的文件。它会优先读取 /run/systemd/system//var/run/systemd/system/ 下的生成式单元文件(尤其当服务由 generator 生成或被 drop-in 覆盖时)。

  • 先运行 systemctl cat myapp,确认实际加载的是哪个路径下的文件(注意输出顶部的“Loaded:”行)
  • 如果显示加载的是 /run/systemd/system/myapp.service,说明有 generator 或临时覆盖,直接编辑 /etc/systemd/system/ 下的文件无效
  • 检查是否存在 drop-in 目录:/etc/systemd/system/myapp.service.d/*.conf,它们的优先级高于主文件,会覆盖同名字段
  • 确认没在 .service 文件里误写 Alias=WantedBy= 导致 unit 名称被重定向

systemctl restart 后进程 环境变量 还是旧的?

systemd 不会把已启动进程的环境变量“热更新”进去,restart 是杀掉旧进程、用新配置拉起新进程 —— 但如果你用的是 fork+daemonize 模式(比如传统 SysV 风格的守护进程),主进程可能立刻退出,子进程脱离 systemd 管控,后续就不再受其环境或资源限制约束。

  • 检查服务是否设置了 Type=forking,且正确声明了 PIDFile=;否则 systemd 无法跟踪真正的工作进程
  • 更推荐改用 Type=simple(默认)或 Type=notify,避免 fork 分离
  • 验证环境变量是否生效:用 systemctl show --property=Environment myapp 查看 systemd 解析后的值,再用 cat /proc/$(pidof myapp)/environ | tr '' 'n' 看实际进程看到的环境
  • 注意 EnvironmentFile= 中的变量不会自动导出到 shell 子进程,需显式 Environment=FOO=$FOO 才能透传

配置改了但日志里看不到变化?

日志内容不更新,往往不是配置没生效,而是 journal 没刷新、或服务根本没按预期重载配置 —— 尤其对那些支持运行时重载(如 nginx -s reload、redis-cli CONFIG REWRITE)但未集成到 systemd 的服务。

  • 确认服务是否真的重启了:systemctl status myapp 看 Active 时间戳和 Main PID 是否变化
  • journal 默认只保留近期日志,旧条目可能已被轮转清除;加 --all 或指定时间范围:journalctl -u myapp --since "2024-05-01"
  • 如果服务自身支持重载信号(如 SIGHUP),但 unit 文件里没配 ExecReload=,那么 systemctl reload 实际什么也没做
  • 某些服务(如 rsyslog)会监听配置变更并自动重载,但 systemd 并不感知,此时需手动触发或改用 systemctl kill --signal=SIGHUP myapp

SELinux 或 Capabilities 导致配置被静默忽略?

看起来一切正常:文件改了、reload 成功、restart 也成功,但服务行为异常(比如无法绑定 端口 、读不到 配置文件),且 journal 里没有明显报错 —— 这很可能是 SELinux 策略或 capability 限制让 systemd 解析或传递配置失败。

  • 检查 SELinux 状态:sestatus,若为 enforcing,临时设为 permissive:sudo setenforce 0,再试一次,看问题是否消失
  • 查看拒绝日志:sudo ausearch -m avc -ts recent | audit2why,常会暴露类似“avc: denied {read} for pid=1234 comm=”myapp” name=”myapp.conf” dev=”sda1″ ino=56789″ 的记录
  • Capability 如 CAP_NET_BIND_SERVICE 若未在 Capabilities= 中声明,即使配置写了 Port=80,进程也无法真正绑定
  • 注意:PrivateTmp=yes 会让服务看到的是独立 tmpfs,你放在 /tmp/ 下的调试文件它根本看不到

最易被忽略的一点:systemd 单元文件语法错误不会导致 reload 失败,而是静默跳过该 unit —— 所以务必用 systemd-analyze verify /etc/systemd/system/myapp.service 检查语法,别只信 daemon-reload 的返回码。

text=ZqhQzanResources