Docker Compose: Spring Boot and Postgres example

Tien Nguyen - Oct 8 '23 - - Dev Community

Docker provides lightweight containers to run services in isolation from our infrastructure so we can deliver software quickly. In this tutorial, I will show you how to dockerize Spring Boot microservice and Postgres example using Docker Compose.

Related Posts:

Overview

Assume that we have a Spring Boot Application working with Postgres database.
The problem is to containerize a system that requires more than one Docker container:

  • Spring Boot for Rest API
  • Postgres for database

Docker Compose helps us setup the system more easily and efficiently than with only Docker. We're gonna following these steps:

  • Create Spring Boot App working with Postgres database.
  • Create Dockerfile for Spring Boot App.
  • Write Docker Compose configurations in YAML file.
  • Set Spring Boot Docker Compose Environment variables.
  • Run the system.

Directory Structure:

docker-compose-spring-boot-postgres

Create Spring Boot App

You can read and get Github source code from one of following tutorials:

Using the code base above, we put the Spring Boot project in bezkoder-app folder without the need of resources/application.properties. It is because Environment variables will be exported to .env file.

Create Dockerfile for Spring Boot App

Dockerfile defines a list of commands that Docker uses for setting up the Spring Boot application environment. So we put the file in bezkoder-app folder.

Because we will use Docker Compose, we won't define all the configuration commands in this Dockerfile.

bezkoder-app/Dockerfile



# FROM maven:3.8.2-jdk-8 # for Java 8
FROM maven:3.8.5-openjdk-17

WORKDIR /bezkoder-app
COPY . .
RUN mvn clean install

CMD mvn spring-boot:run


Enter fullscreen mode Exit fullscreen mode

Let me explain some points:

  • FROM: install the image of the Maven - JDK version.
  • WORKDIR: path of the working directory.
  • COPY: copy all the files inside the project directory to the container.
  • RUN: execute a command-line inside the container: mvn clean install to install the dependencies in pom.xml.
  • CMD: run script mvn spring-boot:run after the image is built.

Write Docker Compose configurations

On the root of the project directory, we're gonna create the docker-compose.yml file. Follow version 3 syntax defined by Docker:



version: '3.8'

services: 
    postgresdb:
    app:

volumes:


Enter fullscreen mode Exit fullscreen mode
  • version: Docker Compose file format version will be used.
  • services: individual services in isolated containers. Our application has two services: app (Spring Boot) and postgresdb (PostgreSQL database).
  • volumes: named volumes that keeps our data alive after restart.

Let's implement the details.

docker-compose.yml



version: "3.8"

services:
  postgresdb:
    image: postgres
    restart: unless-stopped
    env_file: ./.env
    environment:
      - POSTGRES_USER=$POSTGRESDB_USER
      - POSTGRES_PASSWORD=$POSTGRESDB_ROOT_PASSWORD
      - POSTGRES_DB=$POSTGRESDB_DATABASE
    ports:
      - $POSTGRESDB_LOCAL_PORT:$POSTGRESDB_DOCKER_PORT
    volumes:
      - db:/var/lib/postgres
  app:
    depends_on:
      - postgresdb
    build: ./bezkoder-app
    restart: on-failure
    env_file: ./.env
    ports:
      - $SPRING_LOCAL_PORT:$SPRING_DOCKER_PORT
    environment:
      SPRING_APPLICATION_JSON: '{
        "spring.datasource.url"  : "jdbc:postgresql://postgresdb:$POSTGRESDB_DOCKER_PORT/$POSTGRESDB_DATABASE",
        "spring.datasource.username" : "$POSTGRESDB_USER",
        "spring.datasource.password" : "$POSTGRESDB_ROOT_PASSWORD",
        "spring.jpa.properties.hibernate.dialect" : "org.hibernate.dialect.PostgreSQLDialect",
        "spring.jpa.hibernate.ddl-auto" : "update"
      }'
    volumes:
      - .m2:/root/.m2
    stdin_open: true
    tty: true

volumes:
  db:


Enter fullscreen mode Exit fullscreen mode
  • postgresdb:

    • image: official Docker image
    • restart: configure the restart policy
    • env_file: specify our .env path that we will create later
    • environment: provide setting using environment variables
    • ports: specify ports will be used
    • volumes: map volume folders
  • app:

    • depends_on: dependency order, postgresdb is started before app
    • build: configuration options that are applied at build time that we defined in the Dockerfile with relative path
    • environment: environmental variables that Spring Boot application uses
    • stdin_open and tty: keep open the terminal after building container

