Goal of this example

This example shows how to create a “microservice ecosystem” from dockerized spring boot applications. The services are accessible internally inside docker, but external access is only in a controlled way through an API Gateway. Inside the “ecosystem” the number or running instances or the locations can change any time, without affecting the “interface” that is provided to the extnal world. Such a dockerized ecosystem can be used for

Setting up a local test environment of a microservice project

Testing different cluster configurations

Testing cluster fail-over

Can be the basis of a production deployment (if added support for multi node clusters, security, etc)

We will build the following :



We will use a Zuul API Gateway and an Eureka service registry. Details of how they work are explained in other blog post of the series (links below), but what matters for this exercise is that they are regular Spring Boot applications. A very similar ecosystem could be build from any java application.

Technology Used

Spring boot 1.3.5.RELEASE

Docker

Docker Compose

Docker maven plugin

Zuul

Eureka

This article is part of a Spring Cloud / Netflix OSS series

How to create a docker image from a spring boot application

Our first goal is to generate a Docker image from a Spring boot application using maven. This can be achieved by the Spotify docker maven plugin. It eliminates the need to create a Dockerfile, instead all important properties like the base image and entrypoint can be set in the pom.xml like this :

<plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>0.4.10</version> <configuration> <imageName>${project.artifactId}</imageName> <baseImage>java:8</baseImage> <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint> <!-- copy the service's jar file from target into the root directory of the image --> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}.jar</include> </resource> </resources> </configuration> <executions> <execution> <id>build-image</id> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin>

This does the following :

Sets the <baseImage> (equivalent to FROM in dockerfile) to java:8

Sets the <entryPoint> (equivalent to CMD in dockerfile) to the generated jar file.

Binds the plugin to the build goal, so it will be automatically executed when <pre>mvn install</pre> is executed

If the command was successfully executed then we should see the image listed when

docker images

is executed.

Link docker containers to see each other over the network

Once we have our docker images we want to start them up in a way they connect to each other over the network. The legacy way to do is to use the -link command, e.g.: like this :

## Starts up an eureka image, names it eureka-server and exposes port 8761 docker run -p 8761:8761 --name eureka-server eureka-server ## Starts up an echo-service image and makes the container named eureka-server accessible over the network by the eureka-server name docker run --name echo-service --link eureka-server echo-service

Use docker-compose the start up multiple containers and set up a container network

Docker compose is a command line tool to start up multiple predefined containers. Container definitions are stored in a file named docker-compose.yml . The above example starts up three containers. The depends_on defines the startup order and how containers see the other. The file also defines the exposed ports of the services.

version: '2' services: echo-service: image: echo-service depends_on: - eureka-server eureka-server: image: eureka-server ports: - "8761:8761" zuul-server: image: zuul-server depends_on: - eureka-server ports: - "9090:9090"

The above file defines that

Eureka will expose it’s 8761 port to the external network

Zuul server will expose it’s 9090 port to the external network

Echo-service will be only internally accessible

To start up the containers build all images then type

##use the -d option to start up in deamon mode docker-compose up

docker compose could also build the images, but it would require a Dockerfile that we replaced with the Docker maven plugin. Once the services are up you can execute a few commands to validate the setup

##show running docker containers docker ps ##List docker netwrks docker network ls

Scaling

One fo the many benefits of docker-compose is that it allows easy scaling of the services. For example if we want two echo-service containers then simply call

<span class="pl-c">##starts a 2nd instance of echo-service</span> docker-compose scale echo-service=2

Resource utilization

Starting up three or more VMs would require a lot of time and resource. Docker containers share their resources with the host, therefore the overhead is very minimal. The startup time and memory footprint of a dockerized java application is almost identical to a regulat java application.