Lately, I've been playing with Tekton to try and build a CI pipeline. It has a concept of a Pipeline that contains the ordering of Tasks that should be run. To run a pipeline there's an aptly named resource called PipelineRun. Once this is complete it sits around on the Kubernetes cluster which is helpful when you need to see logs, but eventually, you need to clean this up. This can also be used to delete pods based on age, or any other resource that has the creationTimestamp metadata (potentially all of them?)

The simplest way I thought this could be done was to delete the PipelineRun after a certain duration.

Note: If you're running on Alpine Linux it has a different version of the "date" utility than some fatter distros, so you'll either need to install that version or use this slightly more complicated date command to get the date you need.

Command

The command to get all PipelineRuns and delete them if they're older than a day would be:

kubectl get pipelineruns -o go-template --template '{{range .items}}{{.metadata.name}} {{.metadata.creationTimestamp}}{{"\n"}}{{end}}' | awk -v date="$(date -d "@$(($(date +%s) - 86400))" +%Y-%m-%d)" '$2 < date {print $1}' | xargs --no-run-if-empty kubectl delete pipelinerun

You can change this to be older or more recent by changing the "86400" value. That is the number of seconds ago.

Breakdown

Get Resource

The first part gets the PipelineRun (or another resource's) name and creation time:

kubectl get pipelineruns -o go-template --template '{{range .items}}{{.metadata.name}} {{.metadata.creationTimestamp}}{{"\n"}}{{end}}'

Outputs:

build-pipeline-run-4lwr9 2019-12-20T09:55:46Z
build-pipeline-run-6jf9x 2019-12-20T10:06:08Z
build-pipeline-run-6sn69 2019-12-19T09:54:50Z
Date comparison

Next it:

  • Finds the timestamp in the output lines above (the $2 in the command below).
  • Gets the current date and takes off the seconds
  • Formats it as YYYY-mm-dd
  • Compares it to the timestamp of the resource If the resource timestamp is before the given date, print the resource name
awk -v date="$(date -d "@$(($(date +%s) - 86400))" +%Y-%m-%d)" '$2 < date {print $1}'
Delete Resource

Finally, pass all the matching resource names into the kubectl delete command:

xargs --no-run-if-empty kubectl delete pipelinerun

CronJob

The last thing to do is to set this up to run regularly, fortunately, Kubernetes provides us with CronJobs to run tasks on a schedule.

---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: tidy-old-pipeline-runs
spec:
  schedule: "0 4 * * *"
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 2
  jobTemplate:
    spec:
      backoffLimit: 4
      template:
        spec:
          serviceAccountName: trigger-service-acct
        terminationGracePeriodSeconds: 0
        restartPolicy: Never
        containers:
          - name: kubectl
            imagePullPolicy: IfNotPresent
            image: bitnami/kubectl:1.15
            command:
            - "/bin/sh"
            - "-c"
            - |
              kubectl get pipelineruns -o go-template --template '{{range .items}}{{.metadata.name}} {{.metadata.creationTimestamp}}{{"\n"}}{{end}}' | awk -v date="$(date -d "@$(($(date +%s) - 86400))" +%Y-%m-%d)" '$2 < date {print $1}' | xargs --no-run-if-empty kubectl delete pipelinerun

Tags: