Andrew Harry

andrewharry.com

Creating a simple Kubernetes

Cron Job

Today, I am learning how to add a simple cron job to a kubernetes environment. The Cron job will ‘ping’ an endpoint of one of the hosted services every 5 minutes.

What's a Cron job?

A cron job a utility program that lets users schedule tasks to run at a specific time.
Users can determine what kind of task they want to automate and when it should be executed.

Source - https://www.hostinger.com/tutorials/cron-job

Help! I’m new to Kubernetes!

So am I, where to start? This looks like as good a place as any.

OK, so do I even have kubernetes installed? I thought I did when I installed DockerDesktop (Windows 11 machine). But it turns out - I missed the checkbox in the docker settings

Docker Settings

Then run the following command kubectl config get-contexts

CURRENT   NAME             CLUSTER          AUTHINFO         NAMESPACE
*         docker-desktop   docker-desktop   docker-desktop

Hello World from K8

Let’s just get a simple hello world working…

Source - https://kubernetes.io/docs/tutorials/hello-minikube/

Lets run the create command

kubectl create deployment hello-node --image=k8s.gcr.io/echoserver:1.4

This next line then exposes the echoserver to port 8080

kubectl expose deployment hello-node --type=LoadBalancer --port=8080

Now you can browse to the service using localhost:8080

Yay!

Where’s the YAML?

BUT, this isn’t quite what I was expecting… Where is the YAML? Ok, fair enough. We need to recreate this using YAML this time.

This is a great video “Kubernetes Tutorial for Beginners” which helped me understand how to get things working.

Deployment File

First we define the myapp.deployment.yaml file. This is the template for what we are deploying into k8.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
  labels:
    app: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: k8s.gcr.io/echoserver:1.4
        ports:
        - containerPort: 8080

The file defines what we are deploying called “myapp-deployment”. It is using the container image “k8s.gcr.io/echoserver”. This is being exposed via the port 8080 (via containerPort). The specification is telling kubernetes to spin up 2 replicas (aka Pods).

Service File

Next, we need to create the myapp.service.yaml file. This defines how the deployed container is wired up in Kubernetes.

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  type: LoadBalancer
  allocateLoadBalancerNodePorts: true
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ports:
  - nodePort: 30000
    port: 8080
    protocol: TCP
    targetPort: 8080

This service definition exposes the service to localhost:8080. I had to play around for a bit to get this actually working. The missing bit was around the LoadBalancer and the targetPort. Internally the Pods are listening to port 8080.

Let’s execute these files.

kubectl apply -f .myapp.deployment.yaml
kubectl apply -f .myapp.service.yaml

OK, so we now have kubernetes running a very simple service across two Pods!

Let’s add a Cron Job

I started with this config from the kubernetes website. This original script just starts a cron job and the task itself just logs to the console.

I changed the original script to use the “buildpack-deps:curl” image. The cron job itself is just a simple curl script with some noise suppression (-sS)

  • This runs every minute (* * * * *)
  • It simply hits the myapp service on port 8080 with a GET request.
apiVersion: batch/v1
kind: CronJob
metadata:
  name: ping
spec:
  schedule: "* * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: cronjob
        spec:
          containers:
          - name: ping
            image: buildpack-deps:curl
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -ec
            - curl -sS http://myapp:8080
          restartPolicy: OnFailure

Let’s test the cron job

kubectl apply -f .ping.cron.yaml

From the console we can list the jobs running using kubectl get jobs

kubectl get jobs --watch
NAME             COMPLETIONS   DURATION   AGE
ping-27587963   1/1           5s         2m45s
ping-27587964   1/1           5s         105s
ping-27587965   1/1           5s         45s

From the logs I can see the request being received by the myapp service and I can see the ping job printing out the raw http response.

What’s next?

Well, that was the first time I have played with Kubernetes. I think it is quite amazing what you can do with just some simple scripts. I wonder what real production scripts look like? I can imagine that this would get quite horrible quite quickly if rushed and learning on the job.

All in all? I’m impressed.

Contents