如何在 Docker 容器内运行 cron 定时任务?
容器内跑 cron:Dockerfile 装 cron、COPY crontab 文件、入口脚本用 cron -f 前台运行;注意 cron 不继承容器环境变量。K8s 场景推荐改用 CronJob。本文给出完整 Dockerfile 示例。
基本步骤:镜像里装 cron → COPY crontab 文件到 /etc/cron.d/ → 入口脚本里 cron 启动守护进程(注意环境变量问题:cron 不继承 docker run -e 传入的变量,需导出到 /etc/environment)。不过容器里跑 cron 是妥协方案,K8s 环境优先用 CronJob,单机也可用宿主机 cron 调 docker exec。
完整 Dockerfile 示例
FROM python:3.12-slim
RUN apt-get update && apt-get install -y cron && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
# 拷贝定时任务定义
COPY crontab /etc/cron.d/app-cron
RUN chmod 0644 /etc/cron.d/app-cron && crontab /etc/cron.d/app-cron
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
crontab 文件:
*/10 * * * * . /etc/environment; python /app/jobs/cleanup.py >> /proc/1/fd/1 2>&1
#!/bin/bash
set -e
printenv > /etc/environment # 把容器环境变量导出给 cron 用
cron # 启动 cron 守护进程
exec python app.py # 主进程前台运行
三个必踩的坑
- 环境变量:cron 不继承容器环境,
printenv > /etc/environment+ 任务里 source 是标准解法 - 任务输出:cron 任务默认输出无处可看,重定向到
/proc/1/fd/1(主进程 stdout),这样docker logs和日志采集能拿到 - 双进程:cron + 应用 = 一个容器俩进程,违背了单进程原则,supervisor 类问题(挂了谁拉谁)要自己想清楚
更推荐的替代方案
| 方案 | 适用 |
|---|---|
| K8s CronJob | K8s 环境首选,任务独立 Pod,环境变量天然注入 |
| 宿主机 cron + docker exec | 单机少量任务,容器保持单进程 |
| 应用内调度器 | APScheduler / node-cron,与应用同进程 |
观测云对照
定时任务必须可监控。 任务输出经 stdout 被 DataKit 采集后,用监控器配置"预期时间窗口内无成功日志即告警",cron 静默失效(任务没跑、跑了失败)都能被抓住。
常见问题(FAQ)
Q:cron 容器时区不对?
A:镜像默认 UTC,挂载 -v /etc/localtime:/etc/localtime:ro 或镜像里设置 TZ 环境变量并装 tzdata。
Q:任务没执行怎么查?
A:进容器 grep CRON /var/log/syslog(需 rsyslog)或直接看重定向到 stdout 的输出;先手动跑一遍命令确认命令本身没问题。
Q:Alpine 镜像怎么装 cron?
A:Alpine 自带 crond(busybox),crond -f 前台启动即可,crontab 文件放 /etc/crontabs/root。