version : 3.3.4
OS : windows 10 Pro
Spring Boot 프로젝트를 이미지 파일로 빌드한 후에 Docker에서 실행하는 법을 기록한다.
docker-compose.yml 파일은 로컬 개발 환경에서 MySQL과 Redis를 Docker로 실행할 수 있도록 설정되어 있다.
만약 Spring Boot를 로컬에서 실행하지 않고 도커 내에 배포를 하려면
application.yml과 docker-compose를 수정하고 DockerFile을 추가해야 한다.
docker-compose.yml
services:
mysql:
image: 'mysql:8.0'
environment:
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
TZ: Asia/Seoul
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
ports:
- '3307:3306'
volumes:
- "./mysql/data:/var/lib/mysql"
- "./src/main/sql:/docker-entrypoint-initdb.d"
restart: always
redis:
image: 'redis:latest'
command: ["redis-server", "--requirepass", "klmin6394"]
volumes:
- ./redis/data:/data
ports:
- '6379:6379'
restart: always
application-docker.yml Spring Boot가 로컬에서 실행될 때 Docker로 실행되는 MySQL과 Redis 컨테이너에 연결할 수 있도록 설정한다.
application-docker.yml
spring:
docker:
compose:
enabled: true
datasource:
url: jdbc:mysql://localhost:3307/product
username: product
password: product@1234
driver-class-name: com.mysql.cj.jdbc.Driver
data:
redis:
host: localhost
port: 6379
password: klmin6394
배포 환경에서는 Spring Boot도 Docker 컨테이너로 실행된다. docker-compose.prod.yml 파일은 배포 시 MySQL과 Redis와 함께 Spring Boot 애플리케이션을 컨테이너로 구성한다.
docker-compose.prod.yml
services:
mysql:
image: 'mysql:8.0'
environment:
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
TZ: Asia/Seoul
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
ports:
- '3307:3306'
volumes:
- "./mysql/data:/var/lib/mysql"
- "./src/main/sql:/docker-entrypoint-initdb.d"
networks:
- product_api_server_network
restart: always
redis:
image: 'redis:latest'
command: ["redis-server", "--requirepass", "klmin6394"]
volumes:
- ./redis/data:/data
ports:
- '6379:6379'
networks:
- product_api_server_network
restart: always
app:
image: 'product-api-server'
build:
context: .
dockerfile: Dockerfile
ports:
- '8080:8080'
networks:
- product_api_server_network
depends_on:
- mysql
- redis
networks:
product_api_server_network:
현재 로컬에 MySQL이 3306 포트로 실행 중이어서 Docker에서 실행된 MySQL을 외부에서 접근하기 위해 3307 포트로 설정해주었다.
Docker 내부 통신에서는 MySQL 기본 포트인 3306을 그대로 사용하도록 지정했다.
app이라고 작성.product-api-server로 지정.Dockerfile을 기준으로 하여 product-api-server라는 이름의 이미지를 생성한다.product_api_server_network라는 네트워크를 생성하여 mysql, redis, app 서비스가 서로 통신할 수 있도록 설정했다.app서비스가 의존하는 서비스들을 명시한다.app이 시작되기 전에 mysql과 redis가 먼저 시작된다.application-prod.yml 파일은 배포 환경에서 사용되며 Docker Compose에서 정의한 서비스 이름으로 MySQL과 Redis에 연결하도록 설정한다.
application-prod.yml
spring:
docker:
compose:
enabled: true
datasource:
url: jdbc:mysql://mysql:3306/product
username: product
password: product@1234
driver-class-name: com.mysql.cj.jdbc.Driver
data:
redis:
host: redis
port: 6379
password: klmin6394
localhost:3306/product가 아니고mysql:3306/product 이다.서비스명을 써줘야 한다.localhost가 아니고 redis이다.Dockerfile : 애플리케이션을 배포 가능한 이미지로 빌드하기 위한 설정 파일이다. Dockerfile에 작성된 명령어들은 순차적으로 실행되며 최종적으로 하나의 Docker 이미지가 생성된다.
이 이미지를 기반으로 컨테이너를 실행할 수 있다.
gradle build후 명령어로 실행
빌드를 미리 한 후 docker-compose 명령어를 실행한다.
// Dockerfile
FROM openjdk:21-jdk-slim
COPY build/libs/product-api-server.jar /product-api-server.jar
ENTRYPOINT ["java", "-jar", "/product-api-server.jar", "--spring.profiles.active=prod"]
build/libs/product-api-server.jar 파일을 컨테이너 이미지 내부의 /product-api-server.jar 위치로 복사한다.["java", "-jar", "/product-api-server.jar", "--spring.profiles.active=prod"]는 컨테이너가 시작될 때 Java로 JAR 파일을 실행하고 이때 profile은 prod로 실행된다.// Docker-compose 명령어
docker-compose -f docker-compose.prod.yml up --build -d
docker-compose.prod.yml 파일을 사용해 Docker 이미지를 빌드하고 이를 기반으로 컨테이너를 백그라운드에서 실행하는 명령.
docker-compose : Docker Compose 명령어로 여러 컨테이너로 구성된 애플리케이션을 정의하고 실행하기 위해 사용한다.-f docker-compose.prod.yml : -f 옵션은 사용할 Compose 설정 파일을 지정하는 옵션이다.up : 설정 파일에 정의된 모든 서비스를 빌드하고 실행하는 명령어이다.--build : 서비스에 필요한 이미지를 강제로 다시 빌드하도록 지정하는 옵션이다.-d : 백그라운드 모드에서 컨테이너를 실행하도록 지정한다.
dockerfile로 이미지를 만들고 컨테이너에 실행이 되었다.

