Skip to content

Containerize application with Docker #190

@nanotaboada

Description

@nanotaboada

Description

This issue covers creating a containerized environment for the application with multi-stage builds and Docker Compose orchestration, plus updating the CI workflow to build and push the container image to GitHub Container Registry (GHCR). This ensures streamlined builds, easy local dev/testing, and automatic publishing of container images on push.

Proposed Solution

  • Create a multi-stage Dockerfile with build and runtime stages.
  • Add a .dockerignore file for efficient builds.
  • Add a Docker Compose file (compose.yaml) for local orchestration.
  • Include a health check script for container health validation.
  • Update the CI workflow to:
    • Build the Docker image.
    • Authenticate with GHCR.
    • Push the image with proper tags (e.g., latest, git SHA).

Suggested Approach

Dockerfile

# ------------------------------------------------------------------------------
# Stage 1: Builder
# This stage builds the application and its dependencies.
# ------------------------------------------------------------------------------
FROM maven:3.9-eclipse-temurin-21-alpine AS builder

WORKDIR /app

# Copy pom.xml and source code
COPY pom.xml    .
COPY src        ./src

# Build the application and skip tests for faster build
RUN mvn clean package -DskipTests

# ------------------------------------------------------------------------------
# Stage 2: Runtime
# This stage creates the final, minimal image to run the application.
# ------------------------------------------------------------------------------
FROM eclipse-temurin:21-jdk-alpine AS runtime

WORKDIR /app

# Install curl for health check
RUN apk add --no-cache curl

# Metadata labels for the image. These are useful for registries and inspection.
LABEL org.opencontainers.image.title="🧪 RESTful Web Service with Spring Boot"
LABEL org.opencontainers.image.description="Proof of Concept for a RESTful Web Service made with JDK 21 (LTS) and Spring Boot 3"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.source="https://github.com/nanotaboada/java.samples.spring.boot"

# https://rules.sonarsource.com/docker/RSPEC-6504/

# Copy application JAR file from the builder stage
COPY --from=builder     /app/target/*.jar       ./app.jar

# Copy metadata docs for container registries (e.g.: GitHub Container Registry)
COPY --chmod=444        README.md               ./
COPY --chmod=555        assets/                 ./assets/

# Copy entrypoint and healthcheck scripts
COPY --chmod=555        scripts/healthcheck.sh      ./healthcheck.sh

# Add system user
RUN addgroup -S spring && \
    adduser -S -G spring spring

USER spring

EXPOSE 9000
EXPOSE 9001

HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
    CMD ["./healthcheck.sh"]

ENTRYPOINT ["java", "-jar", "./app.jar"]

healthcheck.sh

#!/bin/sh
set -e

# Minimal curl-based health check with timeout and error reporting
curl --fail --silent --show-error --connect-timeout 1 --max-time 2 http://localhost:9000/health

.dockerignore

.github
.mvn
.vscode
target
.codacy.yml
.gitignore
azure-pipelines.yml
CODE_OF_CONDUCT.md
codecov.yml
CONTRIBUTING.md
LICENSE
mvnw
mvnw.cmd

compose.yaml

services:
  api:
    image: java-samples-spring-boot
    container_name: spring-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      - SPRING_PROFILES_ACTIVE=production
      - SERVER_PORT=9000
    restart: unless-stopped

Acceptance Criteria

  • Dockerfile builds a working image with multi-stage build.
  • .dockerignore excludes unnecessary files.
  • Docker Compose spins up the app with environment variables and health check working.
  • Docker image runs as non-root user.
  • CI workflow builds and pushes Docker image to GHCR on main branch push.
  • Workflow uses secrets safely and authenticates properly to GHCR.

Resources

Metadata

Metadata

Assignees

Labels

containersPull requests that update containers codeenhancementNew feature or requestjavaPull requests that update Java code

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions