/k8s-workshop

K8S discovery workshop

Primary LanguageJavaScriptMIT LicenseMIT

Kubernetes workshop

The goal of this workshop is to see different Kubernetes objects. It shows how to use BatchJob, CronJob and Deployment.

BacthJob

In the folder jobs, you will find a Golang script retrieving jokes from the Chuck Norris Open API and publishing these jokes on Slack.

Requirements

  • make must be available on your machine
  • Go runtime installed on your machine
  • Docker CE setup on your machine
  • working account on Docker Hub for publishing your container
  • kubectl installed
  • accessible Kubernetes Cluster (Minikube or hosted cluster like GKE)
  • Slack account for creating a Incoming Web-Hook
  • gettext and envsubst for *nix OS

ToDo

Create a new incoming web-hook in your Slack account. Export the URL by typing export SLACK_HOOK=myHookURL.

Compile the script locally by running make in your terminal. It will create a binary called job in the jobs folder. You can run the binary locally to see how it works by doing ./job.

After you tested the script, bake it in a container.

The Dockerfile at the root of this repository is used to bake the application. It uses multi-stage builds in order to optimize the size of the container (~10Mb).

The first stage create a cross-platform Golang binary (build stage). The second stage, the one being published to the Docker registry uses an Alpine base image. We install ca-certificates for being able to perform HTTP requests over HTTPS.

In your terminal, run the following commands:

$> docker login # make sure that your logged in to your account
$> docker build -t myDockerUsername/chuck:latest . # build the container - the name must be username/image-name:label
$> docker push myDockerUsername/chuck:latest # publish the container

When you are done with this step, modify accordingly the file jobs/kubernetes.job.yaml and execute the manifest. For doing so, run in your terminal envsubst \$NAMESPACE,\$SLACK_HOOK < jobs/kubernetes.job.yaml | kubectl apply -f -. envsubst takes care of replacing $NAMESPACE by the value you exported in your environment (e.g.: export NAMESPACE=myns).

After deploying, if everything went well, you shall see a Chuck Norris joke appearing in your Slack channel.

Run kubectl get job -n $NAMESPACE to see the status of your job. You can check the status of your pod by running kubectl get po -n $NAMESPACE. The pod is the smallest Kubernetes entities. In our case, the pod has a single container, our Chuck Norris application.

If you try to run again the kubectl apply command, you should see nothing happening. It is normal. A job runs until completion and it must be deleted after deletion if you plan to run it again later. A job could be considered as a single run program.

When you are done with the experiments, delete the job by running kubectl delete job myjobname -n $NAMESPACE.

In the manifest, you can notice 2 properties called parallelism and completions. By default, both properties are set to 1 in order to ensure that the pod will be executed one time only.

Play with the two properties in order to publish several messages at once. After redeploying your manifest, run kubectl get po -n $NAMESPACE -w to watch at the pods and see how Kubernetes deals with these 2 properties.

Conclusion

A job is really useful for performing one time actions like parsing a file and injecting its content in a database. However, you cannot ensure that a Kubernetes Job will run exactly one time whenever you need it because of how Kubernetes has been designed. For more info about it, I strongly suggest to you to deep dive into their documentation about job.

CronJob

A CronJob is a Kubernetes job executed following a schedule. A schedule is a CRON expression. It allows you to run a given job X times a day or every X minutes and so on. For this part, we will re-use the same script as the one for the Job.

Requirements

  • make must be available on your machine
  • Go runtime installed on your machine
  • Docker CE setup on your machine
  • working account on Docker Hub for publishing your container
  • kubectl installed
  • accessible Kubernetes Cluster (Minikube or hosted cluster like GKE)
  • Slack account for creating a Incoming Web-Hook
  • gettext and envsubst for *nix OS

ToDo

Using the manifest jobs/kubernetes.cronjob.yaml, redeploy your application in your Kubernetes cluster. Make sure that you replace the values like the name of the image with the values you use.

The schedule property in the manifest allows you to set your CRON job. It accepts a CRON expression. By default, the CronJob is gonna send a joke on the Slack channel every 5 minutes.

For deploying the CronJob, run the following command: envsubst \$NAMESPACE < jobs/kubernetes.cronjob.yaml | kubectl apply -f -. When it is done, run kubectl get po -n $NAMESPACE -w in a terminal. You can see every 5 minutes a pod getting created, executed and cleaned up after completion.

If you run kubectl get job -n $NAMESPACE, you can see that a CronJob creates a Job for each execution.

Try to send several messages at once by editing the concurrencyPolicy property. Do not forget to first delete the existing CronJob before redeploying.

Conclusion

A CronJob creates Job. The CronJob can be used, for example, for running a recurrent task like your integration tests at a precise time. However, the Kubernetes engine doesn't guarantee that your Job will always be executed following your schedule. Here as well, it's due to the design of Kubernetes. Here also, for more details, I strongly suggest to look into the Kubernetes documentation for understanding the why and the what.

Deployment

For our workshop, we will create a Deployment for a web-server. In the deployment/src, you can find a small script creating a web-server using NodeJS and Express. The server exposes 4 endpoints:

Requirements

  • NodeJS runtime installed on your machine
  • Docker CE setup on your machine
  • working account on Docker Hub for publishing your container
  • kubectl installed
  • accessible Kubernetes Cluster (Minikube or hosted cluster like GKE)
  • gettext and envsubst for *nix OS

ToDo

Bake the NodeJS application using the Dockerfile Dockerfile.server. In your terminal, type the following command line docker build -f Dockerfile.server -t myDockerUsername/workshop-server:latest ..

Make sure that your container works then push it to your Docker registry.

In the script, we have two parts. One takes care of creating a server for allowing Prometheus to scrap the metrics from your application. The other one is your application.

The application has two health-check endpoints. In the manifest kubernetes.yaml, you can see we use a TCP probe for both liveness and readiness. The health-check allows Kubernetes to determine the status of your application (did it start? Is it ready to receive traffic?). The deployment created by the manifest manages replicas.

The metrics are used for calibrating our horizontal pod autoscaler (hpa). In our manifest, we are setting the thresholds to 70% of memory and 50% of CPU for the hpa. The hpa collects its metrics from the metrics-server by calling the api /apis/metrics.k8s.io. Prometheus is used in our case for providing custom metrics to our hpa in later stage.

2 others objects are specified in the manifest: a service (svc) and ingress controller (ing). The svc uses a private IP address (ClusterIP) and is used a load-balancer for reaching the different pods deployed by our manifest. The ing get a public IP and route the traffic to our svc based on what we specified in the paths property. In addition, you can customise the behaviour of NGinx by adding annotations to your ing manifest. The whole list of annotations can be found here

Before applying the manifest to your cluster, make sure that you defined the right DNS in the ing manifest.

Now that it's deployed, you should be able to see a joke from chuck while doing a GET mynds.ltd/chuck.

In order to see how the hpa works, you can use the manifest kubernetes.siege.yaml to stress your application and trigger an upscale.