Skip to main content

Learning microservices with a practical example

·710 words·4 mins
Programming
Alejandro Duarte
Author
Alejandro Duarte
Alejandro Duarte is a Software Engineer, published author, and award winner. He currently works for MariaDB plc as a Developer Relations Engineer. Starting his coding journey at 13 with BASIC on a rudimentary black screen, Alejandro quickly transitioned to C, C++, and Java during his academic years at the National University of Colombia. Relocating first to the UK and then to Finland, Alejandro deepened his involvement in the open-source community. He’s a recognized figure in Java circles, credited with articles and videos amassing millions of views, and presentations at international events.

Although this example application is simplistic and no one should ever use microservices to implement an application like this one, it shows you how it feels to run this kind of applications and how to implement it using Spring Cloud.

If you only want to play around with a microservices application, follow this tutorial. If you want to code the full app using Java, Eureka, Spring Cloud Config, Spring Data Rest, Hystrix, Zuul, Spring Session, and Vaadin,  follow the complete 9 steps tutorial. After completing the tutorial you end up with several terminals where each terminal is running a specific service:

Running microservices

In real-world projects, you most likely wouldn’t start microservices like this. You would probably use an orchestration tool such as Docker Swarm or Kubernetes. There’s a Git  branch in the repository for this example application that contains Docker files you could experiment with to learn more about how to deploy microservices in production environments.

In the following sections, I describe some guidelines to create a practice environment.

Setting up the Machines
#

Use VirtualBox to create a virtual machine and install Alpine Linux on it. Use a Bridged Adapter in the network configuration.

Set up static IPs for both machines. Edit the /etc/network/interfaces file as follows:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 192.168.1.150
        netmask 255.255.255.0
        gateway 192.168.1.1

Set up SSH so you can use your host machine to connect to the virtual machine from now on (something that would happen in a real-world scenario):

apk add openssh

You would need to add PermitRootLogin yes to the /etc/ssh/sshd_config file to make things easier for now (or you can create a new OS user and connect to the VM using its credentials). With this, you can connect to the VM using:

To install Docker, first add the following repository to the **/etc/apk/**repositories file:

http://dl-cdn.alpinelinux.org/alpine/latest-stable/community

Then run:

apk update
apk add docker

To run Docker at startup, execute:

rc-update add docker boot

In VirtualBox, shut down the VM and clone it. Generate a new MAC address for the cloned VM in the network configuration. Start and connect to the cloned VM to configure a different IP address in the /etc/network/interfaces file. For example 192.168.1.151. Restart the cloned VM and start the original one. You should have now two VMs ready.

Running the Application with Docker Swarm
#

In the 192.168.1.150 machine, init a swarm:

docker swarm init --advertise-addr 192.168.1.150

This machine is now the master machine.

Copy the reported docker swarm join command and run it in the other machine (192.168.1.151). The command should look similar to this:

docker swarm join --token SWMTKN-1-2j6qifl5jbb7zmcbr1ti7xl3qthmhj87b853afjmh29i7f6voi-5az2apq6vq80sls2uvd1sjz1o --advertise-addr 192.168.1.151 192.168.1.150:2377

This machine is now a worker machine.

In the master machine (192.168.1.150), create a new docker-compose.yml file with the following contents:

version: '3'

services:
  discovery-server:
    image: alejandrodu/microservices-discovery-server
    ports:
      - "8001:8080"
    command: --spring.cloud.inetutils.preferredNetworks=10.0 --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 128M

  config-server:
    image: alejandrodu/microservices-config-server
    ports:
      - "8101:8080"
    command: --spring.cloud.inetutils.preferredNetworks=10.0 --spring.cloud.config.server.git.default-label=docker --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 128M

  biz-application:
    image: alejandrodu/microservices-biz-application
    ports:
      - "9001:8080"
    command: ---spring.cloud.inetutils.preferredNetworks=10.0 --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    volumes:
      - ~/h2-databases:/root/h2-databases
    deploy:
      resources:
        limits:
          memory: 128M

  admin-application:
    image: alejandrodu/microservices-admin-application
    ports:
      - "9101:8080"
    command: ---spring.cloud.inetutils.preferredNetworks=10.0 --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 256M

  news-application:
    image: alejandrodu/microservices-news-application
    ports:
      - "9201:8080"
    command: ---spring.cloud.inetutils.preferredNetworks=10.0 --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 128M

  website-application:
    image: alejandrodu/microservices-website-application
    ports:
      - "9301:8080"
    command: ---spring.cloud.inetutils.preferredNetworks=10.0 --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 128M

  proxy-server:
    image: alejandrodu/microservices-proxy-server
    ports:
      - "8080:8080"
    command: ---spring.cloud.inetutils.preferredNetworks=10.0 --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 128M

  monitor-application:
    image: alejandrodu/microservices-monitor-application
    ports:
      - "8201:8201"
    command: ---spring.cloud.inetutils.preferredNetworks=10.0 --eureka.client.serviceUrl.defaultZone=http://discovery-server:8080/eureka/ --logging.file=application.log
    deploy:
      resources:
        limits:
          memory: 128M

The main things to notice in the previous configuration are the usage of a preferred network when running a service, the shared volume in the biz-application, and the Git branch used by the config-server.

Run the stack by executing:

docker stack up -c docker-compose.yml microservices-demo

What’s next?
#

The purpose of this article is not to explain all the concepts and details on Docker and Docker Swarm but rather give you some guidance on how to experiment and learn by yourself.

From here you can experiment with cloud providers several of which ease Docker-based deployments, replicating the Discovery and Config services to avoid having them as single points of failure; and setting up a database cluster for the same reason.

Enjoyed this post? I can help your team implement similar solutions—contact me to learn more.

Related

How to call a Java method from a JavaScript function in the browser
·128 words·1 min
Programming Vaadin
In this video I demonstrate how to call a Java method that runs in the server from a JavaScript function running in the web browser:
Copy & paste based development
·481 words·3 mins
Programming
This is about Mr., W. J. a nice and friendly developer working for an IT company in a cosmopolitan city.
Semantic coupling
·474 words·3 mins
Programming
Code Complete is one of those books every developer should read.