- Acknowledgement
- Requirements
- Tip
- Disclaimer
- Downloading Docker and starting the Docker engine
- Microservices to deploy on Docker
- Dockerising the Microservices
- Creating a repository for the config files
- Changing some properties in the config repository
- Building the images
- Writing the docker-compose.yml
- Running the docker-compose.yml
- Final result
- Conclusion
- After party
This work has been achieved with the collaboration of Mohamed Assil Ben Amor and Ismail Akrout, Saturday at GO MY CODE (eating a lot of snacks) and doing a lot of research and testing.
You need to install
- Intellij
- JDK 8 (Java 9 won't work)
- Spring... (TP dependencies)
This work is our original footprint and made us learn lessons from the mistakes of previous generations in this homework.
A windows 10 OS is used for this application, but don't worry it's the same for all other OS (it's docker)
First go to https://docs.docker.com/install/ and download the docker community version (depending on your OS)
- After installing docker engine please check that you've enabled TLS connection
- And make sure you're not signed on to the docker hub
- You should also run the docker engine
This is a screenshot of the settings
- Product Service: The main service, which offers a REST API listing all products.
- Config Service : Configuration service, whose role is to centralize the configuration files of the various microservices in a single place.
- Proxy Service: A gateway that handles the routing of a request to one of the instances of a service, in order to automatically manage the load distribution.
- Discovery Service: Service that records service instances for discovery by other services.
The resulting architecture:
To dockerize our microservices, we need to generate docker image from each Spring boot application using maven. This can be achieved by one of these methods:
- Create a Dockerfile manually for each micro-service
- Using io.fabric8 (docker-maven-plugin)
In this tutorial we will use the docker maven plugin, because we are going to automate the build tasks
Because in order to successfully launch the micro-services you need to do it in this order:
- Build the config image
- Run the config image in a container
- Build the product image
- Build discovery and proxy images
- Run the product, discovery and proxy images
The problem that we can face, that none of the previous generation covered that actually to do that you need to run them in order manually, but no we believe in automation that's the DevOps spirit.
And in order to do that we need to run commands to check service status or just wait for some time then execute the jar file.
Even though we used the dependency tag in the docker-compose.yml you need to set a time gap.
The first step, is to configure the config-service, so open pom.xml
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<alias>${project.artifactId}</alias>
<name>${project.artifactId}</name>
<build>
<from>java:8</from>
<entryPoint>
<shell>["java", "-jar", "/maven/${project.build.finalName}.jar"]</shell>
</entryPoint>
<env>
</env>
<assembly>
<descriptorRef>artifact</descriptorRef>
</assembly>
</build>
</image>
</images>
</configuration>
</plugin>
entryPoint is the docker file entrypoint, using this plugin we will have a Dockerfile automatically generated when we do a docker:build
.
This configuration will produce this Dockerfile
FROM java:8
COPY maven /maven/
ENTRYPOINT ["java", "-jar", "/maven/config-service-0.0.1-SNAPSHOT.jar"]
For the other projects we assumed that the projects needs to start:
- 10 seconds after config-service for the discovery-service
- 20 seconds after config-service for the product-service
- 20 seconds after config-service for the proxy-service
So it's obvious that we will use sleep timeInSeconds
command
Here is an example pom.xml for product-service and proxy-service (just change the 20 to 10 for the discovery-service)
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<alias>${project.artifactId}</alias>
<name>${project.artifactId}</name>
<build>
<from>java:8</from>
<entryPoint>
<shell>sleep 20 && java -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -jar /maven/${project.build.finalName}.jar && java -jar /maven/${project.build.finalName}.jar </shell>
</entryPoint>
<env>
</env>
<assembly>
<descriptorRef>artifact</descriptorRef>
</assembly>
</build>
</image>
</images>
</configuration>
</plugin>
In this section we will describe how to automate the build actions and separate them from the ones used in the debugging.
First we need to create a configuration for each project in the same way
don't panic you we will guide you to create the mvn package configuration
Now you need to create a maven configuration
Make sure it is set like this
Now your build configuration is set, IntelliJ will create your docker image for you and push to the local docker registry (repository) (remember we are signed out from the docker registry)
Create a repository
Go to config-service\src\main\resources\myConfig
and type these commands in order
- git remote add origin
your git url
- git add .
- git commit -m "initial"
- git push -u origin master
Now we need to change some properties before we start creating our docker-compose.yml.
First we go to proxy-service.properties
and add this property
eureka.client.serviceUrl.defaultZone=http://discovery-service:8761/eureka/
in our case the discovery-service is the host and the name of the docker container that we will use in compose file.
this property makes sure that the proxy-service automatically registers to discover-service by setting the default zone.
We will do the same for product-service.properties
.
The final files will be:
product-service.properties
me=arsslen@gomycode.co
eureka.client.serviceUrl.defaultZone=http://discovery-service:8761/eureka/
proxy-service.properties
server.port=9999
eureka.client.serviceUrl.defaultZone=http://discovery-service:8761/eureka/
Well building the images needs to be in order, and we have a problem here
The product-service will not build if the config-service is offline
First build the config-service image using IntelliJ.
So we need to run a config-service container first to build the product-service docker image.
We do it by typing this command
docker run -it -p 8888:8888 config-service --spring.cloud.config.server.git.uri=https://github.com/Arsslensoft/eservices-configs
just change the repository link to the one you created.
Now build the other images
- product-service
- discovery-service
- proxy-service
after building those images you could see that they are already pushed into the local repository by running this command:
docker images
here is a screenshot
This part is tricky, but we will cover it part by part.
- first we gonna create the file
- add the config-service section
- add the product-service, discovery-service and proxy-service sections
Well we need also to initialize the file so there are other properties that are not included in the config-service section
version: '2.0'
services:
config-service:
image: config-service
ports:
- "8888:8888"
expose:
- 8888
networks:
- arsslens-network
environment:
SPRING_APPLICATION_JSON: '{"spring": {"cloud": {"config": { "server":{"git":{"uri":"https://github.com/Arsslensoft/eservices-configs"}}}}}}'
What we did here is:
- used our image config-service
- defined a port rule from the inside of the container to the outside world (my computer)
- exposed that outer port to be accessbile by http://localhost:8888/
- used a network called arsslens-network (it's going to be a bridge network)
- We overriden the application.properties of config-service using SPRING_APPLICATION_JSON environment variable to use our git repository
Here we will use links and depends_on
product-service:
image: product-service
expose:
- 8080
ports:
- "8080:8080"
depends_on:
- config-service
- discovery-service
links:
- config-service:config-service
- discovery-service:discovery-service
networks:
- arsslens-network
environment:
SPRING_APPLICATION_JSON: '{"spring":{"cloud":{"config":{"uri":"http://config-service:8888"}}}}'
- links enables us to wire the containers in the local network (Containers for the linked service are reachable at a hostname identical to the alias, or the service name if no alias was specified).
- depends_on express dependency between services, Service dependencies cause the following behaviors.
discovery-service:
image: discovery-service
expose:
- 8761
ports:
- "8761:8761"
depends_on:
- config-service
environment:
SPRING_APPLICATION_JSON: '{"spring": {"cloud": {"config": {"uri": "http://config-service:8888"}}}}'
EUREKA_INSTANCE_PREFER_IP_ADDRESS: "false"
networks:
- arsslens-network
proxy-service:
image: proxy-service
expose:
- 9999
links:
- config-service:config-service
- discovery-service:discovery-service
ports:
- "9999:9999"
depends_on:
- config-service
- discovery-service
networks:
- arsslens-network
environment:
SPRING_APPLICATION_JSON: '{"spring":{"cloud":{"config":{"uri":"http://config-service:8888"}}}}'
version: '2.0'
services:
config-service:
image: config-service
ports:
- "8888:8888"
expose:
- 8888
networks:
- arsslens-network
environment:
SPRING_APPLICATION_JSON: '{"spring": {"cloud": {"config": { "server":{"git":{"uri":"https://github.com/Arsslensoft/eservices-configs"}}}}}}'
product-service-1:
image: product-service
expose:
- 8080
ports:
- "8080:8080"
depends_on:
- config-service
- discovery-service
links:
- config-service:config-service
- discovery-service:discovery-service
networks:
- arsslens-network
environment:
SPRING_APPLICATION_JSON: '{"spring":{"cloud":{"config":{"uri":"http://config-service:8888"}}}}'
discovery-service:
image: discovery-service
expose:
- 8761
ports:
- "8761:8761"
depends_on:
- config-service
environment:
SPRING_APPLICATION_JSON: '{"spring": {"cloud": {"config": {"uri": "http://config-service:8888"}}}}'
EUREKA_INSTANCE_PREFER_IP_ADDRESS: "false"
networks:
- arsslens-network
proxy-service:
image: proxy-service
expose:
- 9999
links:
- config-service:config-service
- discovery-service:discovery-service
ports:
- "9999:9999"
depends_on:
- config-service
- discovery-service
networks:
- arsslens-network
environment:
SPRING_APPLICATION_JSON: '{"spring":{"cloud":{"config":{"uri":"http://config-service:8888"}}}}'
networks:
arsslens-network:
driver: bridge
To run it it's easy just type docker-compose up
, please make sure you are in the same directory as you docker-compose.yml.
Finally you'll see this starting
Proof that the product-service successfully registered
Proof that the proxy-service successfully registered
And finally done
We discovered that it's not just about making docker images, its about linking them, automating and making them run with proof.
We just ate snacks of the hackathon and did our homework with love 🖤 hoping to get a 20.