Docker Compose

YAML 하나로 다중 컨테이너 정의 및 관리


📚 시리즈 네비게이션

이전현재다음
Volume & NetworkDocker ComposeDocker vs Podman

시리즈 목차


🎯 Docker Compose란?

다중 컨테이너 애플리케이션을 정의하고 실행하는 도구.

docker run 여러 번                 vs              docker compose up
─────────────────────────────────────────────────────────────────────
docker network create mynet                       compose.yaml 하나로
docker run -d --name db ...                       전체 환경 정의
docker run -d --name app ...
docker run -d --name web ...

📦 설치

Docker Desktop에는 기본 포함. Linux 서버는 별도 설치.

# Docker Compose v2 (플러그인 방식)
# Docker 설치 시 함께 설치됨
 
# 확인
docker compose version
# Docker Compose version v2.x.x

Note: docker-compose (하이픈) → docker compose (스페이스)로 변경됨.


📝 compose.yaml 기본 구조

# compose.yaml (또는 docker-compose.yml)
 
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    
  app:
    build: ./app
    environment:
      - DB_HOST=db
    depends_on:
      - db
    
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: secret
    volumes:
      - db-data:/var/lib/mysql
 
volumes:
  db-data:
 
networks:
  default:
    driver: bridge

최상위 요소

요소설명
services컨테이너 정의
volumes볼륨 정의
networks네트워크 정의
configs설정 파일 (Swarm)
secrets비밀 데이터 (Swarm)

🔧 services 상세

image vs build

services:
  # 이미지 사용
  web:
    image: nginx:alpine
  
  # Dockerfile로 빌드
  app:
    build: ./app
    # 또는 상세 설정
    build:
      context: ./app
      dockerfile: Dockerfile.prod
      args:
        - VERSION=1.0.0

ports

services:
  web:
    ports:
      - "8080:80"           # 호스트:컨테이너
      - "8443:443"
      - "127.0.0.1:8080:80" # 특정 IP
      - "3000"              # 랜덤 호스트 포트

environment

services:
  app:
    environment:
      # 리스트 형식
      - NODE_ENV=production
      - DB_HOST=db
      - DB_PORT=3306
    
    # 또는 맵 형식
    environment:
      NODE_ENV: production
      DB_HOST: db
      DB_PORT: 3306

env_file

services:
  app:
    env_file:
      - .env
      - .env.local
# .env
DB_HOST=db
DB_PORT=3306
DB_PASSWORD=secret

volumes

services:
  app:
    volumes:
      # Named volume
      - app-data:/data
      
      # Bind mount
      - ./src:/app/src
      - ./config:/app/config:ro  # 읽기 전용
      
      # Anonymous volume
      - /app/node_modules
 
volumes:
  app-data:

networks

services:
  web:
    networks:
      - frontend
  
  app:
    networks:
      - frontend
      - backend
  
  db:
    networks:
      - backend
 
networks:
  frontend:
  backend:

depends_on

services:
  app:
    depends_on:
      - db
      - redis
    # 시작 순서만 보장, 준비 완료는 보장 안 함
    
  # 조건부 (healthcheck 필요)
  app:
    depends_on:
      db:
        condition: service_healthy

healthcheck

services:
  db:
    image: mysql:8.0
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

restart

services:
  app:
    restart: always
    # no (기본), always, on-failure, unless-stopped
설명
no재시작 안 함 (기본)
always항상 재시작
on-failure실패 시 재시작
unless-stopped수동 중지 전까지 재시작

리소스 제한

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

🚀 주요 명령어

기본 명령어

# 시작 (백그라운드)
docker compose up -d
 
# 중지
docker compose down
 
# 중지 + 볼륨 삭제
docker compose down -v
 
# 로그
docker compose logs
docker compose logs -f          # 실시간
docker compose logs app         # 특정 서비스
 
# 상태 확인
docker compose ps
 
# 실행 중인 서비스에 명령어 실행
docker compose exec app sh
docker compose exec db mysql -u root -p

빌드 관련

# 빌드
docker compose build
 
# 빌드 후 시작
docker compose up -d --build
 
# 특정 서비스만 빌드
docker compose build app
 
# 캐시 없이 빌드
docker compose build --no-cache

스케일링

# 특정 서비스 여러 개 실행
docker compose up -d --scale app=3
 
# 확인
docker compose ps

기타

# 설정 확인 (문법 검증)
docker compose config
 
# 이미지 pull
docker compose pull
 
# 서비스 재시작
docker compose restart
docker compose restart app
 
