Docker Compose

Docker Compose

1. Docker Compose๋ž€?

Docker Compose๋Š” ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ •์˜ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. YAML ํŒŒ์ผ ํ•˜๋‚˜๋กœ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์Šคํƒ์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์™œ Docker Compose๋ฅผ ์‚ฌ์šฉํ• ๊นŒ์š”?

์ผ๋ฐ˜ Docker ๋ช…๋ น์–ด:

# ๋„คํŠธ์›Œํฌ ์ƒ์„ฑ
docker network create myapp-network

# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹คํ–‰
docker run -d \
  --name db \
  --network myapp-network \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:15

# ๋ฐฑ์—”๋“œ ์‹คํ–‰
docker run -d \
  --name backend \
  --network myapp-network \
  -e DATABASE_URL=postgres://... \
  -p 3000:3000 \
  my-backend

# ํ”„๋ก ํŠธ์—”๋“œ ์‹คํ–‰
docker run -d \
  --name frontend \
  --network myapp-network \
  -p 80:80 \
  my-frontend

Docker Compose:

docker compose up -d
์žฅ์  ์„ค๋ช…
๊ฐ„ํŽธํ•จ ํ•œ ๋ช…๋ น์œผ๋กœ ์ „์ฒด ์‹คํ–‰
์„ ์–ธ์  YAML๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜
๋ฒ„์ „ ๊ด€๋ฆฌ ์„ค์ • ํŒŒ์ผ์„ Git์œผ๋กœ ๊ด€๋ฆฌ
์žฌํ˜„์„ฑ ๋™์ผํ•œ ํ™˜๊ฒฝ ์žฌํ˜„ ๊ฐ€๋Šฅ

2. ์„ค์น˜ ํ™•์ธ

Docker Desktop์—๋Š” Docker Compose๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

# ๋ฒ„์ „ ํ™•์ธ
docker compose version
# Docker Compose version v2.23.0

# ๋˜๋Š” (๊ตฌ๋ฒ„์ „)
docker-compose --version

์ฐธ๊ณ : docker-compose (ํ•˜์ดํ”ˆ)์€ ๊ตฌ๋ฒ„์ „, docker compose (๊ณต๋ฐฑ)์€ ์‹ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.


3. docker-compose.yml ๊ธฐ๋ณธ ๊ตฌ์กฐ

# docker-compose.yml

services:
  ์„œ๋น„์Šค๋ช…1:
    image: ์ด๋ฏธ์ง€๋ช…
    ports:
      - "ํ˜ธ์ŠคํŠธ:์ปจํ…Œ์ด๋„ˆ"
    environment:
      - ๋ณ€์ˆ˜=๊ฐ’
    volumes:
      - ๋ณผ๋ฅจ:๊ฒฝ๋กœ
    depends_on:
      - ๋‹ค๋ฅธ์„œ๋น„์Šค

  ์„œ๋น„์Šค๋ช…2:
    build: ./๊ฒฝ๋กœ
    ...

volumes:
  ๋ณผ๋ฅจ๋ช…:

networks:
  ๋„คํŠธ์›Œํฌ๋ช…:

4. ์ฃผ์š” ์„ค์ • ์˜ต์…˜

services - ์„œ๋น„์Šค ์ •์˜

services:
  web:
    image: nginx:alpine

image - ์ด๋ฏธ์ง€ ์ง€์ •

services:
  db:
    image: postgres:15

  redis:
    image: redis:7-alpine

build - Dockerfile๋กœ ๋นŒ๋“œ

services:
  app:
    build: .                    # ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ Dockerfile

  api:
    build:
      context: ./backend        # ๋นŒ๋“œ ์ปจํ…์ŠคํŠธ
      dockerfile: Dockerfile    # Dockerfile ๊ฒฝ๋กœ
      args:                     # ๋นŒ๋“œ ์ธ์ž
        - NODE_ENV=production

ports - ํฌํŠธ ๋งคํ•‘

services:
  web:
    ports:
      - "8080:80"              # ํ˜ธ์ŠคํŠธ:์ปจํ…Œ์ด๋„ˆ
      - "443:443"

  api:
    ports:
      - "3000:3000"

environment - ํ™˜๊ฒฝ ๋ณ€์ˆ˜

services:
  db:
    environment:
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=myapp

  # ๋˜๋Š” key: value ํ˜•์‹
  api:
    environment:
      NODE_ENV: production
      DB_HOST: db

env_file - ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํŒŒ์ผ

