Efficient Software Deployment: Docker

Yunus Emre Ulusan
5 min readJan 27, 2024

Hello, in this article, I will talk about Docker, a lifesaver in today’s large projects and an essential component in projects. Let’s try to understand the topic by integrating Docker with Spring Boot.

Containerization 101:

  • Imagine a shipping container. It efficiently packs essential goods, protecting them from external factors and ensuring consistent delivery to various destinations. Similarly, in software development, containerization bundles an application with its necessary dependencies (libraries, configuration files, etc.) into a standardized unit called a container. These containers operate in isolation from their host environment; they share the core of the underlying operating system but have their dedicated resources. This isolation ensures predictable application behavior, regardless of the underlying infrastructure.

Now, I will create the docker-compose.yml file in the project directory. The purpose of creating this file is to define, configure, and manage applications with multiple containers. This file specifies how your application will be run and configured in the Docker environment.

version: '3'
services:
db:
container_name: postgres_db
image: postgres
restart: always
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- db:/var/lib/postgresql/data
ports:
- "5432:5432"
app:
container_name: my-app
build: .
restart: always
depends_on:
- db
ports:
- "6060:8080"
environment:
- SPRING_DATASOURCE_URL=${SPRING_DATASOURCE_URL}
- SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME}
- SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
volumes:
db:

The following statement represents the .env file where we store our sensitive information for security reasons.

# PostgreSQL Settings
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=my_db

# Spring Boot App Settings
SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/my_db
SPRING_DATASOURCE_USERNAME=postgres
SPRING_DATASOURCE_PASSWORD=postgres

I will explain the steps here one by one.

Firstly, for the PostgreSQL service named,

  • db we need to choose the database that we will use according to the project’s needs. I chose PostgreSQL.
  • I gave a name to the container_name I want to create, which is postgres_db.
  • The layer we call “image” works on previously prepared packages. We can give a version to the “image,” or we can fetch the latest updated version of PostgreSQL by saying “image: postgres:latest”.
  • volume :This statement creates a Docker volume named “db” and associates this volume with the directory “/var/lib/postgresql/data” inside the PostgreSQL container. The “volumes” section represents disk space used in connection with one or more Docker containers. Docker containers are generally of a temporary nature, and data created at runtime may be lost when the container is stopped or deleted. However, applications or files requiring persistent data, such as a database, can use “volumes” to prevent this situation.
  • environment: Environmental variables for PostgreSQL. Information such as username, password, and database name is configured through these variables.
  • ports: Specifies the port connection between the host and the container (‘5432:5432’).

Secondly, for the Application Service “app” named,

  • Application Service(app): container_name: The name of the application container (my-app).
  • build: Built from the directory where the Dockerfile for the application is located (.).
  • restart: Automatically restarts the container at all times.
  • depends_on: Ensures that the application starts before other dependent services (db)start.
  • ports: The expression “6060:8080” in the Docker Compose file maps this listening port to port 6060 on the host machine. In other words, requests coming from the outside world are directed to port 6060 on the host machine, and these requests are then forwarded to port 8080 of the application within the Docker container. This allows access to the application from the host machine via http://localhost:6060.
  • environment: Environmental variables for the Spring Boot application, including database connection information.

The last stage is,

  • Volumes (volumes): db: A volume to store data for the PostgreSQL container.

Now we will create our Dockerfile.

Creating a Dockerfile aims to specify how Docker containers should be built. Docker containers provide lightweight, isolated runtime environments, allowing applications, services, and dependencies to run consistently and portably across various environments.

FROM maven:3.8.3-openjdk-17-slim AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src/ /app/src/
RUN mvn package -DskipTests

FROM openjdk:18
WORKDIR /app
COPY --from=build /app/target/my-app-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]

The primary goals of crafting a Dockerfile include:

  1. Portability
  2. Reproducible Builds
  3. Automation with Drag-and-Drop
  4. Isolation

Creating a Dockerfile is a crucial step that determines how an application will be packaged into a Docker container. This enables the application to be quickly deployable, replicable, and manageable.

Dockerfile:

First Stage (build): FROM maven:3.8.3-openjdk-17-slim: Uses the base image containing Maven and OpenJDK.

  • WORKDIR /app: Sets the working directory to /app.
  • COPY pom.xml .: Copies the pom.xml file to install Maven dependencies.
  • RUN mvn dependency:go-offline: Downloads dependencies.
  • COPY src/ /app/src/: Copies application source code.
  • RUN mvn package -DskipTests: Builds the application package, skipping tests.

Second Stage: FROM openjdk:18: Uses the OpenJDK 18 image.

  • WORKDIR /app: Sets the working directory to /app.
  • COPY — from= build /app/target/my-app-0.0.1-SNAPSHOT.jar
  • app.jar: Copies the JAR file generated in the first stage.
  • ENTRYPOINT [“java”,”-jar”,”app.jar”]: Runs the application JAR file when the Docker container starts.

This structure can be used to launch a Java Spring Boot application and a PostgreSQL database within the same Docker network.

  • Docker Compose file we created can be executed using the command ‘docker-compose -f docker-compose.ym --env-file .env up -d’, pulling specific information from the .env file.
  • If any changes are made to the modules in our project, we can update the Docker container by adding ‘--build’ to the end of the command, like ‘docker-compose -f docker-compose.ym --env-file .env up -d --build’, pulling private information from the .env file as the Docker container is updated.
  • After executing this command and obtaining a successful result, you can view the running containers with the ‘docker ps’ command. If you encounter an error, you can use the ‘docker logs my-app’ command to check the logs of that specific container.

I hope this text will be useful to you.

“You can access my other articles from the links below;

--

--