Docker 容器中运行定时任务
FreeGuideOnline
最新
2026-07-06
bash #!/bin/bash echo "$(date): 开始归档日志..." >> /var/log/app/cron.log
实际的业务逻辑,例如压缩旧日志
find /var/log/app/ -name "*.log" -mtime +7 -exec gzip {} ;
确保脚本有可执行权限:`chmod +x /usr/local/bin/archive-logs.sh`
### 步骤 2:创建 Crontab 定义文件
在项目目录下创建 `crontab` 文件,例如 `my-crontab`:
每分钟执行一次(仅用于测试)
-
-
-
-
- /usr/local/bin/archive-logs.sh >> /var/log/app/cron.log 2>&1
-
-
-
每天凌晨2点执行数据清理
0 2 * * * /usr/local/bin/cleanup-tmp.sh
### 步骤 3:编写 Dockerfile 并让 Cron 作为主进程
关键技术点:**将 cron 运行在前台**,并处理环境变量传递。
```dockerfile
FROM ubuntu:22.04
# 安装 cron 和必要的工具
RUN apt-get update && apt-get install -y cron && rm -rf /var/lib/apt/lists/*
# 创建应用目录和日志文件
RUN mkdir -p /var/log/app && touch /var/log/app/cron.log
# 复制脚本和 crontab
COPY archive-logs.sh /usr/local/bin/archive-logs.sh
COPY cleanup-tmp.sh /usr/local/bin/cleanup-tmp.sh
COPY my-crontab /etc/cron.d/my-crontab
# 赋予执行权限
RUN chmod +x /usr/local/bin/*.sh
# 应用 crontab
RUN crontab /etc/cron.d/my-crontab
# 创建启动脚本,解决环境变量传递与前台运行问题
RUN echo '#!/bin/bash\nprintenv | grep -v "no_proxy" >> /etc/environment\ncron -f' > /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]
核心解释:
cron -f让 cron 守护进程在前台运行,成为容器的主进程。printenv | grep -v "no_proxy" >> /etc/environment这一步极为关键:因为 cron 运行任务时使用的环境非常干净,不会自动继承 Docker 容器传入的环境变量。通过将环境变量写入/etc/environment,cron 的子进程便能够读取到它们。- 我们也可以在任务脚本内部手动加载所需变量,但上述方法更为通用。
构建并运行:
docker build -t my-cron-app .
docker run -d --name cron-test my-cron-app
查看日志验证任务执行:
docker exec -it cron-test tail -f /var/log/app/cron.log
适用场景与局限
- 优点:依赖简单,镜像自包含,方便移植。
- 缺点:每个容器仅能跑一个 cron 守护进程;任务失败通知较困难;日志容易被淹没;需自行处理环境变量。
方法二:使用 轻量级 Cron 替代品 —— supercronic
Supercronic 是一个用 Go 编写的 cron 运行器,专为容器而生。它能够正确转发信号、处理日志、且无需复杂的启动脚本。
Dockerfile 示例(基于 Alpine)
FROM alpine:latest
# 安装 supercronic(直接下载二进制)
ENV SUPERCRONIC_VERSION=v0.2.29
RUN wget -O /usr/local/bin/supercronic \
https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-amd64 \
&& chmod +x /usr/local/bin/supercronic
COPY my-crontab /etc/crontab
COPY archive-logs.sh /usr/local/bin/archive-logs.sh
CMD ["/usr/local/bin/supercronic", "/etc/crontab"]
Supercronic 自动将整个环境变量传递给任务,且会输出结构化的任务执行日志到 stdout/stderr,非常适合配合 Docker 日志驱动。遇到任务失败时,它会以非零状态退出,便于容器编排平台检测。
方法三:宿主机 Cron 调用容器执行一次性命令
如果你不希望修改镜像,或者定时任务属于“管理类”操作(如备份整个应用),可以由宿主机的 cron 配合 docker exec 完成。
宿主机 Crontab 示例
# 每天凌晨1点执行容器内的备份脚本
0 1 * * * docker exec my-app-container /usr/local/bin/backup.sh
优点:无需改动镜像,集中管理任务。 缺点:与宿主机耦合,容器名称或 ID 变化时需要更新;需关注容器存活状态;破坏了容器的自包含性。
方法四:使用容器编排工具的原生定时任务支持
Docker Swarm 模式
Swarm 本身不直接支持 CronJob,但可以通过调度全局或副本服务并结合 sleep 技巧实现,但不够优雅。更好的方式是利用第三方工具如 Ofelia。
Kubernetes 中的 CronJob
在生产环境中,Kubernetes CronJob 是运行定时任务的首选方案。它完全遵循云原生理念。
定义一个 CronJob YAML
apiVersion: batch/v1
kind: CronJob
metadata:
name: archive-logs
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: archiver
image: your-registry/log-archiver:latest
args:
- /bin/sh
- -c
- /usr/local/bin/archive-logs.sh
restartPolicy: OnFailure
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1