Kubernetes CronJob 详解:配置、原理与实践指南

前言

自从公司没了运维,我就开始负责公司的运维工作了,日常运维工作很琐碎,比如每个月月末要做下个月云服务的预算,要进行费用的监测, 还有隔几天要看一下ssl证书有没有过期,要及时更新维护,我们使用的主要是阿里云服务,为此写了脚本来进行费用 监测估算以及 ssl 证书监测,然后发送钉钉通知。没接触运维工作前,并不熟悉 kubernetes, 因此定时任务放在 本地,然后使用 crontab 来定时执行。现在接触了 kubernetes 后, 知道 kubernetes 有自己的定时任务机制,所以我就想把这些定时任务放到 kubernetes 中。

脚本功能

脚本当然不是本文的重点,简单来说,就是调用阿里提供的 SDK 查询云服务的费用以及即将到期的 ssl 证书, 然后发送钉钉通知。代码就不多说了,效果图如下:

接下来才是本文重点,如何将这个脚本运行在 kubernetes 中。

kubernetes 自己的定时任务机制

Kubernetes CronJob 是一种用于管理定时任务的资源对象,类似于 Linux 系统中的 cron 。它允许用户在指定的时间或周期性地运行 Job,从而执行批处理任务。

CronJob 会创建 Job ,而 Job 又会创建 Pod 来执行实际的任务。因此,CronJob、Job 和 Pod 的关系可以概括为:

复制代码
CronJob → Job → Pod

CronJob 配置文件详解

一个典型的 CronJob 配置文件(YAML)如下:

yaml 复制代码
apiVersion: batch/v1
kind: CronJob
metadata:
  namespace: default
  name: my-cronjob
spec:
  schedule: "*/5 * * * *"  # 每5分钟执行一次(cron表达式)
  concurrencyPolicy: Forbid  # 禁止并发执行
  startingDeadlineSeconds: 60  # 任务启动的最长等待时间(秒)
  successfulJobsHistoryLimit: 3  # 保留成功的Job记录数
  failedJobsHistoryLimit: 1  # 保留失败的Job记录数
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: my-job
            image: busybox
            command: ["/bin/sh", "-c", "echo 'Hello from CronJob!' && date"]
          restartPolicy: OnFailure  # 失败时重启

关键字段解析

字段 说明 示例
schedule Cron 表达式 ,定义任务执行时间 "0 * * * *" (每小时执行)
concurrencyPolicy 并发策略 ,可选: • Allow (允许并发) • Forbid (禁止并发) • Replace (替换正在运行的 Job) Forbid
startingDeadlineSeconds 任务启动超时时间 ,超过时间未启动则视为失败 60 (60秒)
successfulJobsHistoryLimit 保留成功 Job 的历史记录数量 3 (保留3个)
failedJobsHistoryLimit 保留失败 Job 的历史记录数量 1 (保留1个)
jobTemplate Job 模板 ,定义实际运行的 Job 见示例

到这里先脑海里有这个概念,下面结合将监控脚本部署到 kubernetes 案例就会明白。

监控脚本部署到 kubernetes 案例

构建镜像

首先,我们需要将监控脚本打包成镜像。这里我使用的是 docker 来构建镜像,镜像的 Dockerfile 如下:

bash 复制代码
FROM {你的镜像仓库地址}/python:3.11
WORKDIR /app
COPY . .

RUN chmod +x main.sh

RUN pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt

CMD ["./main.sh"]

这里我将 python:3.11 镜像上传到了我们的私有镜像仓库,这样拉取会快一些。

main.sh 脚本内容如下:

bash 复制代码
#!/bin/bash

python3 main.py --subscription_type=PayAsYouGo
python3 ssl_main.py

一个是费用监控脚本,另一个是 ssl 证书监控脚本。

这个 Dockerfile 文件还是比较简单的,下面来构建镜像,执行如下命令:

ruby 复制代码
docker build  -t ${Image}:${ImageTag} -t ${Image}:latest .

构建完成后,将镜像推送到镜像仓库(我们使用的阿里镜像仓库),执行如下命令:

perl 复制代码
docker push ${Image}:${ImageTag}
docker push ${Image}:latest

到这里镜像就构建完成了,下面来创建 CronJob 资源对象。

创建 CronJob 资源对象

我们创建一个 cronjob.yaml 文件,内容如下:

yaml 复制代码
kind: CronJob
metadata:
  namespace: kube-ops
  name: serverguard-job
spec:
  schedule: "*/2 * * * *"  # 每2分钟执行一次
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: serverguard
              image: {你的镜像仓库地址}/server-guard:latest
              imagePullPolicy: Always
          restartPolicy: OnFailure

这是我写的第一版,接下来执行,看看有啥问题,执行如下命令

复制代码
kubectl apply -f cronjob.yaml

执行完成后,查看 CronJob 资源对象,执行如下命令:

arduino 复制代码
kubectl get cronjob -n kube-ops # cronjob 可以缩写为cj

可以看到如下输出:

sql 复制代码
NAME            SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
serverguard-job       */2 * * * *     False     0        <none>          13s

