Skip to main content
The Furniture API includes Docker configuration for containerized deployment. This guide covers building and running the application with Docker.

Prerequisites

Ensure you have the following installed:
  • Docker Engine 20.10 or higher
  • Docker Compose V2
  • At least 2GB of available RAM
  • At least 1GB of available disk space

Docker Configuration

Dockerfile Overview

The application uses a multi-stage Dockerfile optimized for Spring Boot applications:
1

Dependencies Stage

Downloads Maven dependencies using the Maven wrapper:
FROM eclipse-temurin:21-jdk-jammy as deps
WORKDIR /build
COPY --chmod=0755 mvnw mvnw
COPY .mvn/ .mvn/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw dependency:go-offline -DskipTests
2

Build Stage

Compiles the application and creates the JAR file:
FROM deps as package
WORKDIR /build
COPY ./src src/
RUN --mount=type=bind,source=pom.xml,target=pom.xml \
    --mount=type=cache,target=/root/.m2 \
    ./mvnw package -DskipTests && \
    mv target/*.jar target/app.jar
3

Extract Stage

Extracts Spring Boot layers for better caching:
FROM package as extract
WORKDIR /build
RUN java -Djarmode=layertools -jar target/app.jar extract \
    --destination target/extracted
4

Runtime Stage

Creates minimal runtime image with non-root user:
FROM eclipse-temurin:21-jre-jammy AS final
RUN adduser --disabled-password --uid 10001 appuser
USER appuser
COPY --from=extract build/target/extracted/dependencies/ ./
COPY --from=extract build/target/extracted/spring-boot-loader/ ./
COPY --from=extract build/target/extracted/snapshot-dependencies/ ./
COPY --from=extract build/target/extracted/application/ ./
EXPOSE 8082
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
The multi-stage build reduces final image size and improves build caching. Dependencies are cached separately from application code.

Building the Docker Image

Basic Build

Build the Docker image using:
docker build -t furniture-api .

Build with Tag

Build with version tag:
docker build -t furniture-api:0.0.1-SNAPSHOT .
The Dockerfile uses BuildKit syntax for improved caching. Ensure BuildKit is enabled:
export DOCKER_BUILDKIT=1

Running with Docker

Run Container

Start the container with port mapping:
docker run -p 8082:8082 furniture-api

Run with Environment Variables

Pass environment variables for configuration:
docker run -p 8082:8082 \
  -e DB_HOST=your-db-host \
  -e DB_PORT=5432 \
  -e DB_NAME=catalog_and_inventory_db \
  -e DB_USERNAME=your-username \
  -e DB_PASSWORD=your-password \
  furniture-api

Run in Detached Mode

Run container in background:
docker run -d -p 8082:8082 --name furniture-api furniture-api

Docker Compose Configuration

Basic Setup

The compose.yaml file defines the application service:
services:
  server:
    build:
      context: .
    ports:
      - 8082:8082

With PostgreSQL Database

Extend the configuration to include PostgreSQL:
services:
  server:
    build:
      context: .
    ports:
      - 8082:8082
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=catalog_and_inventory_db
      - DB_USERNAME=postgres
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/catalog_and_inventory_db
    depends_on:
      db:
        condition: service_healthy
  
  db:
    image: postgres:16-alpine
    restart: always
    environment:
      - POSTGRES_DB=catalog_and_inventory_db
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - db-data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db-data:
Create the db/password.txt file with your database password before running Docker Compose with secrets.

Docker Compose Commands

Start Services

1

Build and start

Build images and start all services:
docker compose up --build
2

Run in background

Start services in detached mode:
docker compose up -d
3

View logs

Monitor application logs:
# All services
docker compose logs -f

# Specific service
docker compose logs -f server

Stop Services

# Stop services
docker compose stop

# Stop and remove containers
docker compose down

# Stop and remove containers, volumes, and images
docker compose down -v --rmi all

Image Optimization

Layer Caching

The Dockerfile is optimized for layer caching:
  1. Dependencies are downloaded in a separate layer
  2. Maven cache is persisted between builds
  3. Spring Boot layers are extracted separately
  4. Only changed layers are rebuilt
This approach significantly speeds up rebuilds when only application code changes, as dependencies don’t need to be re-downloaded.

Image Size

The final image uses JRE instead of JDK:
FROM eclipse-temurin:21-jre-jammy AS final
This reduces image size by approximately 200-300 MB compared to using the full JDK.

Security Best Practices

Non-Root User

The application runs as a non-privileged user:
ARG UID=10001
RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "/nonexistent" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    appuser
USER appuser

Port Configuration

The application exposes port 8082:
EXPOSE 8082
Map to a different host port if needed:
docker run -p 8080:8082 furniture-api

Health Checks

Add health check to Docker Compose:
services:
  server:
    build:
      context: .
    ports:
      - 8082:8082
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8082/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
The Furniture API includes Spring Boot Actuator, which provides a /actuator/health endpoint for health checks.

Troubleshooting

Build Failures

If the build fails:
# Clear build cache
docker builder prune

# Rebuild without cache
docker build --no-cache -t furniture-api .

Container Won’t Start

Check container logs:
docker logs furniture-api

# Or with Docker Compose
docker compose logs server

Connection Issues

If the application can’t connect to the database:
  1. Verify database container is running: docker compose ps
  2. Check network connectivity: docker compose exec server ping db
  3. Verify environment variables: docker compose exec server env | grep DB

Port Already in Use

If port 8082 is already in use:
services:
  server:
    ports:
      - 8083:8082  # Map to different host port

Build docs developers (and LLMs) love