在linux中为自定义服务添加前置检查脚本,核心是通过systemd的execstartpre指令在启动前执行校验逻辑,如检查配置文件、端口占用、依赖服务状态等,任一检查失败则中止启动。

在 Linux 中为自定义服务添加前置检查脚本,核心是让服务启动前自动执行校验逻辑(比如端口占用、配置文件存在性、依赖服务是否就绪等),失败则中止启动。这通常通过 systemd 的 ExecStartPre 指令实现,无需修改服务主程序,也不依赖外部调度器。
使用 ExecStartPre 直接嵌入检查命令
这是最常用、最轻量的方式。在服务单元文件(如 /etc/systemd/system/myapp.service)的 [Service] 段中添加 ExecStartPre:
- 每条
ExecStartPre=行执行一个命令,按顺序运行;任一命令返回非 0 状态,启动立即终止 - 支持完整 shell 语法,但注意:systemd 不调用 shell 解释器,如需管道、重定向或 &&,需显式调用
/bin/sh -c - 路径必须绝对,环境变量默认不继承,需显式指定(如
PATH=/usr/local/bin:/usr/bin:/bin)
示例:
[Service] Type=simple ExecStartPre=/usr/bin/test -f /etc/myapp/config.yaml ExecStartPre=/bin/sh -c 'lsof -i :8080 > /dev/null || exit 0' ExecStartPre=/usr/bin/systemctl is-active --quiet nginx ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yaml
说明:依次检查配置文件是否存在、8080 端口是否空闲(lsof 未找到时退出码为 1,用 || exit 0 反转为成功)、nginx 是否正在运行。
封装为独立检查脚本并调用
当检查逻辑较复杂(如多步验证、日志记录、超时等待)时,建议写成独立脚本(如 /usr/local/libexec/myapp-precheck),再由 ExecStartPre 调用:
- 脚本需有可执行权限(
chmod +x),推荐使用#!/bin/sh保证兼容性 - 脚本内应明确处理错误并返回恰当退出码(0 表示通过,非 0 表示失败)
- 可在脚本中使用
logger记录检查过程,便于排查启动失败原因
示例脚本内容:
#!/bin/sh
[ -r "/etc/myapp/config.yaml" ] || { logger -t myapp "Config missing or unreadable"; exit 1; }
if ss -tln | grep -q ':8080'; then
logger -t myapp "Port 8080 already in use"
exit 1
fi
systemctl is-active --quiet redis || { logger -t myapp "Redis not running"; exit 1; }
对应服务单元中写:ExecStartPre=/usr/local/libexec/myapp-precheck
配合 Wants/After 确保依赖服务已就绪
ExecStartPre 只做检查,不负责启动依赖项。若需确保某服务(如数据库)先启动并进入 active 状态,应在 [Unit] 段声明依赖关系:
-
Wants=postgresql.service表示“希望它运行”,但不强制等待 -
After=postgresql.service表示“本服务启动时机晚于 PostgreSQL”,配合Wants才能真正触发依赖启动 - 检查脚本中仍需用
systemctl is-active确认状态,因为After仅控制启动顺序,不保证服务已 ready
典型组合:
[Unit] Description=My App Service Wants=postgresql.service After=postgresql.service [Service] ExecStartPre=/usr/local/libexec/myapp-precheck ExecStart=/usr/local/bin/myapp
调试与验证方法
前置检查失败时,systemd 默认只显示“failed to start”,需主动排查:
- 运行
systemctl daemon-reload重载单元文件变更 - 用
systemctl start myapp.service手动触发,再执行systemctl status myapp.service查看最近一次失败的详细信息(含ExecStartPre的具体报错) - 用
journalctl -u myapp.service -n 50 --no-pager查看完整日志,包括检查脚本输出(如果用了logger) - 临时在检查命令后加
&& echo "OK"或重定向到文件,确认命令是否被执行











