Let’s build Microservices Part II

Amol Limaye
6 min readJul 19, 2020

--

How to containerize spring boot microservices using Docker

Photo by Kira auf der Heide on Unsplash — Pack a service in a container

This series of ‘How-to’ blog posts is my effort to learn and share the knowledge and working code of building various components of a microservices ecosystem.

This is a complete end-to-end explanation and ‘open-source’ code for microservices using NGINX + Consul + Spring boot. So, I think, this would be useful to fellow software engineers.

Let me know in the comments or message me if you want me to cover any more aspects of microservices.

In part I of this series, we built three RESTful microservices that work together to vend out product information in JSON format. They use consul for service discovery and for external configuration.

Next, we will build on that code to do the following:

  • Containerize each microservice — using docker
  • Build API gateway in front of these services — using NGINX

In this part, we will dockerize three spring boot microservices.

In next part — part III , I will cover the details of building an API gateway using NGINX in front of these services.

Part 1https://medium.com/swlh/lets-build-microservices-part-1-a6d1b37154a9

Part 3https://medium.com/@amol.limaye/lets-build-microservices-part-iii-20e9e5c780a0

Source code for part 1: https://github.com/amollimaye/microservices-ecommerce

Source code for parts 2 and 3: https://github.com/amollimaye/microservices-ecommerce-2

Blog Structure

Part 1

  • Build spring boot microservices
  • Use Consul for external configuration and service discovery

Part 2

  • Explaining what we will build
  • Why containerize ?
  • About Docker
  • Step 1: Containerize microservices

Part 3

  • Need for API gateway
  • About NGINX
  • About Consul-Template and Docker-Compose
  • Step 2: Updates to service properties
  • Step 3: Build NGINX + Consul Template container
  • Step 4: docker-compose
  • See the application in action

Explaining what we will build

Microservices block diagram

What we built in part I

In Part I, we built ECommerce spring boot service that vends out JSON data. It uses product service to get product information and image service to get image information.

Product and image services use single responsibility principle: they are responsible for managing their respective domain data i.e. product and image data. Each service has a database per service that is directly accessible only to that service. For simplicity, we have used H2 in-memory DB. We have built just read (get) endpoints in these services, to Read the data. We will use messaging in future post for CUD operations.

ECommerce service is a composite microservice that aggregates the data from these two services, transforms it, and send it back to the client. This is aggregator pattern.

For cross-cutting concerns of service discovery and external configuration we use consul. We use spring cloud to integrate these spring boot services to consul. Spring boot actuator provides the ‘/health’ endpoint in these services which consul uses to check the ‘up’ status of the service instances.

What we will build in part II

In this part, I explain what is docker and the steps and commands needed to dockerize a spring boot service. We will dockerize ECommerce, Image and product services this way.

Why Containerize ?

A container will encapsulate everything that is needed to run the microservice; the OS, code, runtime environment and the needed libraries. So, a developer does not need to worry about inconsistencies between dev and prod environments. These containers are not tied to a specific infrastructure. They run on a PC same way as they would run on cloud. Containers enable us to dynamically provision number of instances of a given service as per need.

To sum up, below are the benefits of containerized microservices

  • Portability and consistency across environments
  • Ease of scale up or down as per need
  • Cost effective

We will containerize the microservices using Docker. In the next part, we will also containerize NGINX API gateway and Consul and will run this entire container system together using docker-compose. We will also scale up a service to show multiple instances of same service running on same machine.

About Docker

Docker is an open source containerization platform. Docker enables developers to package applications into containers — standardised executable components that combine application source code with all the operating system (OS) libraries and dependencies required to run the code in any environment.

We will create one ‘docker image’ of each service. Each image will contain the source code and needed dependencies.

A Docker image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

This ‘self-sufficient’ docker image will be instantiated by the docker engine. This running instance of docker image is called docker container.

Containerized apps

Please note, this is a dev setup to understand and explore how various components work. Production setup would be more complex.

Let’s code!

Step 1: Containerize microservices

If you do not have docker setup, follow this link https://docs.docker.com/get-docker/ . Try running a sample app to verify that docker works fine on your machine.

Now, let’s containerize first microservice — ‘product-service’ — using below steps.

Step 1.1: Add a docker file — We add a file named DockerFile as shown below. This is a text file that contains the list of commands that the docker engine will run, to assemble and instantiate the docker image. This file is added to the root directory of the service source code.

product-service DockerFile

Step 1.2: Build application jar file: Go to root directory of product service. DockerFile and pom.xml are present there. Run below maven command to build and package the java code into a jar file.

mvn clean package

Then we run below docker command. It creates a docker image for product service. It uses the ‘openjdk:8-jdk-alpine’ base image, that we specified in DockerFile, to build this image.

docker build -t product .

Step 1.3: Containerize image service and ecommerce service

Create a DockerFile at the root of ecommerce service and image service. Their contents would be almost similar as shown for product service. The only difference being the name of the service and jar file in the DockerFile. Other steps remain same.

Step 1.4: Run Docker Image Now that we have built the images, docker images command shows us all these available images, product.

Now we can run the product service docker instance using below command.

docker run product

The output will be shown on console.

We could optionally run the instance in detached mode using flag ‘-d’ . So, the docker instance will be a separate process and won’t hold the terminal to show application’s output. In that case, we could check the docker logs as follows:

#run docker image in detached mode
docker run product -d
#See logs of the container named product
docker logs product

The product service start-up will fail since we have coded the service such that it expects a consul server at localhost:8500. But consul is not there on localhost yet, since the product service is inside a container now.

We need to change all the services, to point to instance running on local machine. For this, I will update the properties to the ip address of my local machine.

spring.cloud.consul.host=<MY-IP-ADDRESS>
spring.cloud.consul.port=8500

I will rebuild the docker images and start docker instances of all three microservices. Now, the microservices will start successfully and register themselves to consul service registry.

Earlier, each microservice was running on localhost, but now since it is inside a docker instance, each will be assigned a new IP and port. The inter-service calls will continue to work without any more code change, since services use consul service registry to get location of services.

In part III, we will explore other important components of the microservice system, and why we need them.

Note: The contents of this blog are my personal views and do not reflect that of my employer in any way.

Resources:

--

--

Amol Limaye

I love to write code, build stuff and share that knowledge. More about me on my profile: https://in.linkedin.com/in/amolrlimaye