Why would I want to migrate the systemd timer job as a k8s cronjob? One could say, for better resilience and resource utilization in the cluster. Workloads will be scheduled for any available node, not only the one with the timer configured. However, the real reason is, because by doing unnecessarily complex stuff, people will think I am smart.

Without further ado, let’s start with a Dockerfile. I want to containerize terraform job from previous post:

FROM hashicorp/terraform:1.9

WORKDIR /workspace
COPY main.tf /workspace/main.tf

ENTRYPOINT ["terraform"]

Let’s build it, and push to the dockerhub. I know it is silly to push and pull from the dockerhub, but we do not have local registry yet – which makes good idea for the next post.

Here is the general idea, how cronjob should look like:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: terraform-cloudflare-cronjob
spec:
  schedule: "0 * * * *" 
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: terraform-cloudflare-container
            image: {{image}}:{{tag}}
            args: ["apply","--auto-approve"]
            volumeMounts:
            - name: vars-secret
              mountPath: /workspace/vars.auto.tfvars
              subPath: vars.auto.tfvars
            - name: terraform-workspace-storage
              mountPath: /workspace/

          restartPolicy: OnFailure

          volumes:
          - name: vars-secret
            secret:
              secretName: vars
          - name: terraform-workspace-storage
            persistentVolumeClaim:
              claimName: terraform-pvc
  • schedule: it uses cron syntax, lets run it every hour for now
  • image: change it for your image
  • volume mounts: we need to create one secret, and one persistent volume claim

To create a secret, save it as vars.auto.tfvars:

cloudflare_api_token = ""
zone_id = ""
domains = ["domain","subdomain1","subdomain2"]

and create secret from that file:

kubectl create secret generic vars --from-file=vars.auto.tfvars  

It will be mounted as a file, and terraform will read them automatically. There are two reasons we want to mount this file externally: security and ease configuration. Definitely do not share the api token with anyone. And by having external domain configuration, we can easily add and remove subdomains.

Next, lets create pvc:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: terraform-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 200Mi

Last but not least, we need to run terraform init first. Easiest way would be just create one-shot pod for that. Definition would be quite similar. Only notable difference would be args for terraform command.

apiVersion: v1
kind: Pod
metadata:
  name: terraform-cloudflare-pod
spec:
  containers:
  - name: terraform-cloudflare-container
    image: {{image}}:{{tag}}
    args: ["init"]
    volumeMounts:
    - name: vars-secret
      mountPath: /workspace/vars.auto.tfvars
      subPath: vars.auto.tfvars
    - name: terraform-workspace-storage
      mountPath: /workspace/

  volumes:
  - name: vars-secret
    secret:
      secretName: vars
  - name: terraform-workspace-storage
    persistentVolumeClaim:
      claimName: terraform-pvc

Leave a Reply

Your email address will not be published. Required fields are marked *

+ ,