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

166

除了创建CronJob清理已完成的任务,还有没有自动删除已完成任务的方法?

K8s Job文档指出,已完成的任务应该保持完成状态,直到手动删除。但因为我每天通过CronJobs运行数千个任务,不想保留已完成的任务。

9个回答

216

现在您可以设置历史限制或完全禁用历史记录,以便不会无限期保留失败或成功的CronJobs。请参见我的答案此处。文档在此处

要设置历史记录限制

.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

5
有没有一种方法可以设置历史记录的时间限制,例如在一周后删除成功的作业? - Kamaraju
19
请注意,链接的答案仅适用于“CronJob”对象(正如提问者所提到的),而不适用于“Job”对象。 - Cory Klein
2
也许在这里也可以看一下:https://kubernetes.io/docs/concepts/workloads/controllers/job/#clean-up-finished-jobs-automatically,似乎有一个可能性来定义ttlSecondsAfterFinished,它“将级联删除Job,即连同Job一起删除其依赖对象,例如Pods”。 - hilbert
“删除一周后的成功作业”不是只需选择适当的 successfulJobsHistoryLimit 即可吗?例如,如果作业每天运行一次,则为 7;如果作业每天运行两次,则为 14,以此类推。 - David Parks
还应注意到,这仅适用于自动创建的作业,在按照计划任务时间顺序正常运行的过程中,而不是手动创建的作业(即通过 kubectl create job --from=cronjob/cronjob-template foojob 创建的作业)。后者是有意不支持的。 - chb
显示剩余2条评论

44

这在1.12 Alpha版本中是可能的,使用ttlSecondsAfterFinished。例如,请参考自动清理完成的任务

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

1
请注意,此 TTL 机制为 alpha 版本,具有功能门 TTLAfterFinished。我不理解这个功能门部分。 - technazi
2
“功能门”是启用或禁用Kubernetes功能的标志。我不知道如何设置它们,甚至不知道像EKS这样的托管服务是否具备此能力。我猜测您也需要配置主节点,但这只是我的猜测。@technazi - rath
1
谢谢@rath! 是的,虽然我正在通过helm模板配置作业和pod,但我没有看到可以配置功能门的地方,因此我无法使用alpha改进,换句话说,ttlSecondsAfterFinished如果没有设置功能门则无效。 - technazi

35

使用字段选择器的另一种方式:链接

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

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

  1. 创建一个服务账号,例如my-sa-name
  2. 创建一个角色,具有资源jobs的列出和删除权限
  3. 将该角色附加在服务帐户上(rolebinding)
  4. 创建一个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


5
您能否提供如何创建具有所需权限的服务账号的示例? - brechtvhb
谢谢!我只需要更改角色为:
  • apiGroups:["batch"]
- SteveCoffman

23

我发现以下方法可行

要删除失败的作业:

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

删除已完成的任务:

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

5
为了让它起作用,我不得不更新命令:kubectl delete jobs $(kubectl get jobs | awk '$2 ~ 1/1' | awk '{print $1}') - user2804197
1
如果没有要删除的已完成作业,则此命令不会失败:kubectl get jobs | awk '$2 ~ "1/1" {print $1}' | xargs kubectl delete job - visit1985

13

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

计划设定一个定时任务,删除以下任何内容:

  • 已完成的作业
  • 2 - 9天之前的作业(这样我就有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输出不同。 - Stephen
您还可以将这两个 awk 命令合并为一个。我测试了以下内容,它可以替换上面 awk 组件的功能:awk '$4 ~ /^[2-9]d/ || $2 ~ /^1/ {print $1}' - Stephen
这需要一个集群角色绑定来正确删除已完成的作业吗? - Ryan Clemente

7

我最近建立了一个Kubernetes操作器来执行此任务。

部署后,它将监视所选命名空间,并删除已完成的作业/ Pod(如果它们没有错误/重启)。

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


13
请不要仅仅将某些工具或库作为答案发布。至少在答案中演示它是如何解决问题的。 - Baum mit Augen

6
使用 jsonpath:
kubectl delete job $(kubectl get job -o=jsonpath='{.items[?(@.status.succeeded==1)].metadata.name}')

5

如文档所述,“删除旧作业由用户自行处理”,请参见http://kubernetes.io/docs/user-guide/jobs/#job-termination-and-cleanup

我会运行一个基于作业名称和特定条件的Pod来执行此清理操作,从而至少让Kubernetes负责此处进程的可用性。您可以为此运行定期作业(假设您运行Kubernetes 1.5)。


我不理解的是,用于清理的Pod现在与其他Pod位于同一命名空间中,那么如何配置它最初连接到集群呢? - shan
命名空间只在您的安全设置非常严格时才相关(而在k8s中,使用pod操作pod时,您的安全性会稍微降低)。幸运的是,有一些进展:允许挂起的作业数量已经增加(gcloud约为40k,而不是以前的10k),并且使用cronjobs,您可以通过限制保留的旧作业数量来让k8s为您管理它。 - Norbert

4

通过运行 cron 作业来简单地删除它们:

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

2
不建议解析文本输出。相反,您应该请求一个json,使用jq解析它并迭代结果。 - Mikulas Dite
1
kubectl delete job $(kubectl get jobs -o jsonpath='{.items[?(@.status.completionTime)].metadata.name}') - Payman
7
不要这样做。这也会删除正在运行的任务。 - cristi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接