데이터 엔지니어링/Docker

5. Docker Compose 이해

427paul 2026. 5. 28. 22:06

1. 도커 컴포즈(Docker Compose)의 핵심 철학

현대적인 웹 서비스는 웹 서버, API, 데이터베이스, 캐시 등 여러 컨테이너가 유기적으로 움직입니다. Docker Compose는 이를 일일이 docker run으로 띄우는 불편함을 해결하기 위해 탄생한 "다중 컨테이너 통합 관리 도구"입니다.

  • 핵심 가치: docker-compose.yml이라는 정의서 한 장으로 복잡한 다중 인프라를 선언적으로 구축
  • 궁극의 이점:
    • 주렁주렁 달린 환경 변수와 볼륨 설정을 단 하나의 파일로 규격화
    • 명령어 한 줄로 인프라 전체의 생성 및 완전 폭파(수명 주기)를 제어
    • 환경별(.env 변수 파일 연동) 설정을 분리하여 관리 효율성을 극대화

2. docker-compose.yml 구조 및 작성 예시

설정 파일은 크게 services(컨테이너 정의), networks(통신망), volumes(저장소) 3대 섹션으로 구성

version: '3.8' # 파일 규격 버전 (최근에는 생략 가능)

services:      # 1. 실행할 컨테이너들의 정의
  web-app:
    build: .   # 현재 디렉토리의 Dockerfile을 빌드
    ports:
      - "8080:80"
    depends_on:
      - db     # db 서비스가 먼저 실행된 후 시작됨
    environment:
      - DB_HOST=db

  db:
    image: postgres:15
    volumes:
      - db-data:/var/lib/postgresql/data # 2. 데이터 영속성을 위한 볼륨

networks:      # 3. 컨테이너 간 통신을 위한 네트워크 (자동 생성됨)
  default:

volumes:       # 물리적인 저장소 공간 정의
  db-data:

💻 웹 App + MySQL + Redis 3티어 통합 관리 예시

docker-compose.yml

version: '3.8'
services:
  # 1. 웹 애플리케이션 서비스
  web-app:
    build: .                 # 현재 경로의 Dockerfile을 읽어 이미지 빌드
    ports:
      - "8080:8080"          # 호스트 8080 포트 ➔ 컨테이너 8080 포트 포워딩
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql-db:3306/mydb # 서비스 이름 사용 ⭐
      - SPRING_REDIS_HOST=redis-cache
    depends_on:              # 2. 실행 의존성 순서 정의 (DB, 캐시 선행)
      - mysql-db
      - redis-cache

  # 2. 데이터베이스 서비스
  mysql-db:
    image: mysql:8.0
    environment:
      - MYSQL_DATABASE=mydb
      - MYSQL_ROOT_PASSWORD=secretpass
    volumes:
      - mysql-data:/var/lib/mysql # 3. 데이터 보존을 위한 볼륨 바인딩

  # 3. 인메모리 캐시 서비스
  redis-cache:
    image: redis:7.0-alpine

# 영구 저장 공간 정의
volumes:
  mysql-data:

3. 💡 도커 컴포즈의 핵심 메커니즘 (동작 원리)

① 서비스 이름 기반 내부 통신 (Service Discovery)

도커 컴포즈는 가동 시 프로젝트 전용 격리 네트워크(기본 브리지)를 자동 생성합니다. 이 망 내부에서 컨테이너들은 수시로 변하는 사설 IP 대신, YAML 파일에 정의한 '서비스 이름'(예: mysql-db, redis-cache)을 호스트명(도메인)처럼 사용해 서로를 즉시 찾아 통신할 수 있습니다.

② depends_on을 통한 가동 순서 보장

depends_on을 명시하면 컴포즈 엔진이 선행 컨테이너를 먼저 부팅한 후 후행 애플리케이션 컨테이너를 구동하므로, DB가 켜지기도 전에 웹 앱이 실행되어 커넥션 에러로 뻗는 대참사를 방지합니다.

  • 실무 팁: 이는 컨테이너의 부팅 순서만 보장할 뿐, 내부 DB 엔진의 완벽한 쿼리 준비 상태까지 보장하진 않으므로 코드 내 재시도(Retry) 로직을 포함하는 것이 정석

4. [실습] Flask 웹 + Redis 멀티 컨테이너 배포 및 관리

새로고침할 때마다 Redis에 방문 횟수(Count)가 누적되는 시스템을 구축하고 한 번에 청소하는 실무 파이프라인입니다.

📄 1) 데이터 및 아키텍처 명세 준비

  • app.py: 호스트 주소를 redis-db라는 컴포즈 서비스명으로 바라보도록 설정한 Flask 코드
import time
import redis
from flask import Flask

app = Flask(__name__)

# Redis 컨테이너 서비스 이름으로 연결
cache = redis.Redis(host='redis-db', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

# [@app.index_string] 라인을 삭제하고 바로 라우팅 데코레이터만 남깁니다.
@app.route('/')
def hello():
    count = get_hit_count()
    return f'<h1>Docker Compose 실습 성공!</h1><p>방문자 수: {count}번째 보았습니다.</p>\\n'

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=5000)

  • requirements.txt: 파이썬 의존성 패키지(flask, redis) 명세
flask
redis
  • Dockerfile: 패키지 설치 및 소스 코드를 복사하여 웹 서버를 가동하는 정석 레시피
FROM python:3.9-slim
WORKDIR /code
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
  • docker-compose.yml: web-server는 현재 경로(.) 기반 빌드 및 8080 포트 포워딩을 지정하고, redis-db 서비스는 공인 redis:alpine 이미지로 실행되도록 직관적으로 설계
services:
  web-server:
    build: .
    ports:
      - "8080:5000"
    depends_on:
      - redis-db

  redis-db:
    image: "redis:alpine"

🖥️ 2) 생명 주기 제어 및 청소 명령어 순서

  1. 인프라 통합 가동 (Up): 단 한 줄의 명령으로 이미지를 다운로드 및 빌드하고, 네트워크를 묶어 백그라운드(d)로 일괄 실행
    docker-compose up -d
    ​
  2. 상태 검증: 서비스 레이아웃 상태를 파악(docker-compose ps)한 뒤 브라우저에서 http://localhost:8080에 접속하여 카운트가 정상 누적되는지 확인
    # 컴포즈로 가동 중인 컨테이너 레이아웃 확인
    docker-compose ps
    ​
  3. 인프라 완전 폭파 (Down): 실습 완료 후 시스템 리소스 반납을 위해 구동 중인 모든 컨테이너를 안전 정지·삭제하고, 가상 네트워크 인터페이스까지 흔적 없이 일괄 삭제
    docker-compose down
    
  4. 하드디스크 최종 청소: 생성된 웹 이미지 원본 및 레디스 베이스 이미지 조각까지 완벽히 소거하여 PC를 태초의 상태로 되돌림
    docker rmi flask-compose-demo-web-server:latest 
    docker rmi redis:alpine
    ​

🛠️ 도커 컴포즈 핵심 명령어 & 실무 팁

핵심 명령어 주요 역할 및 동작 의미

docker-compose up -d 명세서 기반 이미지 빌드/다운로드, 네트워크 생성 및 전체 서비스 백그라운드 일괄 가동
docker-compose ps 현재 도커 컴포즈 아키텍처 내에서 살아 움직이는 서비스 목록 및 상태 확인
docker-compose logs -f 묶여 있는 다중 컨테이너들의 출력을 통합하여 실시간 통합 로그 확인
docker-compose down 가동 중인 컨테이너들을 정지·삭제하고 자동 생성되었던 가상 네트워크망까지 클린 소거
  • 실무 활용 팁 (볼륨 매핑 활용): 개발 환경(Local) 구축 시, 소스 코드가 바뀔 때마다 docker-compose up을 매번 새로 빌드하는 것은 비효율적입니다. 명세서에 volumes 옵션을 주어 호스트의 소스 폴더와 컨테이너 내부 경로를 마운트(동기화)해두면, 로컬에서 코드를 수정하는 즉시 가동 중인 컨테이너에 실시간 반영되어 매우 효율적인 개발 피드백 루프를 만들 수 있습니다.

🔥 최종 개념 요약

  • Dockerfile로 시스템을 구성할 개별 컴포넌트(클래스)를 빌드하고,
  • docker-compose.yml로 그 컴포넌트들이 얽혀 있는 인프라 관계(시스템 구조)를 선언적으로 정의하며,
  • docker-compose up 구문 한 줄로 전체 소프트웨어 스택(애플리케이션 시스템)을 통합 제어