Issue: 도커 컨테이너 간 DB 접속 불가 (Connection Refused)
- 현상: 로컬 실행 시에는 .env의 DB_HOST=localhost 설정으로 정상 작동하지만, 도커 컨테이너 배포 시 애플리케이션이 DB를 찾지 못하고 연결 실패.
- 원인: 도커 컨테이너는 독립된 네트워크를 가짐. .env에 정의된 localhost는 내 컴퓨터(호스트)가 아닌 애플리케이션 컨테이너 자신을 가리키기 때문에 별도 컨테이너로 떠 있는 DB에 접근할 수 없음.
- 해결책: Docker Compose 서비스 이름을 활용한 환경 변수 오버라이딩 코드(application.yml)는 유연성을 위해 ${DB_HOST} 변수 형태를 유지하되, docker-compose.yml 에서 해당 변수의 값을 도커 전용 호스트 이름인 db로 주입하여 소스 코드 수정 없이 환경 간 차이를 해결함.
개선 전
호스트의 포트 포워딩에 의존하거나 로컬 환경의 localhost를 그대로 사용하여 컨테이너 환경에서 접속 실패.
# application.yml
spring:
datasource:
url:jdbc:mysql://localhost:3306/rarego# 에러 발생: 컨테이너 내부에는 DB가 없음
개선 후
도커 엔진의 내부 DNS 기능을 활용하여 서비스 이름으로 통신. 환경 변화에 유연하게 대응 가능.
# docker-compose.yml
SPRING_DATASOURCE_URL:jdbc:mysql://db:3306/${DB_NAME}?useSSL=false&serverTimezone=Asia/Seoul
Issue: 도커 이미지 용량 비대화 및 빌드 속도 저하
- 현상: 단순한 자바 실행 환경임에도 불구하고 Gradle 빌드 도구와 빌드 리소스가 모두 포함되어 도커 이미지 용량이 1GB를 초과하고, 소스 수정 시마다 처음부터 의존성을 다운로드하여 빌드 시간이 매우 길어짐.
- 원인: 단일 스테이지 빌드 방식의 한계. 소스 코드 빌드에 필요한 JDK와 빌드된 Jar만 있으면 되는 실행 환경이 분리되지 않아 불필요한 레이어가 누적됨.
- 해결책: 멀티 스테이지 빌드(Multi-stage Build) 적용 및 레이어 캐싱 최적화 빌드 단계(Build Stage)와 실행 단계(Run Stage)를 분리함. 빌드 단계에서 생성된 Jar 파일만 가벼운 JRE 이미지로 복사하여 최종 이미지 크기를 획기적으로 줄이고, 의존성 설치 레이어를 별도로 분리하여 캐싱 효율을 극대화함.
개선 전
JDK 전체가 포함된 무거운 이미지 사용. 빌드 시마다 모든 라이브러리를 새로 다운로드.
FROM eclipse-temurin:21-jdk
COPY . .
RUN ./gradlew build
ENTRYPOINT ["java","-jar","build/libs/app.jar"]
개선 후