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!🚀

相关推荐
__Smile°1 小时前
kubeadm-k8s 中的 etcd 备份与恢复
数据库·docker·云原生·容器·kubernetes·etcd
慌ZHANG2 小时前
云原生安全挑战与治理策略:从架构思维到落地实践
大数据·云原生·架构
lovebugs3 小时前
Kubernetes中高效获取Java应用JVM参数的终极指南
后端·docker·kubernetes
JuiceFS3 小时前
稿定科技:多云架构下的 AI 存储挑战与 JuiceFS 实践
人工智能·后端·云原生
船长@Quant7 小时前
开源的现代数据探索和可视化平台:Apache Superset 在 Kubernetes 上安装
kubernetes·dashboard·大数据可视化·apache superset·sql-lab·商业智能工具
__Smile°8 小时前
基于 kubeadm 搭建 k8s 集群
linux·运维·docker·云原生·容器·kubernetes
@不会写代码的小张8 小时前
k8s核心组件——kubelet详解
云原生·容器·kubernetes
君科程序定做9 小时前
容器 vs 虚拟机
微服务·云原生·容器·服务发现
Black:)11 小时前
证书更新后 K8s Master状态NotReady
容器·kubernetes