如何自动删除由 CronJob 创建的已完成 Kubernetes 作业?

Posted

技术标签:

【中文标题】如何自动删除由 CronJob 创建的已完成 Kubernetes 作业?【英文标题】:How to automatically remove completed Kubernetes Jobs created by a CronJob? 【发布时间】:2017-05-14 02:46:03 【问题描述】:

除了制作 CronJob 来清理已完成的 Jobs 之外,还有其他方法可以自动删除已完成的 Jobs 吗?

K8s Job Documentation 声明已完成作业的预期行为是让它们保持已完成状态,直到手动删除。因为我每天通过 CronJobs 运行数千个作业,我不想保留已完成的作业。

【问题讨论】:

【参考方案1】:

您现在可以设置历史记录限制,或完全禁用历史记录,这样失败或成功的 CronJobs 不会被无限期保留。见我的回答here。文档是here。

设置history limits:

.spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit 字段是可选的。这些字段指定应保留多少已完成和失败的作业。默认情况下,它们分别设置为 3 和 1。将限制设置为 0 对应于在完成后不保留相应类型的作业。

限制为 0 的配置如下所示:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  successfulJobsHistoryLimit: 0
  failedJobsHistoryLimit: 0
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

【讨论】:

有没有办法设置历史的时间限制,比如一周后删除成功的作业? 我不知道,抱歉。如果您找到方法,请在此处发布后续信息。据推测,我想您可以编写一个 cron 作业,查看旧的 pod 时间戳,然后逐个删除超过 X 天的。 是的,我在 kubernetes 中创建了一个部署,一个 golang 项目,创建了一个通道来监听 pod 列表并观察状态的变化.. 请注意,链接的答案仅适用于 CronJob 对象(提问者提到的),但不适用于 Job 对象。 也许也看看here,看起来有可能定义一个ttlSecondsAfterFinished“将级联删除作业,即删除其依赖对象,例如Pods,连同作业"【参考方案2】:

这在 1.12 Alpha 版中可以使用ttlSecondsAfterFinished。来自Clean Up Finished Jobs Automatically的例子:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi-with-ttl
spec:
  ttlSecondsAfterFinished: 100
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never

【讨论】:

Note that this TTL mechanism is alpha, with feature gate TTLAfterFinished这个功能门部分我没看懂。 Feature gates 是启用或禁用 Kubernetes 功能的标志。我不知道如何设置它们,或者即使您有能力使用像 EKS 这样的托管服务来设置它们。我怀疑您也必须配置主节点,但我在推测。 @technazi 谢谢@rath!是的,当我通过 helm 模板配置作业和 pod 时,我看不到可以配置功能门的地方,因此我无法使用 alpha 改进,基本上说ttlSecondsAfterFinished 没有功能没有效果大门。【参考方案3】:

我发现下面的工作

要删除失败的作业:

kubectl delete job $(kubectl get jobs | awk '$3 ~ 0' | awk 'print $1')

要删除已完成的作业:

kubectl delete job $(kubectl get jobs | awk '$3 ~ 1' | awk 'print $1')

【讨论】:

我必须更新命令才能让它工作:kubectl delete jobs $(kubectl get jobs | awk '$2 ~ 1/1' | awk 'print $1') 如果没有完成的作业要删除,这个不会失败:kubectl get jobs | awk '$2 ~ "1/1" print $1' | xargs kubectl delete job【参考方案4】:

另一种方式using a field-selector:

kubectl delete jobs --field-selector status.successful=1 

这可以在 cronjob 中执行,类似于其他答案。

    创建一个服务帐户,例如my-sa-name 为资源作业创建具有列表和删除权限的角色 在服务帐户中附加角色(角色绑定) 创建一个将使用服务帐户的 cronjob 来检查已完成的作业并删除它们
# 1. Create a service account

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa-name
  namespace: default

---

# 2. Create a role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: my-completed-jobs-cleaner-role
rules:
- apiGroups: [""]
  resources: ["jobs"]
  verbs: ["list", "delete"]

---

# 3. Attach the role to the service account

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-completed-jobs-cleaner-rolebinding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: my-completed-jobs-cleaner-role
subjects:
- kind: ServiceAccount
  name: my-sa-name
  namespace: default

