Containerizing a Two-Tier Java Application with Docker Compose and Image Scanning using Docker Scout

Ajinkya GiriAjinkya Giri
3 min read

πŸ“˜ Introduction

In this blog, we will explore how to containerize a two-tier Java application using Docker, manage services with Docker Compose, and ensure image security through Docker Scout.

We'll walk through a practical use case: a Java Spring Boot backend connected to a MySQL database, containerized using modern DevOps techniques like multi-stage builds, health checks, and vulnerability scanning.


🧱 Docker Compose

Docker Compose allows you to define and orchestrate multi-container applications using a single docker-compose.yml file.

✨ Key Benefits:

  • Multi-container management: Define backend, database, and other services together.

  • Networking: Automatic internal networking with simple service names.

  • Scaling: Increase container replicas with ease.

  • Environment variables: Easily configure apps for different environments.


🧰 Multi-stage Docker Builds

Multi-stage builds reduce the final image size and improve build performance by separating build-time and runtime environments.

✨ Key Benefits:

  • Smaller images: Only necessary files included in the final image.

  • Faster builds: Clean and layered build stages.

  • Improved security: No dev tools in production image.


πŸ”§ Prerequisites

Ensure the following tools are installed:

  • Docker (v23+ recommended for Docker Scout)

  • Git

  • AWS EC2


πŸ“ Step 1: Clone the Repository

git clone https://github.com/Ajinkya-Giri27/Expenses-Tracker-WebApp.git
cd Expenses-Tracker-WebApp

πŸ› οΈ Step 2: Create a Dockerfile

Here is a basic Dockerfile using Maven to build the JAR file:

FROM maven:3.8.3-openjdk-17 AS builder
WORKDIR /app
COPY . /app
RUN mvn clean install -DskipTests=true
EXPOSE 8080
CMD ["java", "-jar", "/expenseapp.jar"]

⚑ This works, but we can optimize it using multi-stage builds.

πŸ‹οΈ Step 3: Optimize with Multi-stage Dockerfile

# Stage 1 - Build the JAR
FROM maven:3.8.3-openjdk-17 AS builder
WORKDIR /app
COPY . /app
RUN mvn clean install -DskipTests=true

# Stage 2 - Run the JAR
FROM openjdk:17-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar /app/target/expenseapp.jar
EXPOSE 8080
CMD ["java", "-jar", "/app/target/expenseapp.jar"]

πŸ”§ This significantly reduces image size and improves security.

πŸ“ Step 4: Create a Docker Compose File

version: "3.8"
services:
  java_app:
    build: .
    container_name: "expensesapp"
    environment:
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/expenses_tracker?allowPublicKeyRetrieval=true&useSSL=false
      SPRING_DATASOURCE_PASSWORD: Test@123
    ports:
      - "8080:8080"
    networks:
      - expenses-app-nw
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000 || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    depends_on:
      - mysql_db
    restart: always

  mysql_db:
    image: mysql
    container_name: "mysql"
    environment:
      MYSQL_ROOT_PASSWORD: Test@123
      MYSQL_DATABASE: expenses_tracker
    volumes:
      - ./mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - expenses-app-nw
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pTest@123"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    restart: always

networks:
  expenses-app-nw:

volumes:
  mysql-data:

πŸš€ Step 5: Run with Docker Compose

docker-compose up --build

🚧 This command builds the images and runs both containers.


🌐 Step 6: Access the Application

Once the containers are running, visit:

http://<your-ec2-ip>:8080

You should see the Expense Tracker App up and running!


πŸ›‘οΈ Docker Scout Image Scanning

πŸ”Ž Scan for vulnerabilities:

docker scout cves expensesapp

πŸ“ƒ Generate a Software Bill of Materials (SBOM):

docker scout sbom expensesapp

πŸ”§ Make sure you're logged in to Docker Hub (docker login) and using Docker CLI v23+.

πŸ“Š Summary

In this guide, we:

  • 🏒 Containerized a Java + MySQL two-tier app

  • βš–οΈ Used Docker Compose for orchestration

  • πŸ‹οΈ Optimized with multi-stage Docker builds

  • πŸ›‘οΈ Scanned image for vulnerabilities using Docker Scout

This approach ensures:

  • Smaller, production-ready images

  • Better build performance

  • Improved security and maintainability


πŸŽ‰ Happy Shipping!

Fork the repo πŸ“, try it on your machine πŸš€, and feel free to ask questions or share feedback in the comments!

✨ Don’t forget to follow me on Hashnode & GitHub for more DevOps content!

0
Subscribe to my newsletter

Read articles from Ajinkya Giri directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ajinkya Giri
Ajinkya Giri

πŸš€ Aspiring DevOps Engineer | Computer Engineering Student 🌍 Passionate about bridging the gap between development and operations, I am a computer engineering student with a keen interest in DevOps, automation, and cloud computing. I thrive on optimizing workflows, implementing CI/CD pipelines, and exploring the latest DevOps tools to enhance software deployment and scalability. πŸ”Ή Tech Interests: DevOps, Cloud Computing (AWS/Azure/GCP), Kubernetes, CI/CD, Infrastructure as Code πŸ”Ή Skills in Progress: Linux, Git, Docker, Terraform, Python/Bash scripting πŸ”Ή Goal: To master DevOps methodologies and contribute to seamless software delivery πŸš€ Always eager to learn, collaborate, and automate! πŸ’‘