This repo provides tutorials for our Microservices training workshop. The workshop is divided in stages that build on each other. Depending on the time constraints certain stages can be skipped.
Each stage has a two-digit number. There are optional stages which are not integrated into the build-on-each-other pattern, but are side branches of a certain stage. Optional stages are marked with the stage's number they are built on and a letter (e.g. 09A) if they are independent, or the stage's number they are built on and a number if several stages form a branch (e.g. 03.1 and 03.2).
Detailed hints for each stage can be found in the hints folder.
For the Microservices Tutorials you need the following tools:
- Java 1.8.x
- IntelliJ IDEA (community or ultimate edition)
- MySQL Server
- Chrome
- Postman (Chrome extension)
- docker
- docker-compose
Note: You can use a VM with all tools setup to get started. The VM setup is described in a separate repo, a list of tools that we use in the workshop can be found here.
Participants are supposed to solve each tutorial stage by themselves. A reference solution can be found in branches. Furthermore we provide detailed hints for each stage in the hints folder (master branch).
You have your first spring boot application up and running.
Your first service will depict a service that can return simple customer information. The stub of the first service is generated using the SpringBoot Initializr. Use the following settings:
- Generate a
Gradle Project
withJava
and Spring Boot1.5.x
(latest stable version) - Group:
com.senacor.bitc
- Artifact:
customer
- Name:
customer
- Package Name:
com.senacor.bitc.demo
- Dependencies:
Web
Open the customer
project using IntelliJ IDEA: File
>> Open...
>> select the customer
folder
- Implement a REST controller that offers one GET method that returns the IP address of the server.
Note: The REST endpoint to return customer information is added at a later stage.
Your spring boot application can be configured via a configuration server.
The cloud config requires another spring-boot project that represents the cloud config server. Use SpringBoot Initializr to generate the project using the following settings:
- Generate a
Gradle Project
withJava
and Spring Boot1.5.x
(latest stable version) - Group:
com.senacor.bitc
- Artifact:
config
- Dependencies:
Web
Config Server
Add the config
project as module in IntelliJ IDEA: File
>> New
>> Module from Existing Sources...
>> select the extracted config
folder
- Configure the config project as cloud-config-server
- Configure the spring cloud config server to use a git-repository where you put the configuration for your customer service.
- Configure the customer service so it uses the cloud config server for configuration.
- Configure the port where the customer service is served through the config server configuration file. The port should not be hard-wired in the customer service any more, but is defined by the configuration file served by the config server.
Note: We are using yaml (.yml
) for our configuration files in the reference solution. We recommend you do the same.
Create a database with a customer table and dummy-data using flyway migration scripts. This data will serve as a basis for the customer endpoint.
- Install MySQL (you can also install it through apt-get).
- Create a MySQL database through the mysql command line.
Note: If you are already familiar with docker you can of course use a mysql docker container instead of the local installation of mysql server.
- Configure the customer project for mysql and flyway (dependencies).
- Write flyway migration scripts to create a table
customer
with fieldsid
,first_name
,last_name
andbirth_date
. - Fill some data into your
customer
table by writing and executing more flyway migration script(s).
Be able to access customer data from the database through a new REST endpoint (without writing boilerplate code).
Since we are working with entities now and we want to avoid unnecessary boiler-code-writing we recommend to add Lombok to the customer project. You can follow the instructions on how to add Lombok to IntelliJ IDEA as plugin and how to integrate Lombok into your project with gradle. Note that you will also have to turn on annotation processing in IntelliJ IDEA for Lombok to work.
- Use Spring Data to retrieve customer data from the database (entity and repository).
- Offer a new REST endpoint that provides customer data (at least: customer by id and customer by last name).
- Test the new REST endpoint (with MockMVC and MockBean).
You recap step 01 till 04 again. You have a second service that provides an account endpoint.
- Do stages 01 till stages 04 again by yourself, but create an accounting service instead of a customer service. When creating an account one has to provide a customer ID. You should be able to create and retrieve simple accounts through the service (AccountID, AccountType and CustomerID are enough to represent the account).
Note: In the next stage the account service will utilize the customer service to check if a customer exists before adding an account. Don't implement the part where the accounting service validates if a customer exists through the customer service yet! We will do this in the next stage when we add the service discovery.
You add a service discovery so the services can find each other through the discovery server. The account endpoint retrieves information from the customer endpoint through a Feign Client.
The discovery server requires another spring-boot project. Use SpringBoot Initializr to generate the project using the following settings:
- Generate a
Gradle Project
withJava
and Spring Boot1.5.x
(latest stable version) - Group:
com.senacor.bitc
- Artifact:
registry
- Dependencies:
Web
Eureka Server
Add the registry
project as module in IntelliJ IDEA: File
>> New
>> Module from Existing Sources...
>> select the extracted registry
folder
- Configure the registry project as Eureka server.
- Configure the customer project as Eureka client so it register with the Eureka server.
- Configure the accounting project as Eureka client so it registers with the Eureka server.
- Configure a feign client for the customer endpoint in the accounting project and verify the customer ID upon account creation.
The complete application (databases, config server, registry and functional services) works as before but runs in docker containers.
- Configure containers for the two MySQL databases by using MySQL images from Docker-Hub
- Configure container for the registry (through image from Docker-Hub or by adding a Dockerfile to the registry project)
- Configure container for the config server (through image from Docker-Hub or by adding a Dockerfile to the registry project)
- Configure container for the customer service by adding a Dockerfile to the customer project
- Configure container for the accounting service by adding a Dockerfile to the accounting project
It is recommended that you test the new containers after each task by starting the newly created container as well as the other parts (locally, outside of container).
Note: In this stage it is enough to link the containers on IP address level. In the docker-compose stage we will create a more generic setup. You can also pass IP-addresses to the spring application running inside a container by defining the SPRING_APPLICATION_JSON
environment variable on container startup. Checkout the spring documentation on externalized configuration for details.
You configure the docker containers of stage 07 through docker-compose so you don't have to link the containers using the specific IP addresses of the containers, but use a configuration by name through docker-compose.
- Add a docker-compose configuration file to the top folder of the repository.
- Configure all the services in the docker-compose configuration (add entry for all the different components and define the linkage).
- Startup the "backbone containers" (database, config server, registry) through docker-compose.
- Startup the "functional containers" (customer, accounting) through docker-compose.
- Test customer and account retrieval and account creation.
You understand the purpose of the config-server and the config-repo better in the context of a microservices deployment. You understand how to make the customer and accounting service more resilient, so you can just run docker-compose up
without starting specific services in a dedicated order by hand.
- Move all the configuration entries from the customer and accounting projects'
application.yml
files to the respective configuration on the config server. - Configure for the config-server connection at startup to customer and accounting service. It should not matter if the config-server is immediately available at startup or later.
- Configure the database connection, so it does not matter if the database is always available. The application should be able to deal with it without crashing.
- Commit the configuration files and let the config server configuration (in
bootstrap.yml
) point to the correct repo/branch. - Build the accounting and customer projects and containers new.
- Run and test the setup by creating a new account through Postman.
You understand the concept of configuration profiles in detail and manage your local setup separately through a configuration profile. You can run the project locally in your IDE or through docker-compose without changing anything in the code or configuration.
- Create two profiles:
dev
andprod
. Theprod
profiles should contain the docker-compose setup like in stage 09. Thedev
profile should contain a local setup so you can start the services through youe IDE without docker-compose. - Configure an in memory H2 database for the
dev
setup, so you don't have to start, stop and reset MySQL containers during development. - Configure your IDE and docker to set the correct profile upon startup.
- Test your setup by running the services from IDEA and aferwards through docker-compose.
You understand the concept of HATEOAS (Hypermedia as the Engine of Application State) and adapt your services accordingly.
- Follow the spring tutorial on HATEOAS to adapt your rest endpoint according to the pattern.
- For data-transfer-objects (DTOs) it is recommended to add a request and a response object for every resource.
- Think about the design of your endpoints with respect to the HATEOAS pattern.
- Extend the customer service, add another endpoint that should serve the address of the customer. Think about how to depict this in the service path and in the Customer and CustomerAddress response links.
Note: You can turn off the HAL link-representation in this stage, see hints for details. The Hypertext Application Language (HAL) standard will be explained in the next stage.
You understand how HAL and HATEOAS work together and how HAL can help you to design RESTful APIs in a standardized way.
- Take a look at the HAL overview, you can also take a look at the official standard's draft.
- Adapt the HATEOAS representation of your services to be HAL (draft-)standard compliant.
Hint: It might help to take a look at the Resources<>
vs. Resource<>
section in the Spring HATEOAS documentation.