
Docker Compose란?
Docker Compose는 여러 개의 컨테이너를 한 번에 정의하고 실행할 수 있는 도구입니다. docker-compose.yml 파일 하나로 여러 서비스를 정의할 수 있으며, 개발/테스트 환경에서 매우 유용합니다.
Compose 기본 구조
version: '3.8'
services:
서비스명:
image: 사용할 이미지
ports:
- "로컬포트:컨테이너포트"
environment:
- 환경변수=값
depends_on:
- 다른서비스
Spring Boot + MySQL 연결
Spring Boot 애플리케이션이 MySQL 데이터베이스에 접근하는 예제를 Compose로 구성해보겠습니다.
1. docker-compose.yml
version: '3.8'
services:
db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: root1234
MYSQL_DATABASE: mydb
ports:
- "3306:3306"
volumes:
- ./mysql_data:/var/lib/mysql
spring:
build: .
depends_on:
- db
ports:
- "8080:8080"
2. Spring Boot application.yml 또는 application.properties
spring:
datasource:
url: jdbc:mysql://db:3306/mydb
username: user
password: user1234
driver-class-name: com.mysql.cj.jdbc.Driver
여기서 핵심은 **DB 접속 주소가 localhost가 아닌 db**라는 점입니다. 이건 Compose에서 설정한 서비스명을 기반으로 내부 DNS가 연결되기 때문입니다.
연결이 안 되는 이유
❌ 잘못된 JDBC URL
# ❌ 이렇게 하면 안 됩니다 (로컬 DB 기준)
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
컨테이너 안에서 실행되는 애플리케이션은 localhost를 자기 자신으로 인식합니다. 그래서 localhost는 DB를 못 찾고, 반드시 Compose의 **서비스명(db)**을 사용해야 합니다.
❌ DB가 완전히 뜨기 전에 애플리케이션이 먼저 실행됨
Spring Boot 컨테이너가 MySQL이 완전히 시작되기 전에 실행될 경우 Connection refused, Communications link failure 등의 오류가 발생합니다.
해결 방법:
- depends_on 사용 (단, 순서만 보장하고, 준비 완료는 보장 안 함)
- Spring Boot에서 spring.datasource.initialization-mode=always와 retry 로직 추가
- wait-for-it.sh, dockerize, initContainers 등으로 DB 준비 확인
❌ Spring Boot가 MySQL에 연결을 시도하면서 다음과 같은 오류가 난다면?
com.mysql.cj.jdbc.exceptions.CommunicationsException:
Communications link failure
왜 실행 순서를 맞췄는데 실패할까?
➤ 답은 depends_on의 한계에 있습니다.
- depends_on은 컨테이너 시작 순서만 보장합니다.
- 서비스 준비 완료(=DB 접속 가능) 상태까지는 보장하지 않습니다.
즉, MySQL 컨테이너가 시작만 됐지,
3306 포트가 완전히 열리고, DB가 초기화되고, 사용자 계정 생성되고 … 이 모든 게 끝난 상태는 아닙니다.
그래서 Spring Boot가 너무 빨리 DB에 연결 시도하면,
아직 준비되지 않은 MySQL에 접근하게 되고 연결 실패가 발생합니다.
해결책: healthcheck + condition: service_healthy
🧩 Spring + MySQL + Redis 연결
services:
my-server:
build: .
ports:
- 8080:8080
depends_on:
my-db:
condition: service_healthy
my-cache-server:
condition: service_healthy
my-db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: password123
MYSQL_DATABASE: mydb
volumes:
- ./mysql_data:/var/lib/mysql
ports:
- 3306:3306
healthcheck:
test: [ "CMD", "mysqladmin", "ping"]
interval: 5s
retries: 10
my-cache-server:
image: redis
ports:
- 6379:6379
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 5s
retries: 10
이제는 DB가 진짜 접속 가능할 때까지 Spring 앱이 기다렸다가 실행됩니다.
항목 | 설명 |
depends_on | 컨테이너 시작 순서만 보장 |
healthcheck | 컨테이너의 정상 작동 상태 판단 |
condition: service_healthy | 의존 서비스가 완전히 준비될 때까지 실행 대기 |
Docker Compose로 실행하기
docker-compose up --build
// --build는 docker-compose up을 실행할 때, 명시적으로 이미지를 새로 빌드하도록 지시
컨테이너가 두 개 실행됩니다:
- spring-app: Spring Boot 애플리케이션
- mysql-db: MySQL 데이터베이스
접속 테스트
정상 연결되면 로그에 다음과 같은 메시지가 출력됩니다:
Connected to database: mydb
또는 애플리케이션에서 정상적으로 데이터 조회 및 저장이 이뤄질 수 있습니다.
프로젝트 구조 예시
myproject/
├── docker-compose.yml
├── Dockerfile
├── src/
└── build.gradle or pom.xml

문제 | 원인 | 해결 방법 |
DB 연결 오류 | JDBC URL에서 localhost 사용 | 서비스명 (db) 사용 |
Connection refused | DB가 준비되기 전에 Spring 실행 | depends_on + retry 로직 |
DB 접속 오류 | 환경변수 누락 또는 잘못된 비밀번호 | docker-compose.yml과 설정 파일 싱크 확인 |
📚 참고 자료
'Docker' 카테고리의 다른 글
도커(Docker) 이미지 직접 생성하기(Dockerfile) (1) | 2025.05.19 |
---|---|
도커 Dockerfile 이란?: FROM 명령어부터 시작 (3) | 2025.05.16 |
도커(Docker) 볼륨(Volumn): 데이터 유실 방지 (0) | 2025.05.15 |
도커(Docker) 명령어 및 포트 매핑 (2) | 2025.05.13 |
도커(Docker)와 컨테이너(Container) (1) | 2024.12.23 |