현대 애플리케이션은 단일 서비스로만 구성되는 경우가 드뭅니다. 대부분 웹 서버, 데이터베이스, 캐시 서버 등 여러 컴포넌트가 함께 동작하여 완전한 시스템을 구성합니다. 개발 과정에서 이런 복잡한 환경을 매번 수동으로 설정하는 것은 매우 비효율적입니다. Docker Compose는 이런 문제를 해결해주는 도구로, 여러 컨테이너를 하나의 설정 파일로 관리할 수 있게 해줍니다.
Docker Compose의 필요성
다중 컨테이너 관리의 복잡성
실제 웹 애플리케이션을 개발할 때를 생각해보겠습니다. Spring Boot로 개발한 백엔드 서버가 있고, MySQL 데이터베이스가 필요하며, 성능 향상을 위해 Redis 캐시 서버도 함께 사용한다고 가정해보겠습니다.
Docker 없이 이런 환경을 구성한다면 각각의 서비스를 개별적으로 설치하고 설정해야 합니다. Docker를 사용하더라도 각 컨테이너를 따로 실행하고 네트워크를 연결하는 것은 여전히 번거로운 작업입니다.
Docker Compose가 제공하는 해결책
Docker Compose는 YAML 파일 하나로 여러 컨테이너의 설정을 정의하고, 단일 명령어로 전체 시스템을 실행할 수 있게 해줍니다.
기본 다중 컨테이너 실습
MySQL과 Redis 동시 실행하기
가장 간단한 예제부터 시작해보겠습니다. MySQL 데이터베이스와 Redis 캐시 서버를 동시에 실행하는 설정을 작성해보겠습니다.
프로젝트 루트 디렉토리에 compose.yml 파일을 생성합니다.
services:
my-db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: pwd1234
volumes:
- ./mysql_data:/var/lib/mysql
ports:
- 3306:3306
my-cache-server:
image: redis
ports:
- 6379:6379
이 설정 파일은 두 개의 서비스를 정의합니다. my-db는 MySQL 컨테이너를, my-cache-server는 Redis 컨테이너를 나타냅니다. 각 서비스는 독립적인 설정을 가지며, Docker Compose가 이들을 하나의 네트워크로 연결해줍니다.
실행은 매우 간단합니다.
docker compose up -d
단 한 줄의 명령어로 두 컨테이너가 동시에 실행되며, 실행 상태는 다음 명령어로 확인할 수 있습니다.
docker compose ps
작업이 끝나면 모든 컨테이너를 한 번에 정리할 수 있습니다.
docker compose down
Spring Boot 애플리케이션과 데이터베이스 연동
설정 파일 준비
이제 실제 애플리케이션을 포함한 더 복잡한 시나리오를 다뤄보겠습니다. Spring Boot 애플리케이션이 MySQL 데이터베이스와 연동하는 환경을 구성해보겠습니다.
먼저 Spring Boot 프로젝트의 application.yml 파일을 작성합니다.
spring:
datasource:
url: jdbc:mysql://my-db:3306/mydb
username: root
password: pwd1234
driver-class-name: com.mysql.cj.jdbc.Driver
여기서 주목할 점은 URL에서 localhost 대신 my-db를 사용한다는 것입니다. 이는 Docker Compose의 서비스명을 통해 컨테이너 간 통신하는 방식입니다.
Dockerfile 작성
Spring Boot 애플리케이션을 컨테이너화하기 위한 Dockerfile을 작성합니다.
FROM openjdk:17-jdk
COPY build/libs/*SNAPSHOT.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
Compose 설정
이제 Spring Boot와 MySQL을 함께 실행하는 compose.yml 파일을 작성합니다.
services:
my-server:
build: .
ports:
- 8080:8080
depends_on:
my-db:
condition: service_healthy
my-db:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: pwd1234
MYSQL_DATABASE: mydb
volumes:
- ./mysql_data:/var/lib/mysql
ports:
- 3306:3306
healthcheck:
test: ["CMD", "mysqladmin", "ping"]
interval: 5s
retries: 10
이 설정에서 중요한 부분들을 살펴보겠습니다.
depends_on과 healthcheck는 서비스 간의 의존성과 실행 순서를 관리합니다. MySQL이 완전히 초기화되기 전에 Spring Boot가 실행되면 데이터베이스 연결 오류가 발생할 수 있습니다. healthcheck를 통해 MySQL이 준비된 상태인지 확인하고, depends_on으로 이 조건이 만족될 때까지 Spring Boot 컨테이너의 실행을 지연시킵니다.
MYSQL_DATABASE 환경변수는 MySQL 컨테이너 초기 실행 시 자동으로 mydb 데이터베이스를 생성해줍니다.
빌드와 실행
프로젝트를 빌드하고 전체 시스템을 실행합니다.
./gradlew clean build
docker compose up -d --build
--build 옵션은 Docker 이미지를 새로 빌드하도록 강제하는 옵션으로, 코드가 변경되었을 때 유용합니다.
컨테이너 네트워킹의 이해
localhost의 함정
Spring Boot 애플리케이션을 컨테이너로 실행할 때 가장 자주 발생하는 문제는 네트워킹 관련 이슈입니다.
전통적인 개발 환경에서는 모든 서비스가 같은 컴퓨터에서 실행되므로 localhost로 서로 통신할 수 있었습니다. 하지만 컨테이너 환경에서는 각 컨테이너가 자신만의 네트워크망과 IP 주소를 가집니다.
Spring Boot 컨테이너 입장에서 localhost:3306은 Spring Boot 컨테이너 내부의 3306번 포트를 의미합니다. MySQL은 별도의 컨테이너에서 실행되고 있으므로, 이 주소로는 MySQL에 접근할 수 없습니다.

서비스명을 통한 통신
Docker Compose는 이 문제를 해결하기 위해 서비스명을 DNS로 사용할 수 있게 해줍니다. compose.yml에서 정의한 서비스명 my-db가 곧 해당 컨테이너의 네트워크 주소가 됩니다.
따라서 application.yml에서 데이터베이스 URL을 다음과 같이 설정해야 합니다.
spring:
datasource:
url: jdbc:mysql://my-db:3306/mydb
이렇게 하면 Spring Boot는 Docker Compose 네트워크를 통해 MySQL 컨테이너에 정확히 연결할 수 있습니다.
다중 서비스 애플리케이션
Redis 캐시 서버 추가
이제 Spring Boot, MySQL, Redis가 모두 함께 동작하는 완전한 시스템을 구축해보겠습니다. 먼저 Spring Boot 프로젝트에 Redis 의존성을 추가합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// 기타 의존성들...
}
Redis 설정
Redis 연결을 위한 설정 클래스를 작성합니다.
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
간단한 컨트롤러도 추가하여 Redis 연결을 테스트해보겠습니다.
@RestController
public class AppController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@GetMapping("/")
public String home() {
redisTemplate.opsForValue().set("test-key", "Hello Redis!");
return "Application is running with Redis cache!";
}
}
application.yml 설정
모든 서비스에 대한 설정을 포함한 application.yml을 작성합니다.
spring:
datasource:
url: jdbc:mysql://my-db:3306/mydb
username: root
password: pwd1234
driver-class-name: com.mysql.cj.jdbc.Driver
data:
redis:
host: my-cache-server
port: 6379
여기서도 Redis 호스트를 localhost가 아닌 my-cache-server로 설정했습니다. 이는 앞서 설명한 컨테이너 네트워킹 원리와 동일합니다.
Compose 설정
세 개의 서비스가 모두 포함된 완전한 compose.yml 파일입니다.
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: pwd1234
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
Spring Boot 서비스가 MySQL과 Redis 모두가 준비될 때까지 기다리도록 depends_on 설정을 확장했습니다. Redis에도 healthcheck를 추가하여 서비스가 완전히 준비된 상태에서만 다음 단계로 진행하도록 했습니다.
시스템 실행과 검증
전체 시스템을 빌드하고 실행합니다.
./gradlew clean build
docker compose down
docker compose up --build -d
모든 서비스가 정상적으로 실행되면 브라우저에서 http://localhost:8080에 접속하여 애플리케이션이 정상 동작하는지 확인할 수 있습니다.
실행 상태는 다음 명령어로 모니터링할 수 있습니다.
docker compose ps
docker logs [컨테이너_ID]

마무리
Docker Compose는 복잡한 다중 컨테이너 환경을 단순하게 관리할 수 있게 해주는 필수 도구입니다. 서비스 간의 의존성 관리, 네트워크 설정, 헬스체크 등의 기능을 통해 안정적인 개발 환경을 구축할 수 있습니다.
'Infra > Docker' 카테고리의 다른 글
| AWS EC2에서 Docker를 활용한 배포 (6) | 2025.06.22 |
|---|---|
| AWS EC2에 서버 배포 (2) | 2025.06.18 |
| Docker Compose 1 (7) | 2025.06.16 |
| Dockerfile (3) | 2025.06.13 |
| Docker Volume (4) | 2025.06.09 |