---

# 4. Create a cronjob (with a crontab schedule) using the service account to check for completed jobs

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: jobs-cleanup
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: my-sa-name
          containers:
          - name: kubectl-container
            image: bitnami/kubectl:latest
            # I'm using bitnami kubectl, because the suggested kubectl image didn't had the `field-selector` option
            command: ["sh", "-c", "kubectl delete jobs --field-selector status.successful=1"]
          restartPolicy: Never

【讨论】:

您能否添加一个示例,说明如何创建具有所需权限的服务帐户? 谢谢!我只需要将角色更改为: - apiGroups: ["batch"]【参考方案5】:

我正在使用wernight/kubectl 的 kubectl 镜像

安排了一个 cron 删除任何内容

completed 2 - 9 days old(所以我有 2 天的时间来审查任何失败的工作)

它每 30 分钟运行一次,所以我没有考虑 10 天以上的工作

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: cleanup
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: kubectl-runner
            image: wernight/kubectl
            command: ["sh", "-c", "kubectl get jobs | awk '$4 ~ /[2-9]d$/ || $3 ~ 1' | awk 'print $1' | xargs kubectl delete job"]
          restartPolicy: Never

【讨论】:

对于您的 awk 命令,您不希望您的第二个条件是 $2 ~ /^1/ 而不是 $3 ~ 1 吗?我假设您正在查看第二列的完成列,至少对我而言,完成列打印为0/11/1,因此获取第一个字符很重要。也许kubectl get job 的输出不同。 您也可以将两个awk 命令合二为一。我测试了以下内容,它将作为上述 awk 组件的替代品:awk '$4 ~ /^[2-9]d/ || $2 ~ /^1/ print $1' 这是否需要集群角色绑定才能正确删除已完成的作业?【参考方案6】:

我最近构建了一个 kubernetes-operator 来完成这项任务。

部署后,它将监控选定的命名空间并删除已完成的作业/pod,如果它们完成且没有错误/重新启动。

https://github.com/lwolf/kube-cleanup-operator

【讨论】:

请不要只发布一些工具或库作为答案。至少在答案本身中展示how it solves the problem。【参考方案7】:

使用 jsonpath:

kubectl delete job $(kubectl get job -o=jsonpath='.items[?(@.status.succeeded==1)].metadata.name')

【讨论】:

【参考方案8】:

如文档“删除旧作业由用户决定”中所述,请参阅http://kubernetes.io/docs/user-guide/jobs/#job-termination-and-cleanup

我会根据作业名称和某些条件运行一个 pod 来执行此清理,从而让 kubernetes 至少在这里处理您的进程的可用性。您可以为此运行一个循环作业(假设您运行 kubernetes 1.5)。

【讨论】:

所以我不明白的是,一个用于清理的 pod 现在与其他 pod 位于相同的命名空间中,您如何配置它以最初连接到集群? 仅当您以非常严格的方式进行安全设置时,命名空间才相关(并且 k8s 中的 pod 在 pod 上运行,您的安全性无论如何都会变弱一些)。幸运的是,取得了一些进展:允许闲置的作业数量已经增加(gcloud 大约 40k 而不是之前的 10k),并且使用 cronjobs,您可以通过限制您保留的旧作业数量让 k8s 为您管理它【参考方案9】:

通过运行 cron 作业删除它们的简单方法:

kubectl get jobs --all-namespaces | sed '1d' | awk ' print $2, "--namespace", $1 ' | while read line; do kubectl delete jobs $line; done

【讨论】:

不建议解析文本输出。相反,您应该请求一个 json,用 jq 解析它并遍历结果。 kubectl delete job $(kubectl get jobs -o jsonpath='.items[?(@.status.completionTime)].metadata.name') 不要这样做。这也会删除正在运行的作业

以上是关于如何自动删除由 CronJob 创建的已完成 Kubernetes 作业?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用自动填充的已保存用户名/密码

如何检查 Linux shell 脚本是不是由 cronjob 执行?

可以将 ClickOnce 配置为删除旧的已发布目录吗?

如何以编程方式完成作业后停止cron作业

自动从 Mysql 表中删除的记录

如何从表中删除然后删除引用的已删除行? (postgresql)