Docker Compose YAML 파일 내부 구조

전체 구조 개요

version: '3.8'                    # Compose 파일 포맷 버전

# 최상위 섹션들
services:                         # 컨테이너 서비스 정의 (필수)
  service_name:
    # 서비스 설정

volumes:                          # 볼륨 정의 (선택)
  volume_name:
    # 볼륨 설정

networks:                         # 네트워크 정의 (선택)
  network_name:
    # 네트워크 설정

configs:                          # 설정 파일 정의 (선택)
  config_name:
    # 설정 파일

secrets:                          # 시크릿 정의 (선택)
  secret_name:
    # 시크릿 설정

# YAML 확장 기능
x-custom:                         # 커스텀 확장 (재사용)
  &anchor: value

include:                          # 다른 파일 포함 (Compose 2.20+)
  - path/to/other.yml

1. version (버전 지정)

version: '3.8'    # 권장 버전
# version: '3.9'  # 최신 기능 사용시
# version: '2.4'  # 레거시 지원

주요 버전:

  • 3.8: 가장 널리 사용, 안정적
  • 3.9: 최신 기능 포함
  • 2.x: 레거시 (비추천)

2. services (서비스 정의) - 핵심!

2-1. 기본 서비스 구조

services:
  service_name:                   # 서비스 이름 (자유롭게 정의)
    # 이미지 관련
    image: nginx:latest           # Docker Hub 이미지
    build:                        # 또는 Dockerfile로 빌드
      context: .
      dockerfile: Dockerfile
    
    # 컨테이너 설정
    container_name: my-nginx      # 컨테이너 이름
    hostname: web-server          # 호스트명
    
    # 포트 매핑
    ports:
      - "80:80"                   # 호스트:컨테이너
      - "443:443"
      
    # 볼륨 마운트
    volumes:
      - ./data:/app/data          # Bind mount
      - app_data:/app/storage     # Named volume
      
    # 환경변수
    environment:
      - NODE_ENV=production
      - API_KEY=secret
    env_file:
      - .env
      
    # 네트워크
    networks:
      - frontend
      - backend
      
    # 의존성
    depends_on:
      - database
      - redis
      
    # 재시작 정책
    restart: unless-stopped
    
    # 실행 명령어
    command: npm start
    entrypoint: /docker-entrypoint.sh
    
    # 작업 디렉토리
    working_dir: /app
    
    # 사용자
    user: "1000:1000"
    
    # 리소스 제한
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "0.5"
    
    # 헬스체크
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      
    # 기타
    labels:
      - "com.example.description=Web server"
    privileged: false
    stdin_open: true              # -i 옵션
    tty: true                     # -t 옵션

2-2. 이미지 관련 옵션

services:
  # 방법 1: 기존 이미지 사용
  app1:
    image: nginx:1.21-alpine      # 이미지:태그
    
  # 방법 2: Dockerfile로 빌드
  app2:
    build: .                      # 현재 디렉토리의 Dockerfile
    
  # 방법 3: 상세 빌드 설정
  app3:
    build:
      context: ./app              # 빌드 컨텍스트
      dockerfile: Dockerfile.prod # Dockerfile 경로
      target: production          # 멀티스테이지 빌드 타겟
      args:                       # 빌드 인수
        - NODE_ENV=production
        - VERSION=1.0.0
      cache_from:                 # 캐시 소스
        - alpine:latest
      labels:                     # 이미지 라벨
        version: "1.0"

2-3. 포트 매핑 옵션

services:
  web:
    ports:
      - "80:80"                   # 호스트:컨테이너
      - "127.0.0.1:8080:80"      # IP:호스트포트:컨테이너포트
      - "3000"                    # 컨테이너 포트만 (랜덤 호스트 포트)
      - "3000-3005:3000-3005"    # 포트 범위
      
    expose:                       # 다른 서비스에만 노출 (호스트 노출 안함)
      - "8080"
      - "9000"

2-4. 볼륨 마운트 옵션