可以看到,CronJob 资源对象创建成功了,接下来查看 Job 资源对象,执行如下命令:

arduino 复制代码
kubectl get job -n kube-ops

可以看到如下输出:

复制代码
NAME                       COMPLETIONS   DURATION   AGE
serverguard-job-29243884   0/1           13s        13s

可以看到,Job 资源对象创建成功了,接下来查看 Pod 资源对象,执行如下命令:

arduino 复制代码
kubectl get pod -n kube-ops

可以看到如下输出:

sql 复制代码
NAME                                              READY   STATUS    RESTARTS   AGE
serverguard-job-29243884-6f6gl                    1/1     Running   0          18s

** 等待任务执行完成 **,再次查看 Job 和 pod ,因为任务设置的每2分钟执行一次,在写文章时,又执行了一次

再次查看 Job 资源对象,可以看到如下输出:

复制代码
NAME                       COMPLETIONS   DURATION   AGE
serverguard-job-29243884   1/1           48s        2m40s
serverguard-job-29243886   1/1           31s        40s

可以看到,COMPLETIONS 为 1/1 ,说明任务执行成功了。

再次查看 Pod 资源对象,可以看到如下输出:

复制代码
NAME                                              READY   STATUS      RESTARTS   AGE
serverguard-job-29243884-6f6gl                    0/1     Completed   0          2m30s
serverguard-job-29243886-srbdd                    0/1     Completed   0          30s

可以看到,Pod 资源对象的状态从 Running 变为 Completed ,说明任务执行成功了。

到这里就算是成功部署到 kubernetes 集群了,但上面这样配置有一个问题,随着任务不断执行,job 和 pod资源对象会不断增加, 下面修改配置文件,添加如下配置:

yaml 复制代码
spec:
  successfulJobsHistoryLimit: 1  # 只保留最近1个成功的Job
  failedJobsHistoryLimit: 1      # 只保留最近1个失败的Job

再次执行任务,查看 Job 和 Pod 资源对象,无论执行多少次任务, 可以看到,Job 资源对象的数量只有1个,Pod 资源对象的数量也只有1个。

到这里,我们就完成了监控脚本的部署到 kubernetes 集群,下面来总结一下。

CronJob 与 Job、Pod 的关系

(1)CronJob → Job

  • CronJob 负责按照 schedule 创建 Job。
  • 每次触发时,都会生成一个新的 Job(除非 concurrencyPolicy 限制)。

(2)Job → Pod

  • Job 负责管理 Pod ,确保任务执行完成。
  • 默认情况下,Job 会创建 1 个 Pod 来执行任务(可通过 parallelism 调整)。

(3)Pod 的生命周期

  • Running → Completed:

常见问题与解决方案

(1)CronJob 每次执行都会创建新的 Pod,导致 Pod 越来越多?

默认情况下,CronJob 不会自动清理旧的 Job 和 Pod,可能导致集群资源浪费。解决方案:

方法 1:设置 successfulJobsHistoryLimitfailedJobsHistoryLimit

yaml 复制代码
spec:
  successfulJobsHistoryLimit: 1  # 只保留最近1个成功的Job
  failedJobsHistoryLimit: 1      # 只保留最近1个失败的Job

Kubernetes 会自动清理超出限制的 Job 和 Pod。

方法 2:使用 TTL 控制器(K8s 1.12+)

yaml 复制代码
spec:
  ttlSecondsAfterFinished: 3600  # 任务完成后1小时自动删除

(2)CronJob 任务执行失败会怎样?

  • 如果 Pod 失败,Job 会根据 restartPolicy 决定是否重启:

    • OnFailure :Pod 会重启(默认最多重试6次)。
    • Never :Pod 不会重启,直接标记为 Failed

最后

将本地任务顺利迁移到 kubernetes 集群,对任务的管理和监控都有了很大的帮助, 同时也解决了本地任务的维护问题,减少了维护成本。

希望这篇博客能帮助你更好地理解 Kubernetes CronJob!🚀

相关推荐
阿里云云原生15 小时前
Higress v2.1.8:30 项引擎更新 + 4 项控制台更新
云原生
阿里云云原生18 小时前
移动端性能监控探索:iOS RUM SDK 技术架构与实践
云原生
阿里云云原生18 小时前
Nacos 3.1.0 正式发布,支持 A2A 注册中心与 MCP 注册协议增强
微服务·云原生
阿里云云原生19 小时前
Qoder 上线提示词增强功能,将开发者从“提示词”的负担中解放出来
云原生
suknna19 小时前
通过命令模拟pod创建
kubernetes
维诺菌20 小时前
k8s java应用pod内存占用过高问题排查
java·jvm·云原生·容器·性能优化·kubernetes
回忆是昨天里的海20 小时前
k8s安装-kubeadm join,将工作节点加入k8s集群
java·服务器·kubernetes
浪飘20 小时前
k8s device plugin
java·docker·kubernetes
helloworddm20 小时前
Orleans 与 Kubernetes 结合的价值分析
云原生·容器·kubernetes
KubeSphere 云原生21 小时前
云原生周刊:Helm 十年,成就 Kubernetes 的生态中枢
云原生·容器·kubernetes