Docker compose: Adding a reverse proxy (optional exercise - draft)
Goal:
Adding a single point of entry to our application using a reverse proxy (nginx). This will allow us to route requests to different services based on the request URL, and make the services private as they do not need to expose a port.
Step 1: Create a new docker-compose file
Create a new file called docker-compose.prod.yml in the same directory as your docker-compose.yml file.
In the docker-compose.prod.yml file, copy over the configuration from docker-compose.yml.
This file can contain different environment variables or settings for a production setup (although for this exercise, we will keep it simple).
Step 2: Configuring nginx
Create a new file called nginx.conf in the same directory as your docker-compose.yml file. This file will contain the configuration for the reverse proxy.
events {}
http {
server {
listen 80;
location / {
proxy_pass http://app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
This requires a little explanation:
- The
serverblock defines a server that listens on port 80 (the default HTTP port). - The
location /block defines how to handle requests to the root URL i.e./. - The
proxy_passdirective is used to specify the upstream server to which the request should be forwarded, in this casehttp://app:8080. - The
proxy_set_headerdirectives are used to pass the original request headers to theappservice. This is important for preserving information about the original request, such as the host and client IP address.
Step 3: Updating the compose file
In docker-compose.prod.yml file, add the nginx service:
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
We will also update the network
networks:
spring-mysql:
driver: bridge
nginx-spring:
driver: bridge
And update the services to use the new network
services:
nginx:
networks:
- nginx-spring
app:
expose:
- "8080"
networks:
- nginx-spring
- spring-mysql
db:
expose:
- "3306"
networks:
- spring-mysql
The idea here is, that we are using the reverse proxy to route requests to the appropriate service based on the request URL. This allows us to keep the services private and not expose their ports directly to the outside world. Instead, all requests go through the nginx reverse proxy, which then forwards them to the correct service (in this example only one service).
By splitting the networks, we can ensure that the database is not accessible from the nginx service, adding an extra layer of security.
Step 4: Adding health check to Spring Boot backend
Add support for health checks in the Spring Boot application. In the pom.xml file, add the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Then we can make use of the actuator endpoints to monitor the health of the application. This exposes the endpoint GET /actuator/health.
In the docker-compose.prod.yml file, add a health check to the app service:
services:
app:
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health >/dev/null 2>&1 || exit 1"]
interval: 5s
timeout: 2s
retries: 2
start_period: 10s
Then we make the nginx service depend on the app service:
services:
nginx:
depends_on:
app:
condition: service_healthy
Step 4: Testing the setup
To start the services, use the following command to start the containers in detached mode:
docker compose -f docker-compose.prod.yml up -d
Note that the -f flag is used to specify the compose file to use.
Check if the containers are running:
docker ps -a
If everything is running correctly, you should see the containers listed.
Test the setup by sending a request to the nginx reverse proxy:
curl http://localhost/api/messages
You should see the response from the app service.
If you encounter any issues, check the logs of the nginx container or the app container:
docker compose -f docker-compose.prod.yml logs nginx
docker compose -f docker-compose.prod.yml logs app
Step 5: Tear down
To stop and remove the containers, use the following command:
docker compose -f docker-compose.prod.yml down -v