k8s创建定时的 Python 任务(CronJob)
问题原因解决方案Pod 长时间处于Running状态Istio 注入了容器,它不会随主容器退出而退出在 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 datetime
print("Hello from Python CronJob!")
print(f"Current time: {datetime.datetime.now()}")
2️⃣ 构建 Docker 镜像
Dockerfile 示例:
FROM python:3.10-slim
WORKDIR /app
COPY 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-job
namespace: your-namespace
spec:
schedule: "0 2 * * *" # 每天 02:00 执行
jobTemplate:
spec:
template:
spec:
containers:
- name: python
image: your-dockerhub-username/python-cronjob:latest
imagePullPolicy: Always
restartPolicy: 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-job
namespace: your-namespace
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: python
image: your-dockerhub-username/python-cronjob:latest
imagePullPolicy: Always
restartPolicy: 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" 注解 |
🔍保留已完成的 Pod
✅ 需求总结
- 使用的是 Kubernetes CronJob 创建的 Job/Pod。
- Python 脚本运行完成后 Pod 状态变为
Completed。 - 默认情况下,Kubernetes 不会保留已完成的 Job 和 Pod。
- 目标:让这些已完成的 Pod 保留 24 小时后再被自动删除。
🧠 原因分析
Kubernetes 的 Job 控制器默认不会保留已完成的 Job 和 Pod。你可以通过 .spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit 来控制保留多少个成功或失败的 Job(以及对应的 Pod)。
但默认值通常为:
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
如果你希望每个完成的 Pod 保留 24 小时而不是固定数量的历史任务,就需要额外机制来实现。
✅ 使用 TTL 控制器(推荐)
Kubernetes 提供了一个非常方便的功能叫做 TTL 控制器(TTL Controller for Finished Resources),可以让你指定一个已完成的资源(如 Job、Pod)在多长时间之后被自动删除。
✅ 实现方式
只需要在你的 Job 模板中添加 .spec.ttlSecondsAfterFinished 字段即可。
修改你的 CronJob YAML 如下:
apiVersion: batch/v1
kind: CronJob
metadata:
name: python-daily-job
namespace: your-namespace
spec:
schedule: "0 2 * * *"
successfulJobsHistoryLimit: 1 # 可选:只保留最近一次成功任务
failedJobsHistoryLimit: 1 # 可选:只保留最近一次失败任务
jobTemplate:
spec:
template:
metadata:
annotations:
sidecar.istio.io/inject: "false" # 如果你不希望注入 Istio Sidecar
spec:
ttlSecondsAfterFinished: 86400 # 👈 关键配置:保留 24 小时 = 86400 秒, 必须放在这里!
containers:
- name: python
image: your-dockerhub-username/python-cronjob:latest
imagePullPolicy: Always
restartPolicy: OnFailure
🔍 说明
ttlSecondsAfterFinished: 86400表示:该 Job 完成后 24 小时内仍然保留在集群中,超过这个时间会被 Kubernetes 自动删除。- 这个功能从 Kubernetes v1.21 开始稳定支持。
- 适用于
Job、Pod、CronJob的jobTemplate中。
✅ 查看保留的 Pod
你可以查看所有已完成的 Pod:
kubectl get pods --field-selector=status.phase==Succeeded
或者根据命名空间过滤:
kubectl get pods -n <namespace> --field-selector=status.phase==Succeeded
这些 Pod 会在 24 小时后自动消失。
⚠️ 注意事项
- 确保你的 Kubernetes 版本 >= v1.21。
- 确保 kube-controller-manager 的参数
--controllers包含ttl控制器(默认开启)。 - 如果你使用的是托管 Kubernetes 服务(如阿里云 ACK、AWS EKS、GKE),一般都已默认启用。
✅ 总结
| 目标 | 实现方法 |
|---|---|
| Pod 执行完后保留 24 小时再删除 | 在 Job 或 CronJob 的 jobTemplate.spec.template.spec 中设置 ttlSecondsAfterFinished: 86400 |
更多推荐



所有评论(0)