Docker Compose 실전 가이드 | 멀티 컨테이너·네트워크·볼륨·프로덕션 배포
이 글의 핵심
Docker Compose로 멀티 컨테이너 애플리케이션을 구성하고 배포하는 완벽 가이드. 네트워크, 볼륨, 환경 변수, 프로덕션 배포까지. 실전 예제와 코드로 개념부터 활용까지 정리합니다. Docker·Docker Compose·DevOps 중심으로 설명합니다.
이 글의 핵심
Docker Compose로 멀티 컨테이너 애플리케이션을 구성하고 배포하는 완벽 가이드입니다. 네트워크, 볼륨, 환경 변수, 헬스체크, 프로덕션 배포까지 실무에 바로 적용할 수 있습니다.
실무 경험 공유: 대규모 인프라의 모니터링 스택(Prometheus, Grafana, Loki)을 Docker Compose로 구축하면서, 개발 환경 구성 시간을 2시간에서 5분으로 단축한 경험을 공유합니다.
들어가며: “컨테이너 여러 개를 어떻게 관리하죠?”
실무 문제 시나리오
시나리오 1: 개발 환경 구성이 복잡해요
웹 서버, 데이터베이스, Redis, Nginx를 각각 설치하고 설정하는 데 하루가 걸립니다. Docker Compose로 docker compose up 한 번에 모든 환경을 구성할 수 있습니다.
시나리오 2: 팀원마다 환경이 달라요
“내 컴퓨터에서는 되는데요?” 문제가 반복됩니다. Docker Compose로 모든 팀원이 동일한 환경을 공유할 수 있습니다. 시나리오 3: 프로덕션 배포가 불안해요
개발 환경과 프로덕션 환경이 달라 배포 후 에러가 발생합니다. Docker Compose로 환경을 일치시킬 수 있습니다.
flowchart TB
subgraph Before[문제 상황]
A1[수동 설치]
A2[환경 불일치]
A3[배포 실패]
end
subgraph After[Docker Compose]
B1[docker compose up]
B2[동일 환경]
B3[안정적 배포]
end
Before --> After
1. Docker Compose 기초
Docker Compose란?
여러 컨테이너를 정의하고 실행하는 도구입니다. YAML 파일로 서비스, 네트워크, 볼륨을 선언적으로 정의합니다.
설치
# Docker Desktop 설치 시 자동 포함
docker compose version
# Linux에서 별도 설치
sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
최소 예제
# docker-compose.yml
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
# 실행
docker compose up
# 백그라운드 실행
docker compose up -d
# 중지 및 삭제
docker compose down
2. 멀티 컨테이너 애플리케이션
실전 예제: 웹 애플리케이션 스택
# docker-compose.yml
version: '3.8'
services:
# Nginx 웹 서버
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./public:/usr/share/nginx/html:ro
depends_on:
- app
networks:
- frontend
# Node.js 애플리케이션
app:
build:
context: ./app
dockerfile: Dockerfile
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
- backend
# PostgreSQL 데이터베이스
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# Redis 캐시
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- backend
volumes:
postgres_data:
redis_data:
networks:
frontend:
backend:
서비스 간 의존성
flowchart LR
subgraph Frontend[Frontend Network]
Nginx
App
end
subgraph Backend[Backend Network]
App2[App]
DB[PostgreSQL]
Redis
end
Nginx --> App
App --> App2
App2 --> DB
App2 --> Redis
3. 네트워크 구성
기본 네트워크
services:
web:
image: nginx
networks:
- frontend
app:
image: node:18
networks:
- frontend
- backend
db:
image: postgres
networks:
- backend
networks:
frontend:
backend:
커스텀 네트워크
networks:
frontend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
backend:
driver: bridge
internal: true # 외부 접근 차단
외부 네트워크 연결
networks:
existing_network:
external: true
name: my-pre-existing-network
4. 볼륨 관리
Named Volumes
services:
db:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
driver: local
Bind Mounts
services:
web:
image: nginx
volumes:
# 호스트 경로:컨테이너 경로:옵션
- ./nginx.conf:/etc/nginx/nginx.conf:ro # 읽기 전용
- ./public:/usr/share/nginx/html
tmpfs Mounts (메모리)
services:
app:
image: node:18
tmpfs:
- /tmp
- /run:size=100M,mode=1777
볼륨 백업 및 복원
# 백업
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres_backup.tar.gz -C /data .
# 복원
docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar xzf /backup/postgres_backup.tar.gz -C /data
5. 환경 변수 및 시크릿
.env 파일
# .env
POSTGRES_USER=admin
POSTGRES_PASSWORD=secret123
POSTGRES_DB=myapp
NODE_ENV=production
API_KEY=your-api-key
# docker-compose.yml
services:
db:
image: postgres
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
환경 파일 분리
services:
app:
image: node:18
env_file:
- .env.common
- .env.production
시크릿 관리 (Docker Swarm)
services:
app:
image: node:18
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true
6. 헬스체크 및 재시작 정책
헬스체크
services:
app:
image: node:18
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
재시작 정책
services:
app:
image: node:18
restart: unless-stopped # 수동 중지 전까지 재시작
worker:
image: node:18
restart: on-failure:3 # 실패 시 최대 3회 재시작
cache:
image: redis
restart: always # 항상 재시작
7. 빌드 및 이미지 관리
Dockerfile과 통합
services:
app:
build:
context: ./app
dockerfile: Dockerfile
args:
- NODE_VERSION=18
- BUILD_ENV=production
target: production # 멀티스테이지 빌드의 특정 단계
cache_from:
- myapp:latest
# app/Dockerfile
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM base AS development
RUN npm install
FROM base AS production
COPY . .
RUN npm run build
CMD ["node", "dist/index.js"]
이미지 빌드 및 푸시
# 빌드
docker compose build
# 특정 서비스만 빌드
docker compose build app
# 빌드 후 실행
docker compose up --build
# 이미지 푸시
docker compose push
8. 프로덕션 배포
프로덕션 설정 분리
# docker-compose.yml (기본)
version: '3.8'
services:
app:
image: myapp:latest
environment:
- NODE_ENV=development
# docker-compose.prod.yml (프로덕션 오버라이드)
version: '3.8'
services:
app:
environment:
- NODE_ENV=production
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
# 프로덕션 실행
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
리소스 제한
services:
app:
image: node:18
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '1'
memory: 512M
로깅 설정
services:
app:
image: node:18
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
9. 실전 예제: 풀스택 애플리케이션
프로젝트 구조
myapp/
├── docker-compose.yml
├── docker-compose.prod.yml
├── .env
├── nginx/
│ ├── Dockerfile
│ └── nginx.conf
├── frontend/
│ ├── Dockerfile
│ ├── package.json
│ └── src/
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ └── src/
└── scripts/
├── init-db.sql
└── backup.sh
docker-compose.yml
version: '3.8'
services:
nginx:
build: ./nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- backend
networks:
- frontend
restart: unless-stopped
frontend:
build:
context: ./frontend
target: production
environment:
- NEXT_PUBLIC_API_URL=http://backend:3000
networks:
- frontend
restart: unless-stopped
backend:
build:
context: ./backend
target: production
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:${DB_PASSWORD}@db:5432/myapp
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=myapp
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped
backup:
image: postgres:15-alpine
volumes:
- postgres_data:/data:ro
- ./backups:/backups
entrypoint: /bin/sh
command: -c "while true; do pg_dump -U user -h db myapp > /backups/backup_$$(date +%Y%m%d_%H%M%S).sql; sleep 86400; done"
depends_on:
- db
networks:
- backend
restart: unless-stopped
volumes:
postgres_data:
redis_data:
networks:
frontend:
backend:
Nginx 설정
# nginx/nginx.conf
upstream frontend {
server frontend:3000;
}
upstream backend {
server backend:3000;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://frontend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
10. 자주 하는 실수와 해결법
문제 1: 컨테이너 간 통신 안 됨
원인: 같은 네트워크에 있지 않음.
# ❌ 잘못된 코드
services:
app:
image: node:18
# 네트워크 지정 안 함
db:
image: postgres
networks:
- backend
# ✅ 올바른 코드
services:
app:
image: node:18
networks:
- backend
db:
image: postgres
networks:
- backend
문제 2: 볼륨 데이터 손실
원인: docker compose down -v로 볼륨까지 삭제.
# ❌ 볼륨까지 삭제
docker compose down -v
# ✅ 컨테이너만 삭제
docker compose down
문제 3: 환경 변수 인식 안 됨
원인: .env 파일 위치 또는 형식 오류.
# .env 파일은 docker-compose.yml과 같은 디렉터리에
# 공백 없이 작성
DB_PASSWORD=secret123
# ❌ DB_PASSWORD = secret123 (공백 있으면 안 됨)
문제 4: 포트 충돌
원인: 호스트 포트가 이미 사용 중.
# 포트 사용 확인
sudo lsof -i :80
# 다른 포트로 변경
services:
nginx:
ports:
- "8080:80" # 호스트 8080 포트 사용
11. 모니터링 및 로깅
Docker Compose 상태 확인
# 실행 중인 서비스 확인
docker compose ps
# 로그 확인
docker compose logs
# 특정 서비스 로그
docker compose logs app
# 실시간 로그
docker compose logs -f
# 최근 100줄
docker compose logs --tail=100
리소스 사용량 모니터링
# 실시간 리소스 사용량
docker stats
# Compose 서비스만
docker compose ps -q | xargs docker stats
Prometheus + Grafana 통합
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
ports:
- "9090:9090"
grafana:
image: grafana/grafana
volumes:
- grafana_data:/var/lib/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
prometheus_data:
grafana_data:
12. CI/CD 통합
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
run: |
docker compose build
docker compose push
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /app
docker compose pull
docker compose up -d
13. Compose V2 내부·네트워킹·프로덕션 패턴
Compose 스펙은 서비스 디스커버리를 위해 기본 브리지 네트워크를 만들고, 서비스 이름이 DNS 이름으로 해석됩니다. 그래서 app 컨테이너에서 postgres:5432로 접속하는 패턴이 가능합니다. 호스트 네트워크 모드는 OS별 차이가 크므로 로컬과 CI에서 동일하게 재현하려면 퍼블리시 포트 방식이 안전합니다.
헬스체크는 오케스트레이션 레벨에서 “준비됐는지”를 판별하는 훅입니다. depends_on만으로는 DB가 준비됐다는 뜻이 아니므로, 애플리케이션 쪽에서 재시도 가능한 연결 루프를 두거나 healthcheck를 맞춥니다.
프로덕션에서 자주 쓰는 옵션
deploy.resources: Swarm 모드에서 CPU/메모리 제한(단일 호스트 Compose에서는mem_limit등과 혼동 주의).profiles:dev전용 서비스(PgAdmin 등)를 프로덕션up에서 제외합니다.- 시크릿:
.env는 편하지만 권한 오류로 레포에 올라가는 사고가 잦습니다. 서버에서는 Docker secrets나 외부 비밀 저장소를 검토합니다.
14. 트러블슈팅 (심화)
| 증상 | 흔한 원인 | 점검 |
|---|---|---|
| 컨테이너는 뜨는데 DB만 안 붙는다 | 잘못된 서비스명·포트·네트워크 attach | docker compose exec app ping postgres |
| 볼륨 권한 문제(Linux) | UID/GID 불일치 | named volume 또는 user 매핑 |
| 빌드 캐시가 꼬인다 | 베이스 이미지·레이어 재사용 | --no-cache로 단일 검증 후 Dockerfile 정리 |
| OOM | 메모리 제한 없음 | 호스트 모니터링 + 컨테이너 limit |
정리 및 체크리스트
핵심 요약
- Docker Compose는 멀티 컨테이너 애플리케이션을 YAML로 정의하고 관리
- 네트워크로 서비스 간 통신을 격리하고 제어
- 볼륨으로 데이터를 영구 저장
- 헬스체크와 재시작 정책으로 안정성 확보
- 환경별 설정 분리로 개발/프로덕션 환경 관리
프로덕션 체크리스트
- 환경 변수를
.env파일로 분리 - 시크릿 정보는
.gitignore에 추가 - 헬스체크 설정
- 재시작 정책 설정
- 리소스 제한 설정
- 로깅 드라이버 설정
- 백업 전략 수립
- 모니터링 도구 연동
같이 보면 좋은 글
- Kubernetes 실전 가이드 | Pod·Service·Deployment·Ingress
- 웹 보안 완벽 가이드 | OWASP Top 10·XSS·CSRF·JWT
- Next.js 15 완벽 가이드 | App Router·Server Actions·Turbopack
이 글에서 다루는 키워드
Docker, Docker Compose, 컨테이너, DevOps, 멀티 컨테이너, 네트워크, 볼륨, 배포, CI/CD
내부 동작과 핵심 메커니즘
이 글의 주제는 「Docker Compose 실전 가이드 | 멀티 컨테이너·네트워크·볼륨·프로덕션 배포」입니다. 앞선 튜토리얼을 구현·런타임 관점에서 다시 압축합니다. 구성 요소 간 책임 분리와 관측 가능한 지점을 기준으로 “입력이 어디서 검증되고, 핵심 연산이 어디서 일어나며, 부작용(I/O·네트워크·디스크)·동시성이 어디서 터지는가”를 한 장면으로 그리면 장애 분석이 빨라집니다.
처리 파이프라인(개념도)
flowchart TD A[입력·요청·이벤트] --> B[파싱·검증·디코딩] B --> C[핵심 연산·상태 전이] C --> D[부작용: I/O·네트워크·동시성] D --> E[결과·관측·저장]
경계에서의 지연·실패(시퀀스 관점)
sequenceDiagram participant C as 클라이언트/호출자 participant B as 경계(프로세스·런타임·게이트웨이) participant D as 의존성(외부 API·DB·큐) C->>B: 요청/이벤트 B->>D: 조회·쓰기·RPC D-->>B: 지연·부분 실패·재시도 가능 B-->>C: 응답 또는 오류(코드·상관 ID)
알고리즘·프로토콜·리소스 관점 체크포인트
- 불변 조건(Invariant): 각 단계가 만족해야 하는 조건(버퍼 경계, 프로토콜 상태, 트랜잭션 격리, 파일 디스크립터 상한)을 문장으로 적어 두면 디버깅 비용이 줄어듭니다.
- 결정성: 동일 입력에 동일 출력이 보장되는 순수 층과, 시간·네트워크·스레드 스케줄에 의해 달라질 수 있는 층을 분리해야 테스트와 장애 분석이 쉬워집니다.
- 경계 비용: 직렬화/역직렬화, 문자 인코딩, syscall 횟수, 락 경합, GC·할당, 캐시 미스처럼 누적 비용을 의심 목록에 넣습니다.
- 백프레셔: 생산자가 소비자보다 빠를 때(소켓 버퍼, 큐 깊이, 스트림) 어디서 어떤 신호로 속도를 줄일지 정의합니다.
프로덕션 운영 패턴
실서비스에서는 기능과 함께 관측·배포·보안·비용·규제가 동시에 요구됩니다.
| 영역 | 운영 관점 질문 |
|---|---|
| 관측성 | 요청 단위 상관 ID, 에러율/지연 분위수(p95/p99), 의존성 타임아웃·재시도가 대시보드에 보이는가 |
| 안전성 | 입력 검증·권한·비밀·감사 로그가 코드 경로마다 일관적인가 |
| 신뢰성 | 재시도는 멱등 연산에만 적용되는가, 서킷 브레이커·백오프·DLQ가 있는가 |
| 성능 | 캐시 계층·배치 크기·커넥션 풀·인덱스·백프레셔가 데이터 규모에 맞는가 |
| 배포 | 롤백 룬북, 카나리/블루그린, 마이그레이션 호환성·플래그가 문서화되어 있는가 |
| 용량 | 피크 트래픽·디스크·파일 디스크립터·스레드 풀 상한을 주기적으로 검증하는가 |
스테이징은 데이터 양·네트워크 RTT·동시성을 가능한 한 프로덕션에 가깝게 맞추는 것이 재현율을 높입니다.
확장 예시: 엔드투엔드 미니 시나리오
「Docker Compose 실전 가이드 | 멀티 컨테이너·네트워크·볼륨·프로덕션 배포」을 실제 배포·운영 흐름으로 옮긴 체크리스트형 시나리오입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.
- 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드 표를 API 또는 이벤트 경계에 둔다.
- 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 한 화면(로그+메트릭+트레이스)에서 추적한다.
- 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
- 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지(또는 피처 플래그) 확인한다.
- 부하 후 검증: 피크 대비 p95/p99, 에러율, 리소스 상한, 알림 임계값이 기대 범위인지 본다.
의사코드 스케치(프레임워크 무관)
handle(request):
ctx = newCorrelationId()
validated = validateSchema(request) // 경계에서 거절
authorize(validated, ctx) // 권한·테넌트
result = domainCore(validated) // 순수에 가까운 규칙
persistOrEmit(result, idempotentKey) // I/O: 멱등·재시도 정책
recordMetrics(ctx, latency, outcome)
return result
문제 해결(Troubleshooting)
| 증상 | 가능 원인 | 조치 |
|---|---|---|
| 간헐적 실패 | 레이스, 타임아웃, 외부 의존성 불안정, DNS | 최소 재현 스크립트, 분산 트레이스·로그 상관관계, 재시도·서킷 설정 점검 |
| 성능 저하 | N+1, 동기 I/O, 락 경합, 과도한 직렬화, 캐시 미스 | 프로파일러·APM으로 핫스팟 확인 후 한 가지씩 제거 |
| 메모리 증가 | 캐시 무제한, 구독/리스너 누수, 대용량 버퍼, 커넥션 미반납 | 상한·TTL·힙/FD 스냅샷 비교 |
| 빌드·배포만 실패 | 환경 변수, 권한, 플랫폼 차이, lockfile | CI 로그와 로컬 diff, 런타임·이미지 버전 핀 |
| 설정이 로컬과 다름 | 프로필·시크릿·기본값, 지역 리전 | 단일 소스(예: 스키마 검증된 설정)와 배포 매트릭스 표준화 |
| 데이터 불일치 | 비멱등 재시도, 부분 쓰기, 캐시 무효화 누락 | 멱등 키·아웃박스·트랜잭션 경계 재검토 |
권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.
자주 묻는 질문 (FAQ)
Q. Docker Compose vs Kubernetes, 언제 뭘 쓰나요?
A. 소규모 프로젝트, 개발 환경은 Docker Compose를 권장합니다. 대규모, 멀티 클러스터, 자동 스케일링이 필요하면 Kubernetes를 사용하세요.
Q. 프로덕션에서 Docker Compose를 써도 되나요?
A. 단일 서버 배포는 가능합니다. 하지만 고가용성, 자동 스케일링이 필요하면 Kubernetes나 Docker Swarm을 고려하세요.
Q. 볼륨 데이터를 백업하려면?
A. docker run --rm -v volume_name:/data -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz -C /data . 명령으로 백업할 수 있습니다.
Q. 컨테이너 간 통신이 안 되는데요?
A. 같은 네트워크에 있는지 확인하세요. docker compose logs로 네트워크 오류를 확인할 수 있습니다.