services:
  api:
    env_file:
      - .env
      - .env.local

.env ํŒŒ์ผ:

DB_HOST=localhost
DB_PASSWORD=secret
API_KEY=abc123

volumes - ๋ณผ๋ฅจ ๋งˆ์šดํŠธ

services:
  db:
    volumes:
      - pgdata:/var/lib/postgresql/data    # Named volume
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql  # ๋ฐ”์ธ๋“œ ๋งˆ์šดํŠธ

  app:
    volumes:
      - ./src:/app/src                      # ์†Œ์Šค ์ฝ”๋“œ ๋งˆ์šดํŠธ (๊ฐœ๋ฐœ์šฉ)
      - /app/node_modules                   # ์ต๋ช… ๋ณผ๋ฅจ (๋ฎ์–ด์“ฐ๊ธฐ ๋ฐฉ์ง€)

volumes:
  pgdata:                                   # Named volume ์„ ์–ธ

depends_on - ์˜์กด์„ฑ

services:
  api:
    depends_on:
      - db
      - redis

  db:
    image: postgres:15

  redis:
    image: redis:7

์ฃผ์˜: depends_on์€ ์‹œ์ž‘ ์ˆœ์„œ๋งŒ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค๊ฐ€ "์ค€๋น„"๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

networks - ๋„คํŠธ์›Œํฌ

services:
  frontend:
    networks:
      - frontend-net

  backend:
    networks:
      - frontend-net
      - backend-net

  db:
    networks:
      - backend-net

networks:
  frontend-net:
  backend-net:

restart - ์žฌ์‹œ์ž‘ ์ •์ฑ…

services:
  web:
    restart: always              # ํ•ญ์ƒ ์žฌ์‹œ์ž‘

  api:
    restart: unless-stopped      # ์ˆ˜๋™ ์ค‘์ง€ ์ „๊นŒ์ง€ ์žฌ์‹œ์ž‘

  worker:
    restart: on-failure          # ์‹คํŒจ ์‹œ ์žฌ์‹œ์ž‘

healthcheck - ํ—ฌ์Šค์ฒดํฌ

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

5. Docker Compose ๋ช…๋ น์–ด

์‹คํ–‰

# ์‹คํ–‰ (ํฌ๊ทธ๋ผ์šด๋“œ)
docker compose up

# ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰
docker compose up -d

# ์ด๋ฏธ์ง€ ์žฌ๋นŒ๋“œ ํ›„ ์‹คํ–‰
docker compose up --build

# ํŠน์ • ์„œ๋น„์Šค๋งŒ ์‹คํ–‰
docker compose up -d web api

์ค‘์ง€/์‚ญ์ œ

# ์ค‘์ง€
docker compose stop

# ์ค‘์ง€ ๋ฐ ์ปจํ…Œ์ด๋„ˆ ์‚ญ์ œ
docker compose down

# ๋ณผ๋ฅจ๋„ ํ•จ๊ป˜ ์‚ญ์ œ
docker compose down -v

# ์ด๋ฏธ์ง€๋„ ํ•จ๊ป˜ ์‚ญ์ œ
docker compose down --rmi all

์ƒํƒœ ํ™•์ธ

# ์„œ๋น„์Šค ๋ชฉ๋ก
docker compose ps

# ๋กœ๊ทธ ํ™•์ธ
docker compose logs

# ํŠน์ • ์„œ๋น„์Šค ๋กœ๊ทธ
docker compose logs api

# ์‹ค์‹œ๊ฐ„ ๋กœ๊ทธ
docker compose logs -f

์„œ๋น„์Šค ๊ด€๋ฆฌ

# ์žฌ์‹œ์ž‘
docker compose restart

# ํŠน์ • ์„œ๋น„์Šค ์žฌ์‹œ์ž‘
docker compose restart api

# ์„œ๋น„์Šค ์Šค์ผ€์ผ๋ง
docker compose up -d --scale api=3

# ์„œ๋น„์Šค ๋‚ด ๋ช…๋ น ์‹คํ–‰
docker compose exec api bash
docker compose exec db psql -U postgres

6. ์‹ค์Šต ์˜ˆ์ œ

์˜ˆ์ œ 1: ์›น + ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ:

my-webapp/
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ .env
โ””โ”€โ”€ app/
    โ”œโ”€โ”€ Dockerfile
    โ””โ”€โ”€ index.js

docker-compose.yml:

services:
  app:
    build: ./app
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  pgdata:

