以下内容汇总了在 Ubuntu 系统下,使用 systemd 定时器(timer) 启动脚本时常遇到的问题、原因排查思路、以及对应的解决方案和检查命令。希望能帮助你在 自动化部署(CI) 场景中顺利完成脚本的开机自启动并进行故障排查。
一、问题背景与现象
- 在 chroot 环境预配置好 systemd 定时器,期望系统开机 100~200 秒后自动执行
ci_auto_launcher.sh
脚本。 - 手动运行脚本(在 bash 中)一切正常,但 systemd timer 启动却失败或没有预期效果:
- 日志中显示脚本执行,但实际业务未成功执行。
nohup.out
文件没有生成或为空。pgrep -f
找不到正在运行的client_starter.py
,而ps aux | grep client_starter.py
却能看到进程。
- 无任何报错或报错信息不明显,给排查带来困难。
二、常见根因分析
- 环境差异: systemd 启动脚本时,默认不加载用户登录 Shell 的环境变量(如 PATH、PYTHONPATH 等),导致脚本内
python3.8
、命令路径、依赖环境无法找到。 - 当前工作目录不同: systemd 默认工作目录是
/
,脚本里如果使用相对路径或未正确cd
到目标目录,则导致文件读写失败、日志路径失效。 - 定时器运行时机: 虽然设置了
OnBootSec=200s
,但有时网络、DNS、驱动还未完全就绪,需要在脚本内再做一次等待/重试逻辑。 - nohup 日志不见: 通常是由于
mkdir
失败、脚本路径不对、或python3.8
找不到导致脚本瞬间退出,日志被写在未知位置或根本未创建。 - pgrep -f 匹配规则导致漏查:
pgrep -f client_starter.py
有时无法匹配到,特别是长命令行或被截断、加引号等问题,ps aux | grep client_starter.py
能更直观地看到完整进程信息。
三、重点解决方案
1. 使用绝对路径,避免找不到命令
- 将
python3.8
改为/usr/bin/python3.8
(先用which python3.8
确认实际路径)。 - 在脚本中对所有命令、脚本引用文件、日志文件,都使用 绝对路径,避免工作目录不一致。
2. 指定 systemd 的工作目录(可选)
在你的 .service
文件中增加:
[Service]
WorkingDirectory=/root/tools
或在脚本开头显式:
cd /root/tools || exit 1
保证后续的相对路径正确。
3. 脚本内进行网络 / DNS 就绪检测与重试
在 ci_auto_launcher.sh
内,开头加循环检测 DNS、等待网络稳定,例如:
while ! getent hosts "$website" > /dev/null; do
echo "⏳ DNS 尚未可用,等待中..."
sleep 5
done
确保网络真的就绪后再往下执行,避免定时器跑得太早。
4. 在脚本开头输出调试日志(极大方便排查)
#!/bin/bash
set -x # 打印每行命令
exec > /tmp/ci_debug.log 2>&1
echo "🔥 脚本启动: $(date)"
echo "📍 当前目录: $(pwd)"
echo "👤 当前用户: $(whoami)"
echo "🧠 环境PATH: $PATH"
which python3.8 || echo "❌ python3.8 不在 PATH"
这样你就能在 /tmp/ci_debug.log
中看到脚本的执行流程,以及是否报错。
5. 检查 mkdir
、nohup
调用是否成功
给 mkdir -p
等关键操作加错误检测:
mkdir -p "$file_pth" || {
echo "❌ 创建目录失败:$file_pth"
exit 1
}
这样能及时知道日志目录没建成。
四、常用检查与排错命令
-
查看定时器是否已启用:
systemctl list-timers --all | grep ci_auto_launcher
或者直接看目标目录是否有软链接:
ls -l /etc/systemd/system/timers.target.wants/ci_auto_launcher.timer
-
查看服务日志
journalctl -u ci_auto_launcher.service --no-pager -n 50
如果脚本中
echo
/set -x
输出到标准输出或标准错误,就能在这里看到。 -
检查脚本自身输出日志 (
nohup.out
)find /root/tools -name nohup.out | xargs tail -n 30
有时可以直接搜 error:
find /root/tools -name nohup.out | xargs grep -i "error"
-
进程检查
ps aux | grep '[c]lient_starter.py'
- 或
pgrep -a python3.8 | grep client_starter.py
- 有时
pgrep -f client_starter.py
会漏匹配,最好用ps aux | grep
-
验证绝对路径是否可用
which python3.8
如果输出
/usr/bin/python3.8
,则在脚本中要写/usr/bin/python3.8
,而非python3.8
。 -
手动触发 service 进行调试
# 启动一次服务 systemctl start ci_auto_launcher.service # 查看状态和日志 systemctl status ci_auto_launcher.service journalctl -u ci_auto_launcher.service
如果可以正常跑通,说明定时器没问题,下一次开机后会自动启动。
-
实时附加到 systemd-run (调试)
systemd-run --unit=test-ci --pty /root/tools/ci_auto_launcher.sh
它会立即用 systemd 环境执行脚本,并在当前终端显示所有 stdout/stderr 信息,方便即时查看错误。
五、综合思路与步骤
- 先在 Shell 中测试脚本:确保脚本逻辑、路径、安装的 Python 都没问题。
- 改脚本为绝对路径 + 写 debug 输出:避免 systemd 环境差异。
- 临时用 systemd-run --pty 来模拟定时器环境,看脚本是否成功。
- 正式启用 timer:
OnBootSec=200s
,然后systemctl reboot
测试;查看journalctl -u ci_auto_launcher.service
。 - 查看 nohup.out / /tmp/ci_debug.log:如果为空或不存在,九成是命令找不到 / 脚本秒退。
六、附:推荐的脚本改进点
- 脚本最前面写:
#!/bin/bash set -x exec > /tmp/ci_debug.log 2>&1 # 全部输出到这个文件 cd /root/tools || exit 1 # 切换目录,防止 systemd 处于 / PYTHON="/usr/bin/python3.8" # 确定绝对路径
- mkdir 失败要有提示
- 网络等待 / DNS 检测
- 完成后记录结果:在脚本最后写:
echo "[$(date)] - 执行成功" >> /var/log/ci_auto_launcher_success.log
结语
只要抓住 systemd 和 shell 环境的区别、网络/DNS 的时序性、脚本路径及日志输出 这几条主线,绝大多数“手动 OK,定时器失败”问题都能迎刃而解。希望这份整理能够让你快速定位并解决在 Ubuntu autoinstall + systemd timer 下的自动化脚本部署故障。祝一切顺利!