在 Docker 容器中執行排程任務(Cron Job)是常見的需求,但 Docker 容器的設計原則是「一個容器執行一個程序」,因此直接在容器內跑 cron 並不是最理想的做法。本文整理幾種常見方案,以及各自的優缺點。
方式一:在容器內安裝並執行 cron
最直接的方式是在 Dockerfile 中安裝 cron,並讓它作為主程序執行。
Dockerfile 範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
FROM debian:bullseye-slim
# 安裝 cron
RUN apt-get update && apt-get install -y cron && rm -rf /var/lib/apt/lists/*
# 複製 crontab 設定
COPY crontab /etc/cron.d/my-cron
# 設定正確的權限
RUN chmod 0644 /etc/cron.d/my-cron
# 套用 crontab
RUN crontab /etc/cron.d/my-cron
# 建立 log 檔案
RUN touch /var/log/cron.log
# 啟動 cron 並輸出 log
CMD cron && tail -f /var/log/cron.log
|
crontab 檔案內容
1
2
3
4
5
|
# 每天凌晨 2 點執行備份腳本
0 2 * * * root /scripts/backup.sh >> /var/log/cron.log 2>&1
# 每 5 分鐘執行一次
*/5 * * * * root /scripts/check.sh >> /var/log/cron.log 2>&1
|
注意事項
- 環境變數問題:cron 執行時不會載入 Docker 的環境變數(
-e 傳入的),需在腳本中明確讀取或用 /proc/1/environ 導入
- 時區問題:容器預設時區為 UTC,可設定
TZ 環境變數或掛載 /etc/localtime
1
2
3
|
# docker-compose.yml 設定時區
environment:
- TZ=Asia/Taipei
|
方式二:使用 docker-compose 與獨立 cron 容器
將排程邏輯分離到獨立容器,保持主應用容器乾淨。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# docker-compose.yml
version: '3.8'
services:
app:
image: my-app:latest
ports:
- "8080:80"
cron:
image: my-app:latest
command: cron -f # 前台執行 cron
volumes:
- ./scripts:/scripts
environment:
- TZ=Asia/Taipei
depends_on:
- app
|
方式三:使用 Ofelia 排程工具
Ofelia 是專為 Docker 設計的排程工具,可透過 docker-compose.yml 標籤設定,不需要修改現有容器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
version: '3.8'
services:
ofelia:
image: mcuadros/ofelia:latest
depends_on:
- app
command: daemon --docker
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
app:
image: my-app:latest
labels:
ofelia.enabled: "true"
ofelia.job-exec.backup.schedule: "0 2 * * *"
ofelia.job-exec.backup.command: "/scripts/backup.sh"
|
方式四:Kubernetes CronJob(生產環境推薦)
若使用 Kubernetes,可使用內建的 CronJob 資源,不需要在容器中跑 cron daemon:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-backup-job
spec:
schedule: "0 2 * * *" # 每天凌晨 2 點
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: my-app:latest
command: ["/scripts/backup.sh"]
restartPolicy: OnFailure
|
各方式比較
| 方式 |
適用情境 |
優點 |
缺點 |
| 容器內 cron |
簡單專案、單機部署 |
簡單直接 |
環境變數問題、違反單一職責 |
| 獨立 cron 容器 |
Docker Compose 專案 |
責任分離 |
需要額外容器 |
| Ofelia |
Docker 環境 |
設定簡潔 |
需要存取 Docker Socket |
| Kubernetes CronJob |
生產環境、K8s 叢集 |
官方支援、可靠 |
需要 K8s 環境 |
參考資料