k8s创建定时的 Python 任务(CronJob)
k8s创建定时的 Python 任务(CronJob)
在 Kubernetes (k8s) 中创建一个每日定时的 Python 任务(CronJob),通常使用 CronJob
资源对象。这个 CronJob 会在指定的时间运行一次 Job,执行你的 Python 脚本。
下面是一个完整的流程:
🧩 场景说明
- 每天凌晨 2:00 执行一个 Python 脚本。
- Python 脚本打包在 Docker 镜像中。
- 使用 Kubernetes 的
CronJob
实现定时任务。
✅ 步骤概览
- 编写 Python 脚本
- 构建 Docker 镜像并推送到镜像仓库
- 创建 Kubernetes CronJob YAML 文件
- 应用 YAML 并验证
1️⃣ 编写 Python 脚本
比如:script.py
# script.py
import datetimeprint("Hello from Python CronJob!")
print(f"Current time: {datetime.datetime.now()}")
2️⃣ 构建 Docker 镜像
Dockerfile 示例:
FROM python:3.10-slimWORKDIR /appCOPY script.py .CMD ["python", "script.py"]
构建并推送镜像(以 Docker Hub 为例):
docker build -t your-dockerhub-username/python-cronjob:latest .
docker push your-dockerhub-username/python-cronjob:latest
3️⃣ 创建 Kubernetes CronJob YAML
文件名:python-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:name: python-daily-jobnamespace: your-namespace
spec:schedule: "0 2 * * *" # 每天 02:00 执行jobTemplate:spec:template:spec:containers:- name: pythonimage: your-dockerhub-username/python-cronjob:latestimagePullPolicy: AlwaysrestartPolicy: OnFailure
Cron 表达式格式:
┌───────────── minute (0 - 59) │ ┌───────────── hour (0 - 23) │ │ ┌───────────── day of the month (1 - 31) │ │ │ ┌───────────── month (1 - 12) │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday) │ │ │ │ │ 0 2 * * *
4️⃣ 部署到 Kubernetes
kubectl apply -f python-cronjob.yaml
查看 CronJob 状态:
kubectl get cronjobs
kubectl get jobs --watch
kubectl get pods
查看日志:
kubectl logs <pod-name>
🧪 测试 CronJob 是否生效
你可以手动触发一次 Job 来测试:
kubectl create job --from=cronjob/python-daily-job manual-run
然后查看 Pod 日志确认是否正常运行。
🔐 可选:私有镜像仓库认证
如果你使用的是私有镜像仓库,需要先创建 imagePullSecrets
:
kubectl create secret docker-registry regcred \--docker-server=<your-registry-server> \--docker-username=<your-name> \--docker-password=<your-pwd> \--docker-email=<your-email>
并在 CronJob 中添加:
imagePullSecrets:- name: regcred
📌 小贴士
- 如果脚本需要访问外部资源(如数据库、API),请确保 Kubernetes 集群网络可达。
- CronJob 默认不会保留历史记录,可以通过
.spec.successfulJobsHistoryLimit
和.spec.failedJobsHistoryLimit
控制保留多少个成功/失败的任务。
❌ 问题
Python 定时任务运行结束后,Pod 没有进入 Completed
状态,而是保持在 Running
状态。查看发现,Pod 中的容器包括:
istio-init
✅ 已完成python-daily-job
✅ 脚本已执行完毕(已完成)istio-proxy
❌ 仍在运行
🧠 原因分析
这是 Istio Sidecar 注入导致的常见问题。
当你在 Kubernetes 集群中启用了 Istio 的自动 Sidecar 注入(即 Pod 被注入了 istio-proxy
容器),默认情况下:
- 即使你的主应用容器(比如
python-daily-job
)已经退出,只要istio-proxy
还在运行,整个 Pod 就不会被标记为Completed
。 - 因为
istio-proxy
是一个长期运行的代理服务,默认行为就是持续监听和转发流量,它不会因为主容器退出而退出。
🚫 导致后果
- CronJob 控制器认为 Job 未完成,因此不会创建下一次定时任务。
- Pod 长时间处于
Running
状态,浪费资源。 .spec.completionTime
不会设置,影响监控和日志清理。
✅ 解决方案
✅ 禁用 Sidecar 注入(推荐用于 Job/CronJob)
对于不需要网络通信或服务治理能力的定时任务来说,不应该注入 Istio Sidecar。
📌 操作方法:
在你的 CronJob YAML 文件中添加注解:
metadata:annotations:sidecar.istio.io/inject: "false"
完整示例:
apiVersion: batch/v1
kind: CronJob
metadata:name: python-daily-jobannotations:sidecar.istio.io/inject: "false" # 关键配置:不注入 Istio Sidecar
spec:schedule: "0 2 * * *"jobTemplate:spec:template:spec:containers:- name: pythonimage: your-dockerhub-username/python-cronjob:latestimagePullPolicy: AlwaysrestartPolicy: OnFailure
✅ 这样部署后,只有你的 Python 容器会被启动,不会有 istio-proxy
和 istio-init
容器。
🔍 如何验证是否生效?
部署更新后的 CronJob:
kubectl apply -f python-cronjob.yaml
然后查看新生成的 Pod:
kubectl get pods
kubectl describe pod <pod-name>
你应该只会看到一个容器:你的 Python 容器,并且当它完成后,Pod 会变成 Completed
状态。
🧪 手动测试技巧
你可以手动触发一次 CronJob:
kubectl create job --from=cronjob/python-daily-job manual-run
然后观察 Pod 状态变化:
kubectl get pods -w
确保 Pod 成功运行并进入 Completed
状态。
📌 总结
问题 | 原因 | 解决方案 |
---|---|---|
Pod 长时间处于 Running 状态 | Istio 注入了 istio-proxy 容器,它不会随主容器退出而退出 | 在 CronJob 上添加 sidecar.istio.io/inject: "false" 注解 |