0°

Ubuntu 系统下,使用 systemd 定时器(timer) 启动脚本时常遇到的问题、原因排查思路、以及对应的解决方案和检查命令

以下内容汇总了在 Ubuntu 系统下,使用 systemd 定时器(timer) 启动脚本时常遇到的问题、原因排查思路、以及对应的解决方案和检查命令。希望能帮助你在 自动化部署(CI) 场景中顺利完成脚本的开机自启动并进行故障排查。

一、问题背景与现象

  1. 在 chroot 环境预配置好 systemd 定时器,期望系统开机 100~200 秒后自动执行 ci_auto_launcher.sh 脚本。
  2. 手动运行脚本(在 bash 中)一切正常,但 systemd timer 启动却失败或没有预期效果:
    • 日志中显示脚本执行,但实际业务未成功执行。
    • nohup.out 文件没有生成或为空。
    • pgrep -f 找不到正在运行的 client_starter.py,而 ps aux | grep client_starter.py 却能看到进程。
  3. 无任何报错或报错信息不明显,给排查带来困难。

二、常见根因分析

  1. 环境差异: systemd 启动脚本时,默认不加载用户登录 Shell 的环境变量(如 PATH、PYTHONPATH 等),导致脚本内 python3.8、命令路径、依赖环境无法找到。
  2. 当前工作目录不同: systemd 默认工作目录是 /,脚本里如果使用相对路径或未正确 cd 到目标目录,则导致文件读写失败、日志路径失效。
  3. 定时器运行时机: 虽然设置了 OnBootSec=200s,但有时网络、DNS、驱动还未完全就绪,需要在脚本内再做一次等待/重试逻辑。
  4. nohup 日志不见: 通常是由于 mkdir 失败、脚本路径不对、或 python3.8 找不到导致脚本瞬间退出,日志被写在未知位置或根本未创建。
  5. 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. 检查 mkdirnohup 调用是否成功

mkdir -p 等关键操作加错误检测

mkdir -p "$file_pth" || {
  echo "❌ 创建目录失败:$file_pth"
  exit 1
}

这样能及时知道日志目录没建成。

四、常用检查与排错命令

  1. 查看定时器是否已启用:

    systemctl list-timers --all | grep ci_auto_launcher

    或者直接看目标目录是否有软链接:

    ls -l /etc/systemd/system/timers.target.wants/ci_auto_launcher.timer
  2. 查看服务日志

    journalctl -u ci_auto_launcher.service --no-pager -n 50

    如果脚本中 echo / set -x 输出到标准输出或标准错误,就能在这里看到。

  3. 检查脚本自身输出日志 (nohup.out)

    find /root/tools -name nohup.out | xargs tail -n 30

    有时可以直接搜 error:

    find /root/tools -name nohup.out | xargs grep -i "error"
  4. 进程检查

    • ps aux | grep '[c]lient_starter.py'
    • pgrep -a python3.8 | grep client_starter.py
    • 有时 pgrep -f client_starter.py 会漏匹配,最好用 ps aux | grep
  5. 验证绝对路径是否可用

    which python3.8

    如果输出 /usr/bin/python3.8,则在脚本中要写 /usr/bin/python3.8,而非 python3.8

  6. 手动触发 service 进行调试

    # 启动一次服务
    systemctl start ci_auto_launcher.service
    
    # 查看状态和日志
    systemctl status ci_auto_launcher.service
    journalctl -u ci_auto_launcher.service

    如果可以正常跑通,说明定时器没问题,下一次开机后会自动启动。

  7. 实时附加到 systemd-run (调试)

    systemd-run --unit=test-ci --pty /root/tools/ci_auto_launcher.sh

    它会立即用 systemd 环境执行脚本,并在当前终端显示所有 stdout/stderr 信息,方便即时查看错误。

五、综合思路与步骤

  1. 先在 Shell 中测试脚本:确保脚本逻辑、路径、安装的 Python 都没问题。
  2. 改脚本为绝对路径 + 写 debug 输出:避免 systemd 环境差异。
  3. 临时用 systemd-run --pty 来模拟定时器环境,看脚本是否成功。
  4. 正式启用 timerOnBootSec=200s,然后 systemctl reboot 测试;查看 journalctl -u ci_auto_launcher.service
  5. 查看 nohup.out / /tmp/ci_debug.log:如果为空或不存在,九成是命令找不到 / 脚本秒退。

六、附:推荐的脚本改进点

  1. 脚本最前面写:
    #!/bin/bash
    set -x
    exec > /tmp/ci_debug.log 2>&1  # 全部输出到这个文件
    cd /root/tools || exit 1       # 切换目录,防止 systemd 处于 /
    PYTHON="/usr/bin/python3.8"    # 确定绝对路径
  2. mkdir 失败要有提示
  3. 网络等待 / DNS 检测
  4. 完成后记录结果:在脚本最后写:
    echo "[$(date)] - 执行成功" >> /var/log/ci_auto_launcher_success.log

结语

只要抓住 systemd 和 shell 环境的区别网络/DNS 的时序性脚本路径及日志输出 这几条主线,绝大多数“手动 OK,定时器失败”问题都能迎刃而解。希望这份整理能够让你快速定位并解决在 Ubuntu autoinstall + systemd timer 下的自动化脚本部署故障。祝一切顺利!

0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论