services:
  app:
    volumes:
      # Bind Mount
      - ./data:/app/data          # 호스트경로:컨테이너경로
      - ./config:/app/config:ro   # 읽기 전용
      - ${HOME}/logs:/app/logs    # 환경변수 사용
      
      # Named Volume
      - app_data:/app/data        # 볼륨명:컨테이너경로
      - app_cache:/app/cache:rw   # 읽기/쓰기 (기본값)
      
      # Anonymous Volume
      - /app/node_modules         # 컨테이너 경로만
      
      # tmpfs (메모리)
      - type: tmpfs
        target: /app/tmp
        tmpfs:
          size: 100M
          
      # 상세 마운트 설정
      - type: bind
        source: ./data
        target: /app/data
        read_only: true

2-5. 환경변수 설정

services:
  app:
    environment:
      # 방법 1: 키=값
      - NODE_ENV=production
      - DEBUG=true
      - PORT=3000
      
      # 방법 2: 맵 형태
      NODE_ENV: production
      DEBUG: "true"               # YAML에서 문자열로 처리
      API_URL: "https://api.example.com"
      
    env_file:                     # 환경변수 파일
      - .env                      # 기본 파일
      - .env.local               # 추가 파일
      - ./config/app.env         # 경로 지정

2-6. 네트워크 설정

services:
  web:
    networks:
      - frontend                  # 네트워크 이름만
      - backend
      
  api:
    networks:
      frontend:                   # 상세 설정
        aliases:
          - api-server
        ipv4_address: 172.20.0.5
      backend:
        priority: 1000

2-7. 의존성 관리

services:
  web:
    depends_on:
      - database                  # 기본 의존성
      - redis
      
  api:
    depends_on:                   # 상세 의존성 (Compose 3.8+)
      database:
        condition: service_healthy
      redis:
        condition: service_started
        restart: true

2-8. 헬스체크

services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s               # 검사 간격
      timeout: 10s                # 타임아웃
      retries: 3                  # 재시도 횟수
      start_period: 30s           # 시작 대기 시간
      
  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      
  app:
    healthcheck:
      disable: true               # 헬스체크 비활성화

2-9. 리소스 제한

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '0.50'            # CPU 제한
          memory: 512M            # 메모리 제한
        reservations:
          cpus: '0.25'            # CPU 예약
          memory: 256M            # 메모리 예약
          
    # 또는 간단한 메모리 제한
    mem_limit: 512m
    memswap_limit: 1g
    
    # CPU 제한
    cpus: 0.5
    cpu_shares: 512

2-10. 프로파일 사용

services:
  # 항상 실행되는 서비스
  app:
    image: myapp:latest
    
  # 개발환경에서만 실행
  redis:
    profiles: ["dev", "test"]
    image: redis:6
    
  # 모니터링 프로파일
  prometheus:
    profiles: ["monitoring"]
    image: prom/prometheus
    
  grafana:
    profiles: ["monitoring"]
    image: grafana/grafana

3. volumes (볼륨 정의)

volumes:
  # 기본 Named Volume
  app_data:
  
  # 상세 설정
  postgres_data:
    driver: local               # 볼륨 드라이버
    driver_opts:
      type: none
      o: bind
      device: /path/to/data
      
  # 외부 볼륨 (이미 존재하는 볼륨)
  existing_volume:
    external: true
    name: my-existing-volume
    
  # 라벨 추가
  app_cache:
    labels:
      - "com.example.description=Application cache"
      - "com.example.team=backend"

4. networks (네트워크 정의)

networks:
  # 기본 네트워크
  frontend:
  
  # 상세 설정
  backend:
    driver: bridge              # 네트워크 드라이버
    ipam:                       # IP 관리
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1
    driver_opts:
      com.docker.network.bridge.name: backend-bridge
      
  # 외부 네트워크 (이미 존재)
  existing_network:
    external: true
    name: my-existing-network
    
  # 호스트 네트워크
  host_network:
    external: true
    name: host

