Skip to main content

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

🔗 시리즈 네비게이션

이전다음
Docker Volume & NetworkDocker vs Podman

시리즈 목차로 돌아가기


🔗 참고 자료