Chapter 4

도커 컴포즈

  • 4.1 docker-compose.yml 파일
  • 4.2 도커 컴포즈 기본 사용법
  • 4.3 도커 컴포즈 활용

웹 서버 + DB + 캐시처럼 여러 컨테이너가 필요한 환경을 매번 docker run으로 하나씩 띄우는 건 비현실적이잖아. 도커 컴포즈는 이 문제를 YAML 파일 하나로 해결해.

핵심은 docker-compose.yml(또는 compose.yml) 파일이야. 이 파일에 애플리케이션을 구성하는 모든 서비스, 네트워크, 볼륨을 선언적으로 정의하거든:

version: "3.8"

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    depends_on:
      - app
    networks:
      - frontend

  app:
    build: ./app
    environment:
      - DB_HOST=db
      - DB_PORT=3306
    depends_on:
      - db
    networks:
      - frontend
      - backend

  db:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=secret
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - backend

volumes:
  db-data:

networks:
  frontend:
  backend:

주요 설정 항목들을 보면 — image는 사용할 이미지고, build는 Dockerfile로 직접 빌드할 경로야. imagebuild를 동시에 쓸 수도 있어. ports는 포트 매핑이고 docker run -p와 같지. environment는 환경 변수 설정인데 .env 파일을 참조하는 것도 가능해. volumes는 데이터 영속성을 위한 볼륨 마운트고, networks는 서비스가 참여할 네트워크야. 같은 네트워크에 있는 서비스끼리만 통신 가능하지. 그리고 depends_on은 서비스 시작 순서를 지정하는 건데, 여기서 주의할 게 있어 — "시작 순서"일 뿐 "준비 완료"를 보장하지는 않아. DB가 시작됐지만 아직 커넥션을 받을 준비가 안 된 상태일 수 있거든. version 필드는 Compose 파일 포맷 버전을 지정하는데, Docker Compose V2부터는 사실상 선택사항이야.

기본 사용법은 간단해:

docker compose up        # 포그라운드 실행
docker compose up -d     # 백그라운드 실행
docker compose up --build  # 이미지 다시 빌드 후 실행

docker compose up은 YAML에 정의된 모든 서비스를 한 번에 생성하고 시작해. 이미지가 없으면 자동으로 빌드하거나 pull 하지.

docker compose stop      # 서비스 중지 (컨테이너 유지)
docker compose down      # 서비스 중지 + 컨테이너/네트워크 삭제
docker compose down -v   # 볼륨까지 삭제
docker compose ps        # 서비스 상태 확인
docker compose logs      # 전체 로그
docker compose logs -f web  # 특정 서비스 실시간 로그
docker compose run app bash    # app 서비스로 일회성 명령 실행
docker compose exec app bash   # 실행 중인 app 서비스에 접속

run은 새 컨테이너를 만들고, exec은 기존 컨테이너에 접속하는 차이가 있어. 참고로 docker-compose(하이픈)은 V1이고 별도 설치가 필요했어. docker compose(공백)은 V2로 도커에 내장되어 있지. 지금은 V2가 표준이야.

활용 쪽으로 가면, 환경 변수를 .env 파일로 분리할 수 있어:

# .env
DB_PASSWORD=my-secret-pw
services:
  db:
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD}

env_file 항목으로 별도의 환경 변수 파일을 지정할 수도 있고, 프로덕션과 개발 환경에서 다른 .env 파일을 사용하면 환경별 설정을 깔끔하게 분리할 수 있지. 여러 Compose 파일을 조합하는 것도 가능해:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

기본 설정을 docker-compose.yml에, 환경별 오버라이드를 별도 파일에 정의하는 패턴이야. 개발 환경에서는 소스 코드를 볼륨으로 마운트하고, 프로덕션에서는 빌드된 이미지를 사용하는 식으로 분리할 수 있어.

스케일링도 간단해:

docker compose up -d --scale app=3

app 서비스를 3개로 늘리는 건데, 포트가 충돌하지 않도록 주의해야 해. 호스트 포트를 고정하면 스케일링이 안 되니까, 로드 밸런서를 앞에 두거나 포트를 동적으로 할당해야 하지.

그리고 헬스 체크도 중요해:

services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

depends_on만으로는 서비스가 "준비"됐는지 알 수 없으니까, 헬스 체크를 설정하면 서비스의 실제 상태를 확인할 수 있어.


정리

4장 읽고 기억할 거 세 가지:

  1. docker-compose.yml 하나로 멀티 컨테이너 환경을 정의한다. 서비스, 네트워크, 볼륨을 선언적으로 관리.
  2. docker compose up -d로 시작하고 docker compose down으로 정리한다. 환경 변수는 .env로 분리하고, 여러 Compose 파일로 환경별 설정을 오버라이드할 수 있다.
  3. depends_on은 시작 순서만 보장하지, 준비 완료를 보장하지 않는다. 서비스의 실제 준비 상태를 확인하려면 헬스 체크를 설정해야 한다.