这是典型的PID文件残留问题:脚本异常退出未清理PID文件,导致启动脚本误判服务已在运行而拒绝启动;需检查进程真实性、PID路径一致性、权限、systemd配置匹配性、信号捕获及/run挂载状态。

service启动时提示“PID file exists but process not running”
这是典型的PID文件残留问题:脚本上次异常退出没清理/var/run/xxx.pid或/run/xxx.pid,systemd或init脚本检查到该文件存在,就直接放弃启动,认为服务已在运行。实际进程早就没了。
关键判断点是:不是服务真在跑,而是启动逻辑被PID文件“骗”了。
- 先确认进程是否真不存在:
ps -p $(cat /var/run/myapp.pid 2>/dev/null)—— 如果报“no such process”,说明PID文件失效 - 再确认PID文件路径是否和unit文件里
PIDFile=配置一致(常见位置有/var/run/、/run/、/var/lib/) - 注意权限:如果脚本以普通用户运行,但PID文件被root创建(比如用sudo启动过一次),后续非root启动会因权限不足无法覆盖该文件
systemd服务中PIDFile配置与实际不匹配
很多老式脚本沿用SysV风格,自己写PID文件,但systemd的PIDFile=参数只认“主进程”的PID——而脚本可能fork了子进程,或者用nohup ./app &方式启动,导致写入PID文件的不是真正主进程PID。
后果是:systemd读取PID文件后去kill那个PID,结果杀错人;或重启时发现PID还在,误判服务存活。
- 检查unit文件:
systemctl cat myapp.service | grep PIDFile,确认路径是否真实由脚本写入 - 脚本中写PID必须用
echo $$ > /run/myapp.pid(不是$!),因为$$是shell自身PID,才是systemd能跟踪的主进程 - 更稳妥的做法是干脆去掉
PIDFile=,改用Type=simple+ExecStart=直接启动二进制,让systemd自己管理PID
脚本未处理信号导致PID文件残留
当用kill(非-9)终止脚本时,若脚本没注册SIGTERM处理器,就不会执行清理逻辑(如rm /run/myapp.pid),下次启动就被卡住。
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
尤其要注意:systemd默认发SIGTERM,等10秒才SIGKILL;如果脚本忽略或没响应SIGTERM,PID文件就永远留在那里。
- 在脚本开头加信号捕获:
trap 'rm -f /run/myapp.pid; exit 0' TERM INT EXIT - 避免用
nohup或setsid绕过shell信号传递,否则trap失效 - 测试方式:
kill $(cat /run/myapp.pid),然后立刻检查PID文件是否消失
/run目录被清空或挂载异常
/run是tmpfs,系统重启必清空;但某些场景下(如k8s initContainer提前挂载、手动mount --bind覆盖),可能导致/run/myapp.pid写入失败,或写入后立即丢失。
这时候日志里常出现“Permission denied”或“No such file or directory”,但错误指向模糊。
- 检查
/run挂载状态:findmnt -T /run,确认它是tmpfs且可写 - 验证写入能力:
touch /run/test.pid && rm /run/test.pid - 若服务依赖特定子目录(如
/run/myapp/),确保脚本启动前已用mkdir -p /run/myapp创建,且chown正确
最易被忽略的是:PID文件路径在脚本里硬编码为/var/run,但现代系统符号链接到/run,而某些容器环境或minimal镜像里这个链接根本不存在——此时echo $$ > /var/run/app.pid会静默失败,连文件都没生成,后续所有基于PID文件的判断全乱套。










