From Monolith to Kubernetes Architecture — Part I — Containerize

Ori Berkovitch
3 min readApr 8, 2022

--

Photo by Keith Markilie 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 series I will describe the process which took us towards creating a Kubernetes cluster, starting from the Monolith app we had when we started.

As part of Google’s startup program, we were granted 100,000$ of credits to migrate from AWS to GCP. Although we were using a Monolith system, we jumped on the opportunity to migrate the system while transforming into a microservice architecture based on Kubernetes.

No matter what architecture you’re using, the first step is to dockerize the monolith, of course. Without dockerization, we can’t move to Kubernetes in any case!

The first and most fundamental idea behind dockerization is moving the Monolith’s configuration to environment variables.

Environment variables are a fundamental property of the Kubernetes architecture. Any microservice launched inside a Pod will be handed a bunch of those Environment variables (such as connection strings, feature flags, etc).

In our case, we were using Tomcat, which mostly draws its configurations from server.xml and context.xml. The first riddle was: “How to use environment variables in server.xml and context.xml”. Luckily, using some references, we discovered server.xml (and its kind) are indeed built to replace notation such as ${MY_GREAT_VARIABLE} with concrete values from the System Properties.

System Properties and Environment Variables are different things. You can think of System Properties as “weak” Environment Variables, that live only in the context of the application.

So the chain goes like this:

Environment Variable → System Property → Server.xml → Java Application

Working Example:

Step 1:

Create environment variables (notice that in the actual Kubernetes cluster, this will be created for you by the pod and node configurations)

export DB_USERNAME=”postgres”

export DB_PASSWORD=”postgres”

Step 2:

create a special environment variable (JAVA_OPTS) to bridge between Environment Variable → to System Property. Notice the (very irritating) -D prefix at the beginning of the phrases.

export JAVA_OPTS=”-DDB_USERNAME=$DB_USERNAME -DDB_PASSWORD=$DB_PASSWORD”

Step 3

Use the variables from JAVA_OPTS as input in server.xml, context.xml, etc. For example:

<Resource name=”jdbc/treebute” auth=”Container” type=”javax.sql.DataSource”
username=”${DB_USERNAME}
password=”${DB_PASSWORD}
driverClassName=”org.postgresql.Driver”
url=”jdbc:postgresql://127.0.0.1:5432/mystuff”
maxTotal=”60"
maxIdle=”20"
validationQuery=”select 1"/>

Notice that when we’ll eventually configure Kubernetes, we will use “secrets” rather than “configuration”. But more on that in sequel posts!

References:

--

--