My first DevOps job interview Part 2 of 3
Tags: devops, kubernetes, career, docker
Published: 2021-04-22 07:09:15

In [the last part](https://niklasmtj.de/blog/my-first-devops-job-interview-part-1) I introduced in the exercises and talked about the complications I had with building a Dockerimage with Chrome inside on an `arm64` platform. Also the used [NodeJS](https://nodejs.org) app and its’ `Dockerfile` was presented. This part will be more about [Kubernetes](https://kubernetes.io), setting up the Cluster and deploying the NodeJS app.

## Setting up a Kubernetes Cluster
After creating the `Dockerfile` it was about setting up a Kubernetes cluster. Which program I use for this was up to me. In my [DevOps with Kubernetes](https://devopswithkubernetes.com) course we use [k3d](https://k3d.io), this implements [K3s](https://k3s.io) in Docker. During the course I had not experienced any problems with this solution, so I was sure to use k3d to solve the assignments.
Installing k3d on macOS is easy via [Homebrew](https://brew.sh) with `brew install k3d`. The cluster can then be created with `k3d cluster create --port '8082:30080@agent[0]' -p 8081:80@loadbalancer --agents 2`. The `8081:80@loadbalancer` will allow our apps to be accessible to us via `localhost:8081`.

## Deploying the app
With a running Kubernetes cluster, deployment was now on the agenda. I decided from the beginning to logically separate the app from the rest of the cluster and created a separate namespace. This is possible with `kubectl create namespace exercise-ns` in Kubernetes. The basic structure for deployment can be found in the Kubernetes documentation ([Deployments | Kubernetes](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment)). So I created a `deployment.yaml` in my `manifests` folder with the following content: 
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: exercise-app
	namespace: exercise-ns
  labels:
    app: exercise-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: exercise-app
  template:
    metadata:
      labels:
        app: exercise-app
    spec:
      containers:
      - name: exercise-app
        image: niklasmtj/exercise-app:v1
```

To make the deployment discoverable I also created a service. The Kubernetes documentation for services ([Deployments | Kubernetes](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#creating-a-deployment)) again provides the basic structure. The service definition can be found under `manifests/service.yaml`:
```yaml
apiVersion: v1
kind: Service
metadata:
  name: exercise-svc
	namespace: exercise-ns
spec:
	type: ClusterIP
  selector:
    app: exercise-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
```

It is important to note here that the `targetPort` corresponds to the port exposed by the Docker container.

## Ingress
After preparing the deployment, the task was now to be able to access it. Thus, the connection via an [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) came into play. By default, K3s uses the Traefik Ingress Controller for Ingress routing, which I also used. The ingress configuration is quite simple. In an `ingress.yaml` file I used the following configuration:
```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: exercise-ingress
  namespace: exercise-ns
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: exercise-svc
          servicePort: 80
```

This way the `/` path is directly forwarded to the `exercise` service we defined in `service.yaml` on port 80.

### IP-Whitelisting
Another task I had to solve with an Ingress was to limit the IP range that is accepted at all. Unfortunately, due to my previous knowledge, I did not had the possibility to implement the whole thing at that time. Nevertheless I read up on how I would implement it and documented it in my readme. During the task I took a closer look at the NGINX Ingress Controller, because I found the most results about it during my research. There it seems to work by a simple annotation in the `ingress.yaml`:

```yaml
metadata:
  annotations:
    ingress.kubernetes.io/whitelist-source-range: "192.168.0.0/16"
```

This will make sure that only IPs from the `192.168.0.0/16` net is able to connect to the apps. So every IP starting at `192.168.0.1` to `196.168.255.254` are eligible to connect. NGINX will drop every request not coming from this IP range.

Also, attempts with Traefik as the Ingress controller, which is used by k3s by default, failed. This is an area I need to look at in more detail in the near future to understand exactly how Ingress works and at what level you can block IPs. Additionally, I need to look at whether it makes a difference that my k3s cluster is running inside Docker and how that affects incoming IPs.

Thank you for reading, 
Niklas

---
The code from this post can also be found on GitHub: [niklasmtj/kubernetes-exercise](https://github.com/niklasmtj/kubernetes-exercise).
Additionally, I created an `arm64` as well as an `amd64` docker image for `niklasmtj/exercise-app:v1`. So the example app should be usable on other devices as well.

**The series:**  
* [Part 1](https://niklasmtj.de/blog/my-first-devops-job-interview-part-1)
* **Part 2**
* Part 3 - coming April 29