Spring: setting up a local development environment for micro services with Docker

Riekelt Brands
3 min readMar 24, 2022

In the past few weeks I have been working on moving a bunch of Symfony applications that formed the logistical backbone of a company to Spring micro services.

Due to the fact that these services are closely knitted together, I felt the need to connect these services in a Docker network. But before we can do that, I first had to set-up the Docker environment for each of these services. In this article I’ll walk you through the steps I took to accomplish this.

Do note that I am not very experienced with Dockerizing Spring applications yet, so if you see me committing a sin then please do let me know in the comments! Any other feedback is of course welcome as well :)

Dockerizing an individual Spring service

For this example I’ll take a rather simple service in the stack: the auditing service. This service takes log entries from other services and processes them into a global audit log. The service is packaged into a single JAR file which we need to Dockerize.

After some tinkering, I settled on this Dockerfile with OpenJDK 17:

FROM openjdk:17-slim
EXPOSE 8000
WORKDIR /opt/app
ARG JAR_FILE=target/audit.jar
ADD ${JAR_FILE} /opt/app/app.jar
ENTRYPOINT ["java","-jar","/opt/app/app.jar","--spring.config.location=<a bunch of config files>"]

As you can see, we simply take the service JAR and store it in the Docker container under /opt/app/app.jar. I do pass a bunch of additional configuration files along, since this service is running a few instances in production with each their own properties file.

Now we have our service running in Docker, but we need to have a way to access this service from our browser, Postman and what have you.

Preparing the service for a local Nginx proxy

To achieve this, we need two files: a Nginx configuration file and a Dockerfile to set up our Nginx instance.

The Nginx configuration file consists of a simple reverse proxy:

server {
listen 80;
server_name audit.loc;

location / {
proxy_pass http://svc-audit:8000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
}

And the Dockerfile simply takes this configuration file, and sets it as the default Nginx configuration file:

FROM nginx:1.16.1-alpine AS nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf

Tying it all together with Docker Compose

So now we have our service container and our Nginx container all that’s left is to tie it together and link the services with our Docker network.

This is the Docker Compose file I settled for:

version: "3.7"

services:
audit:
image: system/svc-audit
container_name: svc-audit
volumes:
- ../../devenv/conf:/opt/<system>/conf:ro
- ../../devenv/keys:/opt/<system>/keys:ro
- ./docker:/opt/<system>/local-conf:ro
build:
context: ./
dockerfile: Dockerfile
restart: always

web:
image: system/nginx-audit
container_name: nginx-audit
build:
context: ./docker/nginx
dockerfile: Dockerfile
environment:
- VIRTUAL_HOST=audit.loc
volumes:
- ./:/data:rw
ports:
- 80
networks:
default: ~
nginx-proxy:
aliases:
- audit.loc

networks:
default:
external:
name: system
nginx-proxy:
external:
name: nginx-proxy

Note that I’m using jwilder/nginx-proxy as an Nginx proxy. This makes accessing the services a breeze.

Let’s launch it!

Now that we’re done with our configuration, all that’s left is to build and launch the application:

docker-compose build
docker-compose up -d
docker-compose logs audit

If all is well you should now see your application running in Docker :)

--

--