
我们发现部署在香港节点的一台容器化应用服务器(Docker容器)未按预期执行其cron定时任务。该容器承载了日志归档任务,负责每天凌晨 2:00 将 Web 应用日志打包并同步至对象存储。然而连续几日未见归档文件,S3 端也未有更新。
由于该服务涉及 SLA 日志留存合规要求,问题需要紧急排查并彻底解决。
初步排查:定时任务未执行
1. 检查 cron 服务状态
容器内已安装 cron,查看状态如下:
ps aux | grep cron
结果显示 cron 服务正常运行,无异常退出记录。
2. 查看 crontab 配置
crontab -l
输出如下:
0 2 * * * /usr/local/bin/log_archive.sh >> /var/log/cron.log 2>&1
脚本路径正确,权限可执行。表面看似配置无误,但日志文件 /var/log/cron.log 中并无任何记录,说明任务根本未触发。
深入排查一:时区问题
1. 主机与容器时区不一致
宿主机为中国香港服务器,默认时区为 Asia/Hong_Kong。但容器构建自官方 python:3.11-slim 镜像,默认时区为 UTC。
进入容器内部执行:
date
输出时间为 UTC,确认为时区问题。
2. 修正方案:统一容器时区
修改 Dockerfile,添加时区设置:
RUN apt-get update && apt-get install -y tzdata \
&& ln -fs /usr/share/zoneinfo/Asia/Hong_Kong /etc/localtime \
&& dpkg-reconfigure -f noninteractive tzdata
重新构建并部署容器后,时间显示与宿主机一致。观察 cron 日志,任务开始执行。
深入排查二:权限问题
问题貌似解决,但在另一台语言环境不同的容器中(基于 alpine 构建)依然未执行定时任务。排查过程中发现以下关键点:
1. cron 文件权限限制
Alpine 使用 crond(BusyBox 实现),其要求任务必须由容器内有权用户添加,默认用户非 root。我们之前使用了 appuser 用户构建镜像,并在入口命令中使用:
USER appuser
但该用户无权限执行 crond。
2. 修复方式一:容器中以 root 身份运行 crond
修改 Dockerfile 或入口命令:
USER root
CMD ["crond", "-f"]
确保 cron 任务由 root 添加和执行。
3. 修复方式二:使用 supervisord 管理多进程
若容器中同时运行应用和 cron,可以使用 supervisord 统一管理:
supervisord.conf 示例:
[supervisord]
nodaemon=true
[program:app]
command=python /app/main.py
autostart=true
autorestart=true
[program:cron]
command=crond -f
autostart=true
autorestart=true
确保两个服务并行启动,互不干扰。
脚本调试建议
即使 cron 正常调度,任务也可能因脚本错误导致执行失败。建议在脚本开头添加如下调试输出:
#!/bin/bash
echo "Log archive script started at $(date)" >> /var/log/archive_debug.log
并确保脚本具有可执行权限:
chmod +x /usr/local/bin/log_archive.sh
最终解决方案汇总
- 统一容器时区:确保 Docker 镜像中设置为 Asia/Hong_Kong。
- 使用 root 或适当权限用户启动 crond。
- 在多进程容器中使用 supervisord 管理 cron 与主进程。
- 增加调试日志,确保脚本实际被触发并执行成功。
- 持久化 cron 日志,可将其挂载到宿主机或监控平台。
本次问题的排查充分说明了在容器化多语言环境中,cron 服务的时区、权限和进程管理需要格外注意。若不仔细处理,很容易出现“看似正常实则未执行”的假象。希望本篇实录能为类似问题提供有效的排查路径与解决思路。
如有涉及Kubernetes、CI/CD 自动部署等更复杂场景,建议配合Job控制器或计划任务框架(如 Apache Airflow)进行统一管理,以提升稳定性与可 observability 性。











