# [Docker Compose 실습] Spring Boot 컨테이너 설정 맞추기

Docker Compose 실습편

- 현재 docker-compose.yml 진단하기

- Compose 파일 1차 정리하기

- Spring Boot 컨테이너 설정 맞추기 ← 현재 문서

- PostgreSQL 볼륨과 초기화 다루기

- 실행 검증과 문제 해결 루틴

Compose 파일을 정리해도 앱 컨테이너 자체가 올바르게 실행되지 않으면 전체 환경은 뜨지 않는다. 이번 실습의 목표는 Spring Boot 앱 이미지가 어떤 JAR을 실행하는지, 어떤 포트를 여는지, DB 주소를 어디서 받는지 맞추는 것이다.

현재 Dockerfile의 핵심 문제

현재 Dockerfile은 JAR 파일명을 환경 변수로 조립해서 실행한다.

ENV PROJECT_NAME=discodeit
ENV PROJECT_VERSION=0.0.1-SNAPSHOT

ENTRYPOINT ["sh", "-c", "java $JVM_OPTS -jar build/libs/${PROJECT_NAME}-${PROJECT_VERSION}.jar"]

하지만 현재 build.gradle에는 다음 값이 있다.

version = '2.0-M9'

settings.gradle의 프로젝트 이름은 다음과 같다.

rootProject.name = 'discodeit'

이 조합이면 기본 JAR 이름은 discodeit-2.0-M9.jar 형태가 될 가능성이 높다. Dockerfile은 discodeit-0.0.1-SNAPSHOT.jar를 실행하려고 하므로, 컨테이너 시작 시 파일을 찾지 못할 수 있다.

가장 단순한 해결책은 빌드된 JAR을 고정된 이름으로 복사해서 실행하는 것이다.

권장 Dockerfile 형태

아래는 현재 프로젝트에 맞춘 정리안이다.

FROM amazoncorretto:17 AS builder

WORKDIR /app

COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .

RUN chmod +x gradlew

COPY src src
RUN ./gradlew clean bootJar -x test --no-daemon

FROM amazoncorretto:17

WORKDIR /app

COPY --from=builder /app/build/libs/*.jar app.jar

EXPOSE 80

ENV JVM_OPTS=""

ENTRYPOINT ["sh", "-c", "java $JVM_OPTS -jar app.jar"]

이 방식의 핵심은 COPY --from=builder /app/build/libs/*.jar app.jar다. Gradle 버전이 바뀌어 JAR 파일명이 달라져도 최종 이미지 안에서는 항상 app.jar로 실행한다.

또한 빌드 스테이지와 실행 스테이지를 나누면 최종 이미지에 소스 코드와 Gradle 빌드 산출 과정을 덜 남길 수 있다. 이 프로젝트는 학습용이라 치명적인 문제는 아니지만, 컨테이너 이미지를 이해하고 관리하는 관점에서는 분리하는 편이 좋다.

build 대신 bootJar를 쓰는 이유

Spring Boot 앱을 컨테이너에서 실행할 때 필요한 것은 실행 가능한 Boot JAR이다. ./gradlew build는 테스트, 검증, 여러 빌드 작업을 함께 포함한다. 현재 Dockerfile은 -x test로 테스트를 제외하고 있지만, 의도는 "실행 JAR 만들기"에 가깝다.

그래서 Docker 이미지 빌드에서는 다음처럼 목적을 명확히 해도 된다.

./gradlew clean bootJar -x test --no-daemon

테스트를 이미지 빌드 단계에서 제외할지는 팀의 선택이다. 로컬 학습 환경에서는 빌드 속도를 위해 제외할 수 있다. CI에서는 이미지 빌드 전에 별도의 test 단계를 두는 편이 더 명확하다.

컨테이너의 DB URL 맞추기

현재 application-prod.yml에는 다음 설정이 있다.

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/discodeit_prod

컨테이너 안에서 이 값이 그대로 쓰이면 앱은 DB 컨테이너를 찾지 못한다. Compose에서 환경 변수로 덮어써야 한다.

app:
  environment:
    SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/${POSTGRES_DB}
    SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER}
    SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}

이 값이 들어가면 Spring Boot는 application-prod.ymllocalhost URL 대신 Compose 환경에 맞는 db 서비스 이름을 사용한다.

설정 파일도 함께 정리할 수 있다

더 명확하게 하려면 application-prod.yml의 DB URL도 운영 기본값이 아니라 환경 변수 기반으로 바꿀 수 있다.

```yaml

spring:

datasource:

url: ${SPRING_DATASOURCE_URL}

username: ${SPRING_DATASOURCE_USERNAME}

password: ${SPRING_DATASOURCE_PASSWORD}

```

그러면 운영 프로필은 "이 값은 외부에서 주입되어야 한다"는 의도가 더 선명해진다.

포트 맞추기

현재 운영 프로필은 앱 포트를 80으로 둔다.

server:
  port: 80

Dockerfile도 같은 포트를 문서화한다.

EXPOSE 80

Compose는 호스트 8081을 컨테이너 80에 연결한다.

ports:
  - "${APP_PORT:-8081}:80"

이 셋이 같은 방향을 보고 있어야 한다.

위치의미
application-prod.ymlserver.port: 80Spring Boot가 컨테이너 안에서 여는 포트
DockerfileEXPOSE 80이미지가 80번 포트를 사용한다는 힌트
docker-compose.yml${APP_PORT:-8081}:80호스트 포트를 컨테이너 80에 연결

이미지 빌드 확인

Dockerfile을 정리한 뒤에는 앱 이미지만 먼저 빌드한다.

docker compose build app

빌드가 성공하면 컨테이너를 실행한다.

docker compose up -d app

다만 appdb에 의존하므로 실제로는 다음처럼 전체를 띄우는 편이 자연스럽다.

docker compose up -d --build

실패하면 앱 로그를 먼저 본다.

docker compose logs -f app

JAR 파일명 문제라면 로그에 Unable to access jarfile 같은 메시지가 나온다. DB URL 문제라면 Connection refused, UnknownHostException, 인증 실패 메시지가 나온다.

체크리스트

  • Dockerfile이 특정 버전 JAR 이름에 의존하지 않는다.
  • 최종 실행 명령이 java $JVM_OPTS -jar app.jar처럼 단순하다.
  • 앱의 컨테이너 내부 포트는 80으로 맞춰져 있다.
  • Compose의 앱 DB URL은 localhost가 아니라 db 서비스 이름을 사용한다.
  • 이미지 빌드 실패와 컨테이너 실행 실패를 로그로 구분할 수 있다.

이 단계까지 끝나면 앱 컨테이너는 "어떤 JAR을 실행할지"와 "어디 DB에 붙을지"가 명확해진다.