How to Do Kubernetes Cronjobs with Sidecars Properly in 2024


TL; DR: Since Kubernetes v1.28, there’s no need to do fancy bash scripts to kill your sidecar when the main container finishes. So using sidecars in Kubernetes Jobs or Cronjobs are now much simpler and more elegant too.

For example, I wanted to run a database backup job in a GKE + Cloud SQL environment, so naturally I’d use a Cloud SQL Proxy to simplify database connection and authentication. Here’s the YAML snippet:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-cronjob
spec:
  concurrencyPolicy: Forbid
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      completions: 1
      parallelism: 1
      template:
        metadata:
          labels:
            # don't need istio for this
            sidecar.istio.io/inject: 'false'
        spec:
          containers:
            - command:
                - bash
                - /app/run.sh
              image: 'mysql:latest'
              name: mysql
              volumeMounts:
                - mountPath: /app/run.sh
                  name: script
                  subPath: run.sh
          initContainers:
            - args:
                - '--private-ip'
                - '--auto-iam-authn'
                - '--address=0.0.0.0'
                - my-gcp-project:my-gcp-region:my-cloud-sql-instance?port=3306
              image: 'gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.11.4'
              name: cloud-sql-proxy
              # this is the key, with `Always` this init container becomes a sidecar container
              restartPolicy: Always
          restartPolicy: Never
          serviceAccount: db-service-account
          serviceAccountName: db-service-account
          volumes:
            - configMap:
                defaultMode: 420
                name: config-map-with-the-script
              name: script
  schedule: 0 20 * * *
  successfulJobsHistoryLimit: 1
  suspend: false

So with this setup, the cloud-sql-proxy container becomes a sidecar which will load before the mysql container and will exit automatically once run.sh finishes.

A more detailed writing is here.

🙂