Exercise 6 : Containers

Previously on HOMicS -> Exercise 5: Stock

Context

We split our monolith into several microservices. Now, it's time to deploy this infrastructure.

About the Containers

A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another.

A Docker container 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.

The container allow us to have independent and decoupled environment for each of our microservices.

Goal

Deploy our market place via docker.

Reminder

services port
gateway 8080
monolith 8090
user 9001
stats 9002
stock 9003

At your keyboard

Checkout the branch:

git checkout exercise-6

Gateway's container

1 - Create your Dockerfile to build the docker image for gateway.

info You can find all the information you need on docker website with this two links step-2-create-a-dockerfile and build-an-image.

tip For each microservice, you can use the following base image to deploy the app : openjdk:8u222-jre.

2 - Generate the docker image described by your Dockerfile

docker build -t {image-name} {dockerfile-folder}

# E.g:

docker build -t "gateway-image" gateway

3 - Run a new container from your image

docker run -d --name {container-name} -p {external-port}:{container-port} {image-name}

# E.g:

docker run -d --name gateway-container -p 9000:8080 gateway-image

In this example, you will launch a new container for your gateway. The port 9000 of your computer is redirected to the port 8080 on your container.

Check the docker's cheatsheet below:

# Pull images from Hub
docker pull {image-with-version}

# Available docker's images
docker images

# Running container's listing
docker ps

# Remove a docker image
docker rmi {image-id}

# Remove a docker container
docker rm {container-id}

# Stop a docker container
docker stop {container-id/container-name}

# Kill a docker container
docker kill {container-id/container-name}

4 - Verify on localhost:8080 that your gateway is running

User-activity and Database

Unlike gateway, User-activity required a database. Previously, it was an in-memory database h2. In real world, we need a persistent database. We already updated all our microservices to use a database on port 1521.

info Usually, each service comes with its database. It's one of the advantages of microservices. Each service can choose a database according to its needs. It allows your team more flexibility for the backup/deployment/upgrade. For simplicity, we are deploying a unique database.

1 - Run the containers for the database.

The image already exists on a hub. You only need to run it with the following command:

# Pull the image from the hub:
docker pull oscarfonts/h2:1.4.197

# Run the container:
docker run -d -p 1521:1521 -p 81:81 -v /tmp/data/homics-data:/opt/h2-data --name=homics-database oscarfonts/h2

2 - Create the user-activity dockerfile

3 - Generate the image and run the containers

Go on localhost:8080 to access your gateway. Go on localhost:9001/user-activity to access user-activity page. Log on gateway and navigate to user-activity tab. warning 404 Not Found. The page isn't accessible and on user-activity, you don't see any new login.

question Why is that ?

By default, docker's container runs on different networks so they cannot communicate directly with each other.

For communication among containers, you can either manage routing at the OS level, or you can use an overlay network. We are going to use docker-compose to achieve this purpose.

Docker-compose

Compose is a tool for defining and running multi-container Docker applications. It deploys several containers within the same network described in a YAML file. In it, we list each application by its name and define how to build its container.

For example, in this compose, we have one application named webapp:

version: '3'
services:
  webapp:
    image: my-webapp-image
    ports:
      - "8080:8080"

1 - Complete the docker-compose.yml

Remember when we were routing our applications via Zuul in the gateway, we set the path for each of our microservices like http://localhost:9001/user. In our case, localhost becomes user.

2 - Update the gateway/application.yml, build the jar: ./buildJars gateway, and finally rebuild the docker image.

3 - Run the docker-compose: docker-compose up

4 - Navigate on localhost:8080, log in, and verify that user-activity is accessible with the recent activity.

Bonus:

You can complete the docker-compose to deploy all microservices and kafka with a single command line.

warning Be aware that this operation is CPU and RAM consuming to run everything. Some of you might encounter some difficulties.

Good to know

In a docker-compose, some applications might depend on others. For example, monolith depends on kafka and the database. You can specify that information by adding the keyword depends_on::

version: '3'
services:
  webapp:
    image: my-webapp-image
    ports:
      - "8080:8080"
    depends_on:
      - database
      - kafka

What's next ? Exercise 7: Kubernetes

We are gonna see how to orchestrate everything automatically with Kubernetes.