5. configs (설정 파일)

configs:
  # 파일에서 설정 로드
  nginx_config:
    file: ./nginx/nginx.conf
    
  # 외부 설정
  app_config:
    external: true
    name: production_config
    
services:
  web:
    configs:
      - source: nginx_config
        target: /etc/nginx/nginx.conf
        mode: 0644

6. secrets (시크릿)

secrets:
  # 파일에서 시크릿 로드
  db_password:
    file: ./secrets/db_password.txt
    
  # 외부 시크릿
  api_key:
    external: true
    name: production_api_key
    
services:
  app:
    secrets:
      - db_password
      - source: api_key
        target: /run/secrets/api_key
        mode: 0400

7. YAML 확장 기능

7-1. Anchors & Aliases (재사용)

# 공통 설정 정의
x-common-config: &common
  restart: unless-stopped
  networks:
    - app-network
  environment:
    - TZ=Asia/Seoul

x-database-config: &db-config
  <<: *common                     # 공통 설정 상속
  volumes:
    - db_data:/var/lib/postgresql/data
  environment:
    - POSTGRES_DB=myapp

services:
  web:
    <<: *common                   # 공통 설정 적용
    image: nginx
    
  db:
    <<: *db-config               # DB 설정 적용
    image: postgres:13

7-2. Extension Fields (확장 필드)

# x-로 시작하는 필드는 Docker에서 무시됨 (사용자 정의용)
x-logging: &default-logging
  driver: json-file
  options:
    max-size: 10m
    max-file: 3

x-healthcheck: &default-healthcheck
  interval: 30s
  timeout: 10s
  retries: 3

services:
  web:
    image: nginx
    logging: *default-logging
    healthcheck:
      <<: *default-healthcheck
      test: ["CMD", "nginx", "-t"]

8. 완전한 예시

version: '3.8'

# 재사용 가능한 설정들
x-common: &common-config
  restart: unless-stopped
  networks:
    - app-network
  environment:
    - TZ=Asia/Seoul
  logging:
    driver: json-file
    options:
      max-size: 10m
      max-file: 3

services:
  # 웹 서버
  nginx:
    <<: *common-config
    image: nginx:1.21-alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - static_files:/var/www/html
    depends_on:
      - app
    healthcheck:
      test: ["CMD", "nginx", "-t"]
      interval: 30s
      timeout: 10s
      retries: 3

  # 애플리케이션
  app:
    <<: *common-config
    build:
      context: .
      dockerfile: Dockerfile
      target: production
      args:
        - NODE_ENV=production
    container_name: node-app
    environment:
      - NODE_ENV=production
      - DB_HOST=postgres
      - REDIS_HOST=redis
    env_file:
      - .env
    volumes:
      - app_data:/app/data
      - static_files:/app/public
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s

  # 데이터베이스
  postgres:
    <<: *common-config
    image: postgres:13-alpine
    container_name: postgres-db
    environment:
      - POSTGRES_DB=${DB_NAME}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    ports:
      - "127.0.0.1:5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 5s
      timeout: 5s
      retries: 5

  # 캐시
  redis:
    <<: *common-config
    image: redis:6-alpine
    container_name: redis-cache
    volumes:
      - redis_data:/data
      - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
    command: redis-server /usr/local/etc/redis/redis.conf

  # 모니터링 (프로파일 사용)
  prometheus:
    profiles: ["monitoring"]
    <<: *common-config
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus

volumes:
  app_data:
    labels:
      - "com.example.description=Application data"
  postgres_data:
    driver: local
  redis_data:
  static_files:
  prometheus_data:
    external: true  # 외부에서 관리되는 볼륨

networks:
  app-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

configs:
  nginx_config:
    file: ./nginx/nginx.conf

secrets:
  db_password:
    file: ./secrets/db_password.txt

이것이 Docker Compose YAML 파일에서 정의할 수 있는 모든 구조와 옵션들입니다! 🚀

Docker 기본