From Monolith to Kubernetes Architecture — Part III— Minikube

Ori Berkovitch
5 min readApr 12, 2022

--

Photo by David Cashbaugh on Unsplash

This is a multipart of a series Going From a Monolith App to Kubernetes.

Part I — Containerize

Part II — Dockerfile

Part III — Minikube

Part IV — GKE / GCP

In this part, we’re going to take our perfectly-environment-variables-aware Docker image, and place it into a minimal kubernetes cluster — the Minikube.

We are using mac machines, so some limitation appear when running Minikube on our hardware, nevertheless, we will accomplish the task at hand.

Here’s what it eventually looks like:

Minikube configured and running our webapp

We were following the most basic tutorial by Nana from the TechWorld vlog on Youtube, with some adjustment to our “real world” circumstances.

Only 3 files required

To get the webapp to run on minikube, we needed only 3 files

  1. webapp-config.yaml; This file contains the non-secret configuration of the app
  2. webapp-secret.yaml; This file contains the secret configuration of the app
  3. webapp.yaml; This file contains both the Deployment and the Service definitions for the app;

The above three files were created directly as referenced by the Youtube video above.

Environment Variables in a Kubernetes setting

Environment variables in kubernetes appear in two forms:

  1. Simple configurations
  2. Secret configurations

You can think of a “Cluster” as a “being” (yes, like a computerized person), to which you “tell” or “send” your configurations and secrets, and upon need — the cluster will know how to use the stuff you told him.

So, for example, if the cluster is planned to run a web application, and the web application requires access to a database — you, as the operator, should tell the cluster ahead the username and the password — and the cluster will use them later, when it is required to actually run the web application.

If you are not familiar at-all with configuring kubernetes, please watch the video above.

Configuration files: From Dockerfile to Kubernetes Yaml

With the basic Dockerfile at our disposal, our duty in now to go through the Dockerfile “ENV” lines, and start putting them into the config.yaml and secret.yaml files, according to their nature. For example, the following Dockerfile lines will be split as follows:

Dockerfile

...
ENV ENV DEV
ENV RUNBACKGROUNDJOB false
ENV DB_USERNAME postgres
ENV DB_PASSWORD postgres
ENV ES_ADDRESS host.minikube.internal
ENV INFLUX_ADDRESS host.minikube.internal:8086
ENV INFLUX_TOKEN 3G_n7ccuGTI3lsadkfp ...
...

webapp-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
name: webapp-config
data:
ENV: "DEV"
RUNBACKGROUNDJOB: "false"
ES_ADDRESS: "host.minikube.internal"
INFLUX_ADDRESS: "host.minikube.internal:8086"
REDIS_ADDRESS: "host.minikube.internal"
REDIS_PORT: "6379"
KAFKA_ADDRESS: "host.minikube.internal:9092"
...

webapp-secret.yaml

apiVersion: v1
kind: Secret
metadata:
name: webapp-secret
type: Opaque
data:
TREEBUTE_DB_USERNAME: cG9zdGdyZXM=
TREEBUTE_DB_PASSWORD: cG9zdGdyZXM=
TREEBUTE_INFLUX_TOKEN: M0dfbjdjY3VHVElDdVk0TDRsR ...
TREEBUTE_REDIS_PASSWORD: ""

Some things to notice:

  1. notice the special host.minikube.internal address. This is the address of the host machine when the docker container is running the application. Remember that in our setting — all the supporting services for the webapp, such as Redis, Kafka, Postgresql, InfluxDB, etc — are all running on the host machine — and thus they are ALL available for the pods at the address host.minikube.internal;
  2. Notice, that if you are using Kafka, you should add host.minikube.internal to the advertised.listeners on server.properties (usually found at /usr/local/etc/kafka/server.properties)
  3. Notice, that cG9zdGdyZXM= is actually the word “postgres” in base64; this is a requirement for secret values, and can be accomplished by running the command line: echo -n postgres | base64

Docker Image not available for kubernetes

A first “real world” pitfall is that the Docker image, which contains our application, is not available inside the kubernetes cluster. This is reasonable, as you can imagine that kubernetes requires communication with some docker repository to download the images. To overcome this, two things are requires:

  1. Your Deployment configuration should contain “imagePullPolicy: Never” in the spec.containers section
  2. You need to run eval $(minikube -p minikube docker-env) before you run docker build; That way, the docker image will be transferred to the cluster;

Minikube Pitfalls

The biggest problem with Minikube and Mac, was that the kubernetes service we created was not available from our host machine. Meaning, the ports we configured with nodePort for type: NodePort did not work! the ports were not exposed. In our case: port 30100 was not exposed!

This seems to be a known issue, but with the help of the “proxy” command provided by kubectl, we were able to “bypass” the limitation, and connect to the service inside the kubernetes cluster

https://stackoverflow.com/questions/49088884/kubernetes-service-not-being-assigned-an-external-ip-address

The workaround would be to directly forward the service with the following command:

kubectl port-forward service/webapp-service — request-timeout=”0" 8080

  • Notice the “service/” prefix in the command above
  • Notice the request-timeout parameter. This is useful when working on the development machine (prevents “Timeout occured” error messages [the typo ‘occured’ is in original message])

Here’s our Service configuration

apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
type: NodePort
selector:
app: webapp
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30100

Playbook Sequence

Here’s our playbook

  1. Start minikube with minikube start — driver=docker;
  2. Run eval $(minikube -p minikube docker-env)
  3. Build your image (and transfer it to minikube) with docker build -t webapp .
  4. Configure your cluster with: kubectl apply -f webapp-config.yaml and kubectl apply -f webapp-secret.yaml
  5. Start the service with: kubectl apply -f webapp.yaml
  6. Observe and behold your cluster command line: minikube dashboard; This will run and open the minikube dashboard
  7. Expose the desired endpoint: kubectl port-forward service/webapp-service — request-timeout=”0" 8080

Relevant references:

--

--