Linux 服务管理 systemd 与 init 比较

1次阅读

根本原因是环境变量、工作目录或权限上下文不一致;systemd默认环境极简且不加载shell配置,需显式设置environment、workingdirectory等,并注意type、wantedby、daemon-reload等关键配置。

Linux 服务管理 systemd 与 init 比较

systemd 服务文件里 ExecStart 启动失败,但手动运行命令却正常

根本原因通常是环境变量、工作目录或权限上下文不一致。systemd 默认不加载用户 shell 的 ~/.bashrc/etc/environmentPATH 也极简(通常只有 /usr/bin:/bin)。

  • systemctl show --Property=Environment <service-name></service-name> 查当前环境
  • 在 service 文件中显式设置:Environment="PATH=/usr/local/bin:/usr/bin:/bin"
  • WorkingDirectory=<code>/path/to/app 避免相对路径失效
  • 如果依赖用户级密钥或 socket(比如 ~/.gnupg),考虑改用 User=root 或配 DynamicUser=yes + StateDirectory=

从 SysV init 迁移到 systemd 时,start-stop-daemon 脚本无法直接复用

systemd 不执行传统 init 脚本里的 fork/daemonize 逻辑,它自己管理进程生命周期。硬套 start-stop-daemon 极易导致状态错乱(比如 systemctl status 显示 inactive (dead),但进程还在跑)。

  • 删掉所有 start-stop-daemonpidfile 相关逻辑
  • Type= 选对:普通前台进程用 Type=simple;需要等待就绪的用 Type=notify(需程序支持 sd_notify);遗留 daemon 用 Type=forking + 正确 PIDFile=
  • 别再写 /var/run/<service>.pid</service>,systemd 自动跟踪主进程 PID
  • 日志统一走 journald,删掉脚本里重定向到 /var/log/xxx.log 的逻辑(除非真有归档需求)

systemctl restart 不生效,或提示 Unit xxx.service not found

不是服务没装,而是 unit 文件没被 systemd 加载识别。常见于自定义 service 文件放错位置、未重载配置、或文件名不匹配。

  • 确认文件路径:用户级服务放 ~/.config/systemd/user/,系统级必须放 /etc/systemd/system/(优先级高于 /usr/lib/systemd/system/
  • 文件名必须以 .service 结尾,且和 systemctl 命令中用的名字完全一致(比如 myapp.service,启动就得用 systemctl start myapp,不能写 myapp.service
  • 改完文件后必须执行 systemctl daemon-reload,否则 systemd 完全无视变更
  • systemctl list-unit-files | grep myapp 确认是否已识别;用 systemctl cat myapp 看实际加载的是哪个文件

为什么 systemctl enable 后开机不自动启动?

enable 只是创建软链接,真正启动取决于 unit 文件里的 WantedBy= 和目标(target)是否激活。最常踩的坑是服务依赖了未启用的 target,或写了 WantedBy=multi-user.target 却系统默认进了 graphical.target(如桌面环境)。

  • 检查 systemctl get-default 输出,确认默认 target 是你要的(比如服务器应为 multi-user.target
  • 确保 service 文件中有 WantedBy=multi-user.target(或对应 target),且没被 ConditionPathExists= 等条件意外屏蔽
  • systemctl is-enabled <service></service> 确认返回 enabled,不是 disabledStatic
  • 如果服务依赖网络,加 After=network-online.targetWants=network-online.target,否则可能因网卡未就绪而跳过启动

真正麻烦的从来不是语法,而是那些没报错、但行为和预期差一拍的上下文细节——比如 journal 日志里没错误,只是进程默默退出了;或者 systemctl status 显示 active,但端口根本没监听。盯住 journalctl -u <service> -n 50 -f</service>systemctl show <service></service>,比反复改配置更省时间。

text=ZqhQzanResources