DevContainer for Spring Boot development that gets you covered for all major challenges of building production grade REST services.
This is an opinionated devcontainer for building REST APIs with Spring Boot. It is not meant to be a complete solution for all use cases. It rather provides starting points tp get you started on all of challenges of building production grade REST services. If you have any suggestions or feedback, please let me know.
Let’s have a look at the main components:
-
OpenJDK 21
-
Spring Boot 3.5.0
-
Maven 3.9.9
-
MS SQL DB 2022
-
Prometheus
-
Grafana
-
Alertmanager
-
Mailcatcher
-
Adminer
-
JaCoCo
-
Bruno
Develop your Spring Boot 3.5 Service on OpenJDK 21.
For illustration I added an example REST-Service that manages data on games. This service exposes some technical metrics: JVM, Hibernate, Spring-Booot (Requests, Errors, etc.) and application specific metrics like the number of games in the database.
To assist your journey of building high quality web services:
- the service exposes a self documenting API using OpenAPI aka Swagger. You can access the API documentation at http://localhost:8088/swagger-ui/index.html.
- I added JaCoCo maven plugin. Each time you run ./mvnw package
the code coverage is calculated and stored in target/site/jacoco/index.html
. Use the included Live server extension to view the report in your browser.
image::https://github.com/CWACoderWithAttitude/dc-spring-boot-all-in-one/blob/what-the-heck/images/games-jacoco-report.png[JaCoCo Report]
- basic build pipeline based on GitHub Actions is included. It runs the tests, builds the app and generates the JaCoCo report. The pipeline is triggered on every push to the main branch and on every pull request.
A picture is worth a thousand words. So let’s have a look at the architecture diagram of the devcontainer.
architecture-beta
group games_service(cloud)[Games Service DevContainer]
service db(database)[Database] in games_service
service apiserver(server)[GamesAPI] in games_service
service prometheus(server)[Prometheus] in games_service
prometheus:L -- R:apiserver
db:R -- L:apiserver
service grafana(server)[Grafana] in games_service
service alert_manager(server)[Alertmanager] in games_service
service mailcatcher(server)[Mailcatcher] in games_service
alert_manager:L -- R:mailcatcher
service adminer(server)[Adminer] in games_service
db:L -- R:adminer
prometheus:T -- B:grafana
alert_manager:T -- B:prometheus
service mssql_tools(server)[MSSQL_Tools]
db:T -- B:mssql_tools
service bruno(cloud)[Bruno]
apiserver:B -- B:bruno
I ship my examples with Bruno collections.
Please find the collections in the bruno
folder. You can import them into Bruno by clicking on the +
icon in the top left corner and selecting Import Collection
.
There’s a CLI tool to run collections, too:
❯ bru run . --reporter-html results.html
Running Folder
Create Game (200 ) - 71 ms
✓ assert: res.status: eq 200
✓ should return status 200 (OK)
✓ id of the create game entity should be greater than 0
Get all games (200 ) - 87 ms
✓ assert: res.status: eq 200
Get game by existing id (200 ) - 10 ms
✓ assert: res.status: eq 200
Get game by non-existing id (404 ) - 7 ms
✓ assert: res.status: eq 404
Update Game - existing id (200 ) - 16 ms
Monitoring - Metrics (200 ) - 11 ms
Monitoring - Info (200 ) - 2 ms
Monitoring - Health (200 ) - 4 ms
Delete Game by existing id (204 ) - 12 ms
✓ assert: res.status: eq 204
Delete Game by non existing id (404 ) - 9 ms
✓ assert: res.status: eq 404
Upload Games from JSON File (415 ) - 9 ms
Update Game - non existing id (200 ) - 7 ms
Requests: 12 passed, 12 total
Tests: 2 passed, 2 total
Assertions: 6 passed, 6 total
Ran all requests - 245 ms
Requests: 12 passed, 12 total
Tests: 2 passed, 2 total
Assertions: 6 passed, 6 total
I like Bruno - open source, local execution, no cloud services required. Support for GUI and CLI. Excellent support for adding asserts and test to your requests.
Is implemented by MS SQL 2022. This setup ships with an empty database. Using Bruno you can easily create items or upload the a set of default games. By default the service default games are loaded from file:///./games-service/src/(resources/board-games.json on startup if the db is empty.
The devcontainer includes Prometheus, Grafana and Alertmanager to monitor your app. Never underestimate the importance of monitoring your app. It is crucial to know how your app is doing in production. This setup includes everything you need to get started to monitor your app and to be notified when something goes wrong.
For me gathering metrics & generating appropriate alerts is key to enable us to run a reliable platform. Dashboards are great to visualize the metrics, but alerts are crucial to be notified when something goes wrong. Dashboards should be build in a way that makes it easy to spot issues. Maybe even more important than just sending alerts it is imperative to send usefull alerts - and not too many of them to prevent alert fatigue.
is used to visualize the collected metrics. This setup ships with a preconfigured datasource connection to prometheus. You only need to add a dashboard to show Spring boot metrics. For starters you can try dashboard 19004:
-
Open Grafana - default credentials are
admin
/admin
:.env
file contains the default password → GF_SECURITY_ADMIN_PASSWORD. -
You can import this dashboard by clicking on the
+
icon in the left sidebar and selectingImport
. Then paste the dashboard ID19004
into the input field and click onLoad
. You can then select the Prometheus datasource and click onImport
.
is used to send notifications when an alert is triggered. Since you definitely want to be notified when your app is down or when something goes wrong, I added a simple alerting rule that will trigger an alert when the app is down. To keep it simple the alerts will be sent via email to a local mailtcatcher. image::https://github.com/CWACoderWithAttitude/dc-spring-boot-all-in-one/blob/main/images/mailcatcher-alert-messages.png[Mailcatcher Alert Messages]
can be reached at http://localhost:1080 (You can test the email notification by sending a test email to the configured SMTP server.) This is an app that accepts SMTP mail connections.Received mails are shown in a web gui. This is a great way to test email notifications without having to set up a real SMTP server.
To make is as easy for you as possible i included difffent ways to peek into the datase. One is a web based GUI, the other is a CLI tool.
Adminer is a web based DB management tool that can be used to manage your database. It can be reached at http://localhost:8010. Please lookup the DB password fron .env file - look out for property mssql_sa_password
.
In case you prefer CLI I included mssql-tools
:
The DB password for the
sa
user is stored in the.env
file asmssql_sa_password
. It’s injected into the mssql-tools container in docker-compoose asMSSQL_PASSWORD
.
docker exec -it mssql.local /bin/bash
root@2f8bd524f7bf:/# sqlcmd -S mssql.local -U sa -P ${MSSQL_PASSWORD}
1> SELECT name FROM master.dbo.sysdatabases
2> go
name
-----
master
tempdb
model
msdb
(4 rows affected)
1> USE msdb
2> go
Changed database context to 'msdb'.
1> SELECT top 5 id, title, ean13 FROM dbo.game WHERE title != "" and ean13 != ""
2> go
id title ean13
--------------------------
34 Catan, Das Würfelspiel 4002051699093
52 Catan, Das Würfelspiel 4002051699093
53 Catan, Das Würfelspiel 4002051699093
54 Catan, Das Würfelspiel 4002051699093
(4 rows affected)
When developing a REST API you need to think about a lot of things. You need to think about how to test your code, how to monitor it, how to deploy it and how to make sure it runs in a container. This is a lot of stuff to think about. So I thought it would be a good idea to build a full blown REST API that covers all these topics. The goal is to show you how to do all this stuff in a simple way. The goal is not to build the best API ever.
We all know "Works on my machine" is a bad slogan. What if "works on my machine" simply means: great - ship it. What if we could turn "works on my machine" into "works in a container"? An envirnment that is consistent regardless of the host system. I want to show you why we should embrace the slogan "It works on my machine". Using devcontainers it is easy to build your product in an environment that’s pretty close to your prod env. Let’s face it - we all have different machines and different setups. When using containers starting from day one you can be suree
OK |
|
http://localhost:8010 DB Admin Frontend |
OK |
Prometheus Targets Check scraping metrics from endpoints is healthy |
OK |
Grafana Visualize Metrics |
OK |
OK |
|
Mailcatcher - Fake SMTP Apps may send SMTP Mails to Pot 1025 |
OK |
-
Integrate alerting into the setup. This will be done with
-
❏ - AlertManager and
-
❏ - Grafana Alerting and
-
-
❏ - publish JaCoCo Report
-
❏ - Integrate Keycloak for authentication and authorization
-
❏ - Run app on Firebase
-
❏ - Deploy app on AWS using CDK and AWS Lambda
-
❏ - Add Kong API Gateway
-
❏ - Automate conversion of asciidoc 2 markdown. Makefile contains
generate_markdown: clean asciidoc2docbook docbook2md
to do exactly that. It should be added to the build pipeline to generate the markdown file automatically… -
❏ - addd appropriate icons to the architecture diagram
-
❏ - fix test mocks for metrics and counters
-
https://learn.microsoft.com/de-de/java/openjdk/containers[Container-Bilder für den Microsoft Build von OpenJDK
-
How Spring Boot Maps Environment Variables to Configuration Properties
-
Testing Spring Boot Applications: Best Practices and Frameworks
-
Spring Boot with MS SQL === Monitoring _ Prometheus Overview
Documenation is provided in Asciidoc format. - Asciidoctor User Manual - Asciidoctor Diagram Extension - Asciidoctor Diagram - Ditaa, PlantUML, Graphviz, Mermaid, etc. - https://docs.github.com/de/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks [Creating and highlighting code blocks] - Creating diagrams with Mermaid - Creating diagrams with PlantUML - Creating diagrams with Ditaa - Creating diagrams with Graphviz - Creating diagrams with Asciidoctor Diagram