Cron任务无法执行含docker exec的PostgreSQL备份脚本问题排查
以下是最可能的几个原因及对应解决方法:
Cron环境PATH缺失Docker路径
Cron的默认PATH远窄于终端,比如终端里执行which docker会得到/usr/bin/docker这类绝对路径,但Cron的默认PATH可能仅包含/usr/bin:/bin,若Docker安装在其他路径(如/usr/local/bin),脚本里直接调用docker会静默失败。由于脚本未做错误检查,仍会返回成功状态,导致日志显示执行完成但无备份生成。
解决:- 在终端执行
which docker获取Docker的绝对路径 - 将脚本里的
docker替换为该绝对路径,或在脚本开头添加PATH=$PATH:/usr/bin(根据实际路径调整) - 也可在Cron任务行开头指定完整PATH,比如:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin * * * * * /path/to/do-pg-backup.sh
- 在终端执行
脚本使用相对路径导致备份文件位置不符
终端执行脚本时,工作目录是你当前所在的文件夹,但Cron执行时默认工作目录为用户家目录(如/root或/home/your-user)。如果脚本里备份输出路径用的是相对路径(比如./backups),备份文件会生成在Cron的工作目录里,而非你预期的位置,误以为未生成备份。
解决:把脚本里所有涉及文件/目录的路径都改成绝对路径,比如将./backups改为/var/lib/postgresql/backups。Cron执行用户无Docker访问权限
终端里的用户可能在docker用户组中,能直接运行docker命令,但Cron执行时的环境未加载组权限(或你用普通用户的Cron,该用户不在docker组),导致docker exec因权限不足失败。
解决:- 检查执行Cron的用户:若为普通用户,执行
groups查看是否包含docker,若没有则运行sudo usermod -aG docker your-user,重新登录生效 - 直接使用root的Cron(切换到root后执行
crontab -e) - 若必须用普通用户,可在脚本里用
sudo docker exec,并给该用户配置免密sudo(编辑/etc/sudoers添加your-user ALL=(ALL) NOPASSWD: /usr/bin/docker)
- 检查执行Cron的用户:若为普通用户,执行
脚本无错误处理,失败不触发告警
你的脚本可能未设置错误捕获,比如docker exec失败后脚本仍继续执行并返回0状态码,导致Cron日志显示"执行完成",但实际备份已失败。
解决:- 在脚本开头添加
set -euo pipefail,让脚本在任何命令失败时立即退出并返回非0码 - 给关键命令添加错误检查,比如:
if ! docker exec pg-container /opt/pg-backup.sh; then echo "$(date): Docker exec failed" >> /var/log/pg-backup-error.log exit 1 fi - 配置Cron把错误输出到日志,比如Cron任务行改为:
* * * * * /path/to/do-pg-backup.sh >> /var/log/pg-backup.log 2>&1,这样能捕获到具体错误信息。
- 在脚本开头添加
时区不一致导致备份逻辑异常(少见)
如果容器内的pg-backup.sh依赖特定时区,而Cron的时区与终端/容器时区不一致,可能导致备份逻辑跳过或失败。
解决:在Cron任务行开头指定时区,比如TZ=Asia/Shanghai * * * * * /path/to/do-pg-backup.sh,或在脚本里设置时区环境变量。
内容的提问来源于stack exchange,提问作者brando

