Contents
see ListDocker Compose v2는 Docker CLI에 통합되어 docker compose 명령으로 사용할 수 있으며, 기존 v1 대비 성능과 기능이 크게 향상되었다. 이 글에서는 실제 웹 애플리케이션 개발에서 Docker Compose를 활용하는 방법을 상세히 다룬다.
기본 구성
Spring Boot + PostgreSQL + Redis + Nginx 스택을 예제로 사용한다.
# docker-compose.yml
services:
# Spring Boot 애플리케이션
app:
build:
context: .
dockerfile: Dockerfile
args:
JAVA_VERSION: 21
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/myapp
SPRING_DATASOURCE_USERNAME: myuser
SPRING_DATASOURCE_PASSWORD: mypassword
SPRING_DATA_REDIS_HOST: redis
SPRING_PROFILES_ACTIVE: docker
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./logs:/app/logs
networks:
- backend
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"
# PostgreSQL
db:
image: postgres:17-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d # 초기화 SQL
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# Redis
redis:
image: redis:7-alpine
command: redis-server --requirepass redispass --maxmemory 256mb --maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "redispass", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# Nginx 리버스 프록시
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
depends_on:
- app
networks:
- backend
volumes:
postgres_data:
driver: local
redis_data:
driver: local
networks:
backend:
driver: bridge
멀티 스테이지 Dockerfile
# Dockerfile
# 빌드 스테이지
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /build
# Gradle 캐시 레이어
COPY gradle/ gradle/
COPY gradlew build.gradle.kts settings.gradle.kts ./
RUN ./gradlew dependencies --no-daemon || true
# 소스 복사 및 빌드
COPY src/ src/
RUN ./gradlew bootJar --no-daemon -x test
# 실행 스테이지
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
# 보안: non-root 사용자로 실행
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /build/build/libs/*.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
EXPOSE 8080
# JVM 최적화 옵션
ENTRYPOINT ["java", \
"-XX:+UseZGC", \
"-XX:MaxRAMPercentage=75.0", \
"-XX:+UseStringDeduplication", \
"-jar", "app.jar"]
환경별 설정 분리
# docker-compose.override.yml (개발용, 자동 로드)
services:
app:
build:
target: builder # 빌드 스테이지에서 멈춤 (핫 리로드용)
volumes:
- ./src:/build/src # 소스 마운트 (핫 리로드)
environment:
SPRING_PROFILES_ACTIVE: dev
SPRING_DEVTOOLS_RESTART_ENABLED: "true"
ports:
- "5005:5005" # 디버그 포트
command: ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "app.jar"]
# 개발용 DB 관리 도구
adminer:
image: adminer
ports:
- "8081:8080"
depends_on:
- db
networks:
- backend
# docker-compose.prod.yml (프로덕션)
services:
app:
restart: always
environment:
SPRING_PROFILES_ACTIVE: prod
JAVA_OPTS: "-XX:+UseZGC -XX:MaxRAMPercentage=75.0"
deploy:
replicas: 2 # 2개 인스턴스
resources:
limits:
memory: 1G
cpus: "2.0"
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
db:
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
주요 명령어
# 개발 환경 실행
docker compose up -d
# 프로덕션 환경 실행
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
# 특정 서비스만 빌드 및 재시작
docker compose up -d --build app
# 로그 확인
docker compose logs -f app # 앱 로그
docker compose logs -f --tail 100 # 최근 100줄
# 서비스 상태 확인
docker compose ps
# 컨테이너 내부 접속
docker compose exec db psql -U myuser -d myapp
docker compose exec redis redis-cli -a redispass
docker compose exec app sh
# 스케일링
docker compose up -d --scale app=3
# 전체 중지 및 정리
docker compose down # 컨테이너만 제거
docker compose down -v # 볼륨도 제거
docker compose down --rmi all # 이미지도 제거
# 사용하지 않는 리소스 정리
docker system prune -a --volumes
Watch 모드 (개발 핫 리로드)
# docker-compose.yml
services:
frontend:
build: ./frontend
develop:
watch:
# 소스 변경 시 자동 동기화
- action: sync
path: ./frontend/src
target: /app/src
# package.json 변경 시 재빌드
- action: rebuild
path: ./frontend/package.json
# 설정 파일 변경 시 재시작
- action: sync+restart
path: ./frontend/vite.config.ts
target: /app/vite.config.ts
# Watch 모드로 실행
docker compose watch
# 파일 저장하면 자동으로 컨테이너에 반영
헬스체크와 의존성 관리
# 정교한 헬스체크
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s # 앱 시작 대기 시간
depends_on:
db:
condition: service_healthy # DB 헬스체크 통과 후 시작
restart: true # DB 재시작 시 앱도 재시작
redis:
condition: service_healthy
네트워크 분리
services:
nginx:
networks:
- frontend # 외부 노출 네트워크
- backend # 내부 통신 네트워크
app:
networks:
- backend # 내부만
db:
networks:
- backend # 내부만 (외부 접근 차단)
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 외부 접근 불가
.dockerignore 설정
# .dockerignore
.git
.gitignore
node_modules
*.md
.env
.env.*
docker-compose*.yml
Dockerfile*
.idea
.vscode
build/
target/
logs/
tmp/
Docker Compose v2는 개발 환경 구축부터 프로덕션 배포까지 멀티 컨테이너 애플리케이션을 효율적으로 관리하는 핵심 도구다. 환경별 설정 파일 분리, 헬스체크, 네트워크 분리, Watch 모드를 적절히 활용하면 안정적이고 생산적인 개발 환경을 구축할 수 있다.