app/Dockerfile:

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

app/index.js:

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.json({
    message: 'Hello from Docker Compose!',
    db_url: process.env.DATABASE_URL ? 'Connected' : 'Not set'
  });
});

app.listen(3000, () => console.log('Server on port 3000'));

์‹คํ–‰:

cd my-webapp
docker compose up -d
curl http://localhost:3000
docker compose logs -f
docker compose down

์˜ˆ์ œ 2: ํ’€์Šคํƒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

# docker-compose.yml

services:
  # ํ”„๋ก ํŠธ์—”๋“œ (React)
  frontend:
    build: ./frontend
    ports:
      - "80:80"
    depends_on:
      - backend

  # ๋ฐฑ์—”๋“œ (Node.js)
  backend:
    build: ./backend
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - DB_NAME=myapp
      - REDIS_HOST=redis
    depends_on:
      - db
      - redis

  # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค (PostgreSQL)
  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql

  # ์บ์‹œ (Redis)
  redis:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

  # ๊ด€๋ฆฌ ๋„๊ตฌ (pgAdmin)
  pgadmin:
    image: dpage/pgadmin4
    environment:
      - PGADMIN_DEFAULT_EMAIL=admin@example.com
      - PGADMIN_DEFAULT_PASSWORD=admin
    ports:
      - "5050:80"
    depends_on:
      - db

volumes:
  pgdata:
  redisdata:

.env:

DB_PASSWORD=supersecret123

์˜ˆ์ œ 3: ๊ฐœ๋ฐœ ํ™˜๊ฒฝ

# docker-compose.dev.yml

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app                    # ์†Œ์Šค ์ฝ”๋“œ ๋งˆ์šดํŠธ
      - /app/node_modules         # node_modules ๋ณดํ˜ธ
    environment:
      - NODE_ENV=development
    command: npm run dev          # ๊ฐœ๋ฐœ ์„œ๋ฒ„ ์‹คํ–‰

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_PASSWORD=devpass
    ports:
      - "5432:5432"              # ๋กœ์ปฌ ์ ‘์† ํ—ˆ์šฉ

์‹คํ–‰:

# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ
docker compose -f docker-compose.dev.yml up

# ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ
docker compose -f docker-compose.yml up -d

7. ์œ ์šฉํ•œ ํŒจํ„ด

ํ™˜๊ฒฝ๋ณ„ ์„ค์ • ๋ถ„๋ฆฌ

# docker-compose.yml (๊ธฐ๋ณธ)
services:
  app:
    image: myapp

# docker-compose.override.yml (๊ฐœ๋ฐœ์šฉ, ์ž๋™ ๋ณ‘ํ•ฉ)
services:
  app:
    build: .
    volumes:
      - .:/app

# docker-compose.prod.yml (ํ”„๋กœ๋•์…˜์šฉ)
services:
  app:
    restart: always
# ๊ฐœ๋ฐœ: docker-compose.yml + docker-compose.override.yml ์ž๋™ ๋ณ‘ํ•ฉ
docker compose up

# ํ”„๋กœ๋•์…˜
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

์„œ๋น„์Šค ๋Œ€๊ธฐ (wait-for-it)

services:
  app:
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:15
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

๋ช…๋ น์–ด ์š”์•ฝ

๋ช…๋ น์–ด ์„ค๋ช…
docker compose up ์„œ๋น„์Šค ์‹œ์ž‘
docker compose up -d ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹œ์ž‘
docker compose up --build ์žฌ๋นŒ๋“œ ํ›„ ์‹œ์ž‘
docker compose down ์„œ๋น„์Šค ์ค‘์ง€ ๋ฐ ์‚ญ์ œ
docker compose down -v ๋ณผ๋ฅจ๋„ ์‚ญ์ œ
docker compose ps ์„œ๋น„์Šค ์ƒํƒœ
docker compose logs ๋กœ๊ทธ ํ™•์ธ
docker compose logs -f ์‹ค์‹œ๊ฐ„ ๋กœ๊ทธ
docker compose exec ์„œ๋น„์Šค ๋ช…๋ น ๋ช…๋ น ์‹คํ–‰
docker compose restart ์žฌ์‹œ์ž‘

๋‹ค์Œ ๋‹จ๊ณ„

05_Practical_Examples.md์—์„œ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— Docker๋ฅผ ์ ์šฉํ•ด๋ด…์‹œ๋‹ค!

to navigate between lessons