You should note that the host port (LOCAL_PORT) and the container port (DOCKER_PORT) is different. Networked service-to-service communication uses the container port, and the outside uses the host port.

Docker Compose Environment variables

In the service configuration, we used environmental variables defined inside the .env file. Now we start writing it.

.env



POSTGRESDB_USER=postgres
POSTGRESDB_ROOT_PASSWORD=123456
POSTGRESDB_DATABASE=bezkoder_db
POSTGRESDB_LOCAL_PORT=5433
POSTGRESDB_DOCKER_PORT=5432

SPRING_LOCAL_PORT=6868
SPRING_DOCKER_PORT=8080


Enter fullscreen mode Exit fullscreen mode

Run the Spring Boot microservice with Docker Compose

We can easily run the whole with only a single command:
docker compose up

Docker will pull the PostgreSQL and Maven images (if our machine does not have it before).

The services can be run on the background with command:
docker compose up -d



$ docker compose up -d
[+] Running 14/14
 ✔ postgresdb 13 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled                                                                                                                                                               30.0s 
   ✔ a803e7c4b030 Pull complete                                                                                                                                                                                               
   ✔ 009c876521a0 Pull complete                                                                                                                                                                                               
   ✔ 9c412905cca2 Pull complete                                                                                                                                                                                               
   ✔ 6463d4bf467a Pull complete                                                                                                                                                                                              
   ✔ bd8b983728ed Pull complete                                                                                                                                                                                              
   ✔ febc167f3560 Pull complete                                                                                                                                                                                              
   ✔ d73c81c4ade3 Pull complete                                                                                                                                                                                              
   ✔ 34b3b0ac6e9e Pull complete                                                                                                                                                                                              
   ✔ 9bd86d074f4e Pull complete                                                                                                                                                                                              
   ✔ 406f63329750 Pull complete                                                                                                                                                                                              
   ✔ ec40772694b7 Pull complete                                                                                                                                                                                              
   ✔ 7d3dfa1637e9 Pull complete                                                                                                                                                                                              
   ✔ e217ca41159f Pull complete                                                                                                                                                                                              
[+] Building 2.9s (9/9) FINISHED                                                                                                                                                                                    
 => [app internal] load build definition from Dockerfile                                                                                                                                                                      
 => => transferring dockerfile: 231B                                                                                                                                                                                          
 => [app internal] load .dockerignore                                                                                                                                                                                         
 => => transferring context: 2B                                                                                                                                                                                               
 => [app internal] load metadata for docker.io/library/maven:3.8.5-openjdk-17                                                                                                                                                 
 => [app 1/4] FROM docker.io/library/maven:3.8.5-openjdk-17@sha256:3a9c30b3af6278a8ae0007d3a3bf00fff80ec3ed7ae4eb9bfa1772853101549b                                                                                           
 => [app internal] load build context                                                                                                                                                                                         
 => => transferring context: 1.94kB                                                                                                                                                                                           
 => [app 2/4] WORKDIR /bezkoder-app                                                                                                                                                                                    
 => [app 3/4] COPY . .                                                                                                                                                                                                 
 => [app 4/4] RUN mvn clean install                                                                                                                                                                                    
 => [app] exporting to image                                                                                                                                                                                                  
 => => exporting layers                                                                                                                                                                                                       
 => => writing image sha256:bb65745b652009fa4bf508b771c9abc5e90f257f9efde63251df8c0a74c672d7                                                                                                                                  
 => => naming to docker.io/library/spring-boot-postgres-app                                                                                                                                                                   
[+] Running 2/1
 ✔ Container spring-boot-postgres-postgresdb-1  Created                                                                                                                                                                       
 ✔ Container spring-boot-postgres-app-1         Created                                                                                                                                                                       