docker desktop에서 생성된 모습이다.

실행 로그이다.

요청을 해보면 정상적으로 요청이 가는것을 확인할 수 있다.

Dockerfile에 gradle build도 포함한다.
Dockerfile에서 여러 FROM 명령을 사용하여 여러 스테이지로 나누어 이미지를 빌드하는 방식이다.
빌드에 필요한 도구와 최종 실행 환경을 분리함으로써 최종 이미지에 빌드 도구나 불필요한 파일을 포함하지 않도록 하여 이미지 크기를 줄이고 보안성을 높이는 데 유용하다.
빌드 스테이지 : Dockerfile에서 여러 개의 FROM 명령을 사용하여 여러 스테이지를 정의할 수 있다.실행 스테이지 : COPY --from=<스테이지 이름> 명령을 사용하여 빌드 스테이지에서 생성된 결과물(예: 빌드된 애플리케이션 파일)을 선택적으로 복사할 수 있다.최종 이미지 최적화 : 멀티 스테이지 빌드를 사용하면 최종 이미지에 필요한 파일만 포함하게 되어 이미지 크기를 줄일 수 있고 보안성도 높일 수 있다.// build.gradle
tasks.named("bootJar") {
mainClass = 'com.product.ProductApplication' // 실제 메인 클래스 경로로 설정
}
mainClass를 설정하지 않으면 bootJar 작업 중 메인 클래스를 찾지 못해 빌드 오류가 발생할 수 있다.
//Dockerfile
# 1단계: 빌드 스테이지
FROM gradle:8.10.2-jdk21 AS builder
WORKDIR /app
# Gradle 빌드 파일만 먼저 복사하여 종속성 캐시를 활용
COPY build.gradle settings.gradle /app/
RUN gradle build -x test --no-daemon
# 소스 코드 복사 및 빌드
COPY src /app/src
RUN gradle bootJar -x test --no-daemon
# 2단계: 실행 스테이지
FROM openjdk:21-jdk
COPY --from=builder /app/build/libs/product-api-server.jar /product-api-server.jar
# 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "/product-api-server.jar", "--spring.profiles.active=prod"]
gradle:8.10.2-jdk21 이미지를 사용하여 Gradle 빌드 환경을 설정한다.build.gradle 및 settings.gradle 파일을 먼저 복사하여 종속성을 캐시한다.gradle bootJar -x test를 실행하여 JAR 파일을 빌드한다. openjdk:21-jdk 이미지를 사용하여 실행 환경을 설정한다.ENTRYPOINT로 JAR 파일을 실행한다.//Docker dompose 명령어
docker-compose -f docker-compose.prod.yml up --build -d
docker-compose.prod.yml 파일을 사용해 이미지를 빌드하고 컨테이너를 백그라운드에서 실행한다.





Windows 10 로컬에서 도커 서비스 연동 : https://velog.io/@klmin/spring-boot-docker-compose-%EB%82%B4%EC%9A%A9-%EA%B8%B0%EB%A1%9D