# 특정 서비스만 시작
docker compose up -d db

🎯 실습: WordPress + MySQL

compose.yaml

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress-data:/var/www/html
    depends_on:
      - db
    restart: always
 
  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
      MYSQL_ROOT_PASSWORD: rootpassword
    volumes:
      - db-data:/var/lib/mysql
    restart: always
 
volumes:
  wordpress-data:
  db-data:

실행

# 시작
docker compose up -d
 
# 확인
docker compose ps
docker compose logs -f
 
# 브라우저에서 http://localhost:8080 접속
 
# 중지
docker compose down
 
# 볼륨까지 삭제 (데이터 삭제)
docker compose down -v

🎯 실습: Node.js + Redis + Nginx

프로젝트 구조

myapp/
├── compose.yaml
├── app/
│   ├── Dockerfile
│   ├── package.json
│   └── index.js
└── nginx/
    └── nginx.conf

compose.yaml

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app
    restart: always
 
  app:
    build: ./app
    environment:
      - REDIS_HOST=redis
      - REDIS_PORT=6379
    depends_on:
      - redis
    restart: always
    deploy:
      replicas: 2
 
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data
    restart: always
 
volumes:
  redis-data:

app/Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

app/package.json

{
  "name": "myapp",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "express": "^4.18.2",
    "redis": "^4.6.0"
  }
}

app/index.js

const express = require('express');
const redis = require('redis');
 
const app = express();
const client = redis.createClient({
  url: `redis://${process.env.REDIS_HOST}:${process.env.REDIS_PORT}`
});
 
client.connect();
 
app.get('/', async (req, res) => {
  const visits = await client.incr('visits');
  res.json({
    message: 'Hello Docker Compose!',
    visits: visits,
    hostname: require('os').hostname()
  });
});
 
app.listen(3000, () => console.log('App running on port 3000'));

nginx/nginx.conf

events {
    worker_connections 1024;
}
 
http {
    upstream app {
        server app:3000;
    }
 
    server {
        listen 80;
        
        location / {
            proxy_pass http://app;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

실행

# 빌드 + 시작
docker compose up -d --build
 
# 테스트
curl http://localhost
curl http://localhost
curl http://localhost
# visits 증가 확인
 
# 스케일 아웃
docker compose up -d --scale app=3
 
# 로그
docker compose logs -f app
 
# 정리
docker compose down -v

🎯 실습: 개발 환경 (Hot Reload)

compose.yaml

services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      # 소스 코드 마운트 (실시간 반영)
      - ./src:/app/src
      # node_modules는 컨테이너 것 사용
      - /app/node_modules
    environment:
      - NODE_ENV=development
    command: npm run dev

compose.override.yaml

개발 환경 전용 설정 (자동으로 병합됨).

# compose.override.yaml
services:
  app:
    volumes:
      - ./src:/app/src
    environment:
      - DEBUG=true

프로덕션 설정

# compose.prod.yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.prod
    environment:
      - NODE_ENV=production
    restart: always
# 개발 환경 (기본)
docker compose up
 
# 프로덕션 환경
docker compose -f compose.yaml -f compose.prod.yaml up -d

📋 compose.yaml 팁

변수 사용

# .env 파일
MYSQL_VERSION=8.0
DB_PASSWORD=secret
 
# compose.yaml
services:
  db:
    image: mysql:${MYSQL_VERSION}
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}

프로필

services:
  app:
    image: myapp
  
  debug:
    image: debug-tools
    profiles:
      - debug
 
# 기본 실행
docker compose up -d
 
# debug 프로필 포함
docker compose --profile debug up -d

확장 (extends)

# common.yaml
services:
  base:
    image: myapp
    environment:
      - LOG_LEVEL=info
 
# compose.yaml
services:
  app:
    extends:
      file: common.yaml
      service: base
    ports:
      - "3000:3000"

📋 명령어 요약

# 라이프사이클
docker compose up -d              # 시작
docker compose down               # 중지
docker compose down -v            # 중지 + 볼륨 삭제
docker compose restart            # 재시작
 
# 빌드
docker compose build              # 빌드
docker compose up -d --build      # 빌드 + 시작
 
# 상태/로그
docker compose ps                 # 상태
docker compose logs -f            # 로그
 
# 실행
docker compose exec <svc> sh      # 접속
docker compose run <svc> <cmd>    # 일회성 명령
 
# 스케일
docker compose up -d --scale app=3

🔗 시리즈 네비게이션

시리즈 목차로 돌아가기


🔗 참고 자료