Attaching to spring-boot-postgres-app-1, spring-boot-postgres-postgresdb-1
...
spring-boot-postgres-postgresdb-1  | PostgreSQL init process complete; ready for start up.
spring-boot-postgres-postgresdb-1  | 
spring-boot-postgres-postgresdb-1  | 
spring-boot-postgres-postgresdb-1  | 2023-10-03 03:35:18.102 UTC [1] LOG:  starting PostgreSQL 16.0 (Debian 16.0-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
spring-boot-postgres-postgresdb-1  | 2023-10-03 03:35:18.102 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
spring-boot-postgres-postgresdb-1  | 2023-10-03 03:35:18.102 UTC [1] LOG:  listening on IPv6 address "::", port 5432
spring-boot-postgres-postgresdb-1  | 2023-10-03 03:35:18.105 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
spring-boot-postgres-postgresdb-1  | 2023-10-03 03:35:18.109 UTC [64] LOG:  database system was shut down at 2023-10-03 03:35:18 UTC
spring-boot-postgres-postgresdb-1  | 2023-10-03 03:35:18.113 UTC [1] LOG:  database system is ready to accept connections
spring-boot-postgres-app-1         | [INFO] Scanning for projects...
spring-boot-postgres-app-1         | [INFO] 
spring-boot-postgres-app-1         | [INFO] --------------< com.bezkoder:spring-boot-jpa-postgresql >---------------
spring-boot-postgres-app-1         | [INFO] Building spring-boot-jpa-postgresql 0.0.1-SNAPSHOT
spring-boot-postgres-app-1         | [INFO] --------------------------------[ jar ]---------------------------------
spring-boot-postgres-app-1         | [INFO] 
spring-boot-postgres-app-1         | [INFO] >>> spring-boot-maven-plugin:3.1.0:run (default-cli) > test-compile @ spring-boot-jpa-postgresql >>>
...
spring-boot-postgres-app-1         | 2023-10-03T03:41:46.545Z  INFO 59 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
spring-boot-postgres-app-1         | 2023-10-03T03:41:46.551Z  INFO 59 --- [           main] s.j.p.SpringBootJpaPostgresqlApplication : Started SpringBootJpaPostgresqlApplication in 2.188 seconds (process running for 2.354)


Enter fullscreen mode Exit fullscreen mode

Now you can check the current working containers:



$ docker ps
CONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS         PORTS                                       NAMES
9c3d10422b09   spring-boot-postgres-app   "/usr/local/bin/mvn-…"   2 minutes ago   Up 2 minutes   0.0.0.0:6868->8080/tcp, :::6868->8080/tcp   spring-boot-postgres-app-1
ed0b41f7f1c8   postgres                   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:5433->5432/tcp, :::5433->5432/tcp   spring-boot-postgres-postgresdb-1


Enter fullscreen mode Exit fullscreen mode

And Docker images:



$ docker images
REPOSITORY                 TAG            IMAGE ID       CREATED         SIZE
spring-boot-postgres-app   latest         bb65745b6520   5 minutes ago   962MB
postgres                   latest         2d74f8a2591c   6 minutes ago   417MB


Enter fullscreen mode Exit fullscreen mode

Send a HTTP request to the Spring Boot - Postgres system:

docker-compose-spring-boot-postgres-test-api

Check Postgres Database:



$ docker exec -ti spring-boot-postgres-postgresdb-1 /bin/bash
root@8869979fbd27:/# psql bezkoder_db postgres
psql (16.0 (Debian 16.0-1.pgdg120+1))
Type "help" for help.

bezkoder_db=# SELECT * FROM tutorials;
 id |    description    | published |                title                 
----+-------------------+-----------+--------------------------------------
  1 | Tut#1 Description | f         | bezkoder Docker Spring Boot Postgres
(1 row)


Enter fullscreen mode Exit fullscreen mode

Stop the Application

Stopping all the running containers is also simple with a single command:
docker compose down



$ docker compose down
 ✔ Container spring-boot-postgres-app-1         Removed                                                                                                                                                      
 ✔ Container spring-boot-postgres-postgresdb-1  Removed                                                                                                                                                      
 ✔ Network spring-boot-postgres_default         Removed     


Enter fullscreen mode Exit fullscreen mode

If you need to stop and remove all containers, networks, and all images used by any service in docker-compose.yml file, use the command:
docker compose down --rmi all

Conclusion

Today we've successfully created Docker Compose file for Spring Boot application and Postgres. Now we can connect Spring Boot to PostgreSQL with Docker on a very simple way: docker-compose.yml.

You can apply this way to one of following project:

If you want to deploy the system on AWS, please visit:
Deploy Spring Boot App on AWS – Elastic Beanstalk

Happy Learning! See you again.

Source Code

The source code for this tutorial can be found at Github.

Documentation: Spring Boot + Swagger 3 example (with OpenAPI 3)
Caching: Spring Boot Redis Cache example

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .