The journey from Monolith to Docker to Kubernetes: part 2

Ido Braunstain
DevOps College
Published in
6 min readMar 11, 2018

--

As explained in part one, I decided to go through the process of dockerizing my web app “Best Browser.”
In this second part, I will implement the following steps to achieve that:

  • Networking — Create a connection between the app’s services using docker networking.
  • Divide and conquer — Break the monolith into small independents logical units.
  • Dockerfile — Create a Dockerfile for the app’s third party resources (Nginx and Postgres) and for the GO code.
  • Docker-Compose — Create and run “Best Browser” from a Docker-Compose file.

TL;DR

The complete Dockerized code can be found here.
If you wish to continue reading this post, please read part one to meet the monolith and find out the benefits of this processes.

Networking

There are many ways to create a connection between containers: Pubsub, Message Queues, Socket, etc. For this demo, I chose to use Docker Single Host Networking using HTTP protocol.

By default, the container is assigned an IP address for every Docker network it connects to. The IP address is assigned from the pool assigned to the network, so the Docker daemon effectively acts as a DHCP server for each container. Each network also has a default subnet mask and gateway.

This quote from Docker Official explains that each container will get an IP address that can be used later for communication. In addition, docker provides a DNS service, so instead of using raw IP address, we will use an alias name, a name is more efficient to find a running container.

The first step is that we need to edit Postgres package to serve as a RESTful API backend that will handle frontend’s requests. Therefore, we’ll need to use a mux to route requests, let’s import github.com/gorilla/mux Go package for that (mux stands for HTTP request multiplexer which matches an incoming request against a list of routes (registered)).
A quick POC:
Now, that Postgres package needs to run independently and serve as a backend for “Best Browser” app, we must create a main method:

Backend main

As you can see, for each different route, I assigned a different method and set this service to listen on localhost:3000.
For example, let’s take a look at the old and new InsertVote method:

OLD: Backend InsertVote
NEW: Backend InsertVote

The new method implementation is triggered each time a POST request was sent to the pre-registered URL (‘/insert_vote/{id}’).
This method can take two parameters, w, and r, and they’re types http.ResponseWriter and *http.Request respectively. These two parameters are populated once they’re hit by a request.

Let’s have a look at the old frontend’s voteHandler method:

OLD: Frontend voteHandler

As shown , I created an instance (‘p_db’) from the old Postgres package and calling the InsertVote method (line 2).
We need to change the way we executed InsertVote method and replace it with a POST request.
This way requires more lines of code, so I created a separate method for it.
Now voteHandler will get the browser name and will call to a local InsertVote method which now firing a POST request:

NEW: Frontend voteHandler
Frontend InsertVote

After a quick test, everything is working as accepted, Great!
Now to finish this section, let’s actually prepare and use docker networking by changing every ‘localhost’ to the target container name, for example, frontend’s InsertVote:

Divide And Conquer

A quick glance at the past, the old “Best Browser” layout:

“Best Browser” Architecture

We can see that on one machine, we have an NGINX, POSTGRES and one big GO code. To add more complexity, I will divide our code into one frontend service and two services getVotes and insertVotes, they will act as our backend. At the end will have something like this…

“Best Browser” Architecture

Let’s dive deep and take a look at our code after the changes:

Hold on we’re almost there…

Dockerfile

Now that we have divided our code into three independent services and implemented a RESTful communication between them, we can start working on the Dockerfiles.
There are tons of blog posts on how to create a Dockerfile for GO, guess what, I choose the simple and shortest one 😅. (To ease your curiosity, I will recommend this The Ultimate Guide to Writing Dockerfiles for Go Web-apps).
Let’s have a look at the Dockerfile I created for insertVote service:

This Dockerfile is pretty much the same for frontend and getVotes services (differ only in the go get commands and the package name).

Now, for NGINX, all we need is to send our custom nginx.conf file into the docker image:

If you take a closer look at nginx.conf file, line 3, I wrote the name of our container (frontend) instead of localhost.

The last piece of our app is POSTGRES db. It will require more than one custom file; I had to create a postgresql.conf, pg_hba.conf and .sql file that will contain all of the necessary privilege and commands to get started — create database, create table and create users.

Now the final step, hold tight…

Docker-Compose

To launch “Best Browser” thestandard docker-compose file will be enough, nothing special here.
We assigned each container with a specific name, later the docker daemon can serve as a DNS and will translate each service name to the corresponding container’s IP address.
(For more information about docker-compose read this)

Summary

We did it!

We dockerize “Best Browser” app, instead of one service we own five completely independents services running from containers.
How should new customer install our app? All he needs is docker installed on his machine, our 887 Bytes docker-compose file and to run this one line command:

docker-compose up

On my next and final post for this series, we will create all of the necessary components to run our app from a Kubernetes Cluster.
We will talk about the benefits and the different usages we can get from an app that lives in Kubernetes.
That’s is it for part II. I hope you have enjoyed it. Please do not hesitate to give feedback and share your own lessons. The next part will be published soon. Stay tuned!
Third part link

--

--

Experienced Software Engineer working as DevOps. Skilled in Kubernetes, Docker, GO, Python and CI/CD.