Docker 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 모드를 적절히 활용하면 안정적이고 생산적인 개발 환경을 구축할 수 있다.