“이제와서 시작하는 Docker 마스터하기” Docker Swarm은 Docker의 네이티브 클러스터링 및 오케스트레이션 도구입니다. 여러 Docker 호스트를 하나의 가상 Docker 호스트로 만들어 컨테이너를 관리할 수 있습니다. Kubernetes보다 간단하면서도 강력한 기능을 제공합니다.
학습 목표
- 🛠️ Docker Swarm의 개념과 아키텍처 이해
- 🏛️ 클러스터 구성과 노드 관리
- 🔄 서비스 배포와 업데이트
- ⚖️ 로드 밸런싱과 고가용성
- 🔒 보안과 모니터링
Docker Swarm이란?
Docker Swarm은 여러 Docker 호스트를 클러스터로 구성하고 관리하는 도구입니다:
Swarm vs Kubernetes 비교
| 특징 | Docker Swarm | Kubernetes |
| 학습 곡선 | 🟢 낮음 | 🔴 높음 |
| 설치 복잡도 | 🟢 간단 | 🟡 복잡 |
| 기능 | 🟡 기본적 | 🟢 풀기능 |
| 생태계 | 🟡 제한적 | 🟢 방대함 |
| Docker 통합 | 🟢 내장 | 🟡 플러그인 |
주요 기능
graph TB
subgraph "Docker Swarm 기능"
A[🏛️ 클러스터 관리]
B[🔄 서비스 오케스트레이션]
C[⚖️ 로드 밸런싱]
D[🔒 보안 및 Secrets]
E[🌐 Overlay 네트워크]
F[📊 모니터링]
end
A --> G[클러스터링된<br/>컨테이너 환경]
B --> G
C --> G
D --> G
E --> G
F --> G
Swarm 모드 시작하기
Swarm 클러스터 구조
graph TB
subgraph "Manager Nodes"
M1[Manager 1<br/>Leader]
M2[Manager 2]
M3[Manager 3]
end
subgraph "Worker Nodes"
W1[Worker 1]
W2[Worker 2]
W3[Worker 3]
W4[Worker 4]
end
M1 -.->|Raft 동기화| M2
M2 -.->|Raft 동기화| M3
M3 -.->|Raft 동기화| M1
M1 -->|Task 할당| W1
M1 -->|Task 할당| W2
M1 -->|Task 할당| W3
M1 -->|Task 할당| W4
1. Swarm 초기화
1
2
3
4
5
6
7
8
| # Manager 노드에서 Swarm 초기화
docker swarm init --advertise-addr 192.168.1.100
# 출력 예시:
# Swarm initialized: current node (abcd1234) is now a manager.
#
# To add a worker to this swarm, run the following command:
# docker swarm join --token SWMTKN-1-xxxxx 192.168.1.100:2377
|
2. Worker 노드 추가
1
2
3
4
5
| # Worker 노드에서 실행
docker swarm join --token SWMTKN-1-xxxxx 192.168.1.100:2377
# Manager 노드로 추가하려면
docker swarm join-token manager
|
3. 노드 확인
1
2
3
4
5
6
7
8
9
| # 클러스터 노드 목록
docker node ls
# 노드 상세 정보
docker node inspect node-name
# 노드 역할 변경
docker node promote worker-node # Worker를 Manager로
docker node demote manager-node # Manager를 Worker로
|
서비스 생성과 관리
1. 첫 번째 서비스 생성
1
2
3
4
5
6
7
8
9
10
11
12
| # 간단한 웹 서비스 생성
docker service create \
--name web \
--replicas 3 \
--publish 80:80 \
nginx:alpine
# 서비스 목록 확인
docker service ls
# 서비스 상세 정보
docker service ps web
|
2. 서비스 업데이트
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 레플리카 수 변경
docker service scale web=5
# 이미지 업데이트
docker service update \
--image nginx:latest \
web
# 롤링 업데이트 설정
docker service update \
--update-parallelism 2 \
--update-delay 10s \
web
|
3. 서비스 제약 조건
1
2
3
4
5
6
7
8
9
| # 특정 노드에만 배치
docker service create \
--name db \
--constraint node.role==manager \
--constraint node.labels.disk==ssd \
postgres:13
# 노드 라벨 추가
docker node update --label-add disk=ssd node1
|
Stack 배포
Stack vs Service 비교
graph LR
subgraph "Service"
S1[📦 단일 서비스]
S2[직접 명령]
S3[간단한 배포]
end
subgraph "Stack"
ST1[📦📦📦 여러 서비스]
ST2[YAML 파일]
ST3[복잡한 배포]
ST4[네트워크/볼륨 포함]
end
S1 --> D1[docker service create]
ST1 --> D2[docker stack deploy]
1. docker-compose.yml 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
| # stack.yml
version: '3.8'
services:
web:
image: nginx:alpine
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
restart_policy:
condition: any
delay: 5s
max_attempts: 3
placement:
constraints:
- node.role == worker
networks:
- webnet
ports:
- "80:80"
app:
image: myapp:latest
deploy:
replicas: 5
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
networks:
- webnet
- backend
environment:
- NODE_ENV=production
- DB_HOST=db
db:
image: postgres:13
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
restart_policy:
condition: any
networks:
- backend
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
redis:
image: redis:alpine
deploy:
replicas: 1
update_config:
parallelism: 1
delay: 10s
networks:
- backend
networks:
webnet:
driver: overlay
backend:
driver: overlay
internal: true
volumes:
db-data:
driver: local
secrets:
db_password:
external: true
|
2. Stack 배포
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Secret 생성
echo "mysecretpassword" | docker secret create db_password -
# Stack 배포
docker stack deploy -c stack.yml myapp
# Stack 목록
docker stack ls
# Stack 서비스 확인
docker stack services myapp
# Stack 제거
docker stack rm myapp
|
네트워킹
Swarm 네트워크 아키텍처
graph TB
subgraph "Ingress Network"
I1[Load Balancer]
I2[Routing Mesh]
end
subgraph "Overlay Networks"
O1[Frontend Network]
O2[Backend Network<br/>Internal]
end
subgraph "Services"
S1[Web Service]
S2[API Service]
S3[DB Service]
end
I1 --> I2
I2 --> S1
S1 -.-> O1
S1 -.-> O2
S2 -.-> O1
S2 -.-> O2
S3 -.-> O2
style O2 fill:#ffcccc
1. Overlay 네트워크
1
2
3
4
5
6
7
8
9
10
11
12
| # Overlay 네트워크 생성
docker network create \
--driver overlay \
--subnet 10.0.0.0/16 \
--attachable \
my-overlay
# 암호화된 Overlay 네트워크
docker network create \
--driver overlay \
--opt encrypted \
secure-overlay
|
2. 서비스 디스커버리
1
2
3
4
5
6
7
8
9
10
11
| # 서비스 간 통신
docker service create \
--name backend \
--network my-overlay \
myapp:backend
docker service create \
--name frontend \
--network my-overlay \
-e BACKEND_URL=http://backend:8080 \
myapp:frontend
|
고가용성 구성
1. Manager 노드 구성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 3개 이상의 홀수 Manager 권장
# Manager 1 (Leader)
docker swarm init --advertise-addr 192.168.1.100
# Manager 2
docker swarm join-token manager
# 생성된 토큰으로 조인
# Manager 3
docker swarm join-token manager
# 생성된 토큰으로 조인
# Quorum 확인
docker node ls
|
2. 서비스 가용성 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| # high-availability.yml
version: '3.8'
services:
web:
image: nginx:alpine
deploy:
replicas: 6
update_config:
parallelism: 2
delay: 10s
failure_action: rollback
monitor: 30s
max_failure_ratio: 0.3
rollback_config:
parallelism: 1
delay: 10s
restart_policy:
condition: any
delay: 5s
max_attempts: 3
window: 120s
placement:
max_replicas_per_node: 2
preferences:
- spread: node.labels.zone
|
로드 밸런싱
1. Ingress 네트워크
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 서비스 생성 시 자동으로 로드 밸런싱
docker service create \
--name web \
--replicas 3 \
--publish published=80,target=80,mode=ingress \
nginx
# Host 모드 (로드 밸런싱 없음)
docker service create \
--name web-host \
--mode global \
--publish published=8080,target=80,mode=host \
nginx
|
2. 외부 로드 밸런서 연동
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # nginx.conf (외부 LB)
upstream docker_swarm {
server swarm-node1:80;
server swarm-node2:80;
server swarm-node3:80;
}
server {
listen 80;
location / {
proxy_pass http://docker_swarm;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
|
모니터링과 로깅
모니터링 스택 구성
flowchart LR
subgraph "Data Collection"
N1[Node Exporter]
C1[cAdvisor]
S1[Service Metrics]
end
subgraph "Storage"
P[Prometheus]
end
subgraph "Visualization"
G[Grafana]
A[Alert Manager]
end
N1 -->|Node 메트릭| P
C1 -->|Container 메트릭| P
S1 -->|Service 메트릭| P
P --> G
P --> A
G -->|Dashboard| U[사용자]
A -->|Alert| U
1. 서비스 모니터링
1
2
3
4
5
6
7
8
9
10
| # 서비스 로그
docker service logs web
docker service logs -f --tail 100 web
# 노드별 컨테이너 확인
docker node ps node1
# 전체 클러스터 상태
docker node ls
docker service ls
|
2. Prometheus 스택
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| # monitoring-stack.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus
configs:
- source: prometheus_config
target: /etc/prometheus/prometheus.yml
deploy:
placement:
constraints:
- node.role == manager
networks:
- monitoring
node-exporter:
image: prom/node-exporter
deploy:
mode: global
networks:
- monitoring
cadvisor:
image: gcr.io/cadvisor/cadvisor
deploy:
mode: global
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
networks:
- monitoring
grafana:
image: grafana/grafana
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
ports:
- "3000:3000"
networks:
- monitoring
networks:
monitoring:
driver: overlay
configs:
prometheus_config:
file: ./prometheus.yml
|
보안
1. Secrets 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Secret 생성
docker secret create db_password password.txt
echo "mypassword" | docker secret create db_password -
# Secret 사용
docker service create \
--name db \
--secret db_password \
-e POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
postgres:13
# Secret 목록
docker secret ls
# Secret 제거
docker secret rm db_password
|
2. TLS 설정
1
2
3
4
5
6
7
8
9
10
11
| # Swarm 통신 암호화 확인
docker swarm ca
# 인증서 로테이션
docker swarm ca --rotate
# 외부 CA 사용
docker swarm ca \
--ca-cert /path/to/ca.crt \
--ca-key /path/to/ca.key \
--external-ca protocol=cfssl,url=https://ca.example.com
|
실전 예제: 마이크로서비스 배포
마이크로서비스 아키텍처
graph TB
subgraph "External"
U[사용자]
LB[Load Balancer]
end
subgraph "API Gateway Layer"
AG1[API Gateway 1]
AG2[API Gateway 2]
AG3[API Gateway 3]
end
subgraph "Service Layer"
US1[User Service 1]
US2[User Service 2]
OS1[Order Service 1]
OS2[Order Service 2]
OS3[Order Service 3]
end
subgraph "Data Layer"
UD[(User DB)]
OD[(Order DB)]
R[(Redis)]
K[Kafka]
end
U --> LB
LB --> AG1 & AG2 & AG3
AG1 & AG2 & AG3 --> US1 & US2
AG1 & AG2 & AG3 --> OS1 & OS2 & OS3
US1 & US2 --> UD
US1 & US2 --> R
OS1 & OS2 & OS3 --> OD
OS1 & OS2 & OS3 --> K
style AG1 fill:#ccffcc
style AG2 fill:#ccffcc
style AG3 fill:#ccffcc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
| # microservices-stack.yml
version: '3.8'
services:
api-gateway:
image: myapp/api-gateway:latest
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
placement:
constraints:
- node.role == worker
ports:
- "80:8080"
networks:
- frontend
- backend
user-service:
image: myapp/user-service:latest
deploy:
replicas: 2
resources:
limits:
cpus: '0.5'
memory: 512M
networks:
- backend
environment:
- DB_HOST=user-db
- REDIS_HOST=redis
order-service:
image: myapp/order-service:latest
deploy:
replicas: 3
placement:
preferences:
- spread: node.labels.zone
networks:
- backend
environment:
- DB_HOST=order-db
- KAFKA_BROKERS=kafka:9092
user-db:
image: postgres:13
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
networks:
- backend
volumes:
- user-db-data:/var/lib/postgresql/data
order-db:
image: postgres:13
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
networks:
- backend
volumes:
- order-db-data:/var/lib/postgresql/data
redis:
image: redis:alpine
deploy:
replicas: 1
networks:
- backend
kafka:
image: confluentinc/cp-kafka:latest
deploy:
replicas: 1
networks:
- backend
environment:
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
zookeeper:
image: confluentinc/cp-zookeeper:latest
deploy:
replicas: 1
networks:
- backend
networks:
frontend:
driver: overlay
backend:
driver: overlay
internal: true
volumes:
user-db-data:
order-db-data:
|
트러블슈팅
문제 해결 체크리스트
| 문제 | 진단 명령어 | 해결 방법 |
| 🔴 서비스 시작 안됨 | docker service ps --no-trunc | 로그 확인, 이미지 검증 |
| 🟡 네트워크 통신 불가 | docker network inspect | 네트워크 재생성 |
| 🔵 노드 비정상 | docker node ls | 노드 재가입 |
| 🟣 로드 밸런싱 문제 | docker service ps | Ingress 네트워크 확인 |
| ⚫ 디스크 공간 부족 | docker system df | 클린업, 볼륨 이동 |
일반적인 문제 해결
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 노드 상태 확인
docker node ls
# 서비스가 시작되지 않을 때
docker service ps web --no-trunc
# 네트워크 문제
docker network inspect overlay-network
# 노드 제거
docker node rm --force node-name
# Swarm 모드 해제
docker swarm leave --force
|
베스트 프랙티스
Swarm 클러스터 구성 가이드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # 권장 구성
Production:
Managers: 3 or 5 (홀수)
Workers: 4+ (필요에 따라)
Development:
Managers: 1
Workers: 2+
# 노드 요구사항
Minimum:
CPU: 2 cores
RAM: 4GB
Disk: 20GB SSD
Recommended:
CPU: 4+ cores
RAM: 8GB+
Disk: 50GB+ SSD
|
프로덕션 체크리스트
- 🔒 TLS 인증서 로테이션 설정
- 📊 모니터링 스택 배포
- 💾 백업 전략 수립
- 🔄 롤링 업데이트 테스트
- 🎯 로드 밸런서 구성
- 🚨 알람 시스템 구축
마무리
Docker Swarm은 간단하면서도 강력한 오케스트레이션 도구입니다. 내장된 로드 밸런싱, 서비스 디스커버리, 롤링 업데이트 등의 기능으로 프로덕션 환경에서도 충분히 사용할 수 있습니다.
다음 편 예고
- 일반적인 Docker 문제와 해결법
- 디버깅 기법
- 성능 최적화
- 트러블슈팅 도구
Docker 문제를 현명하게 해결하는 방법을 배워봅시다! 🔧
📚 Docker 마스터하기 시리즈
🐳 기초편 (입문자용 - 5편)
- Docker란 무엇인가?
- Docker 설치 및 환경 설정
- 첫 번째 컨테이너 실행하기
- Docker 이미지 이해하기
- Dockerfile 작성하기
💼 실전편 (중급자용 - 6편)
- Docker 네트워크 기초
- Docker 볼륨과 데이터 관리
- Docker Compose 입문
- 멀티 컨테이너 애플리케이션
- Docker Hub 활용하기
- Docker 보안 베스트 프랙티스
🚀 고급편 (전문가용 - 9편)
- Docker 로그와 모니터링
- Docker로 Node.js 애플리케이션 배포
- Docker로 Python 애플리케이션 배포
- Docker로 데이터베이스 운영
- Docker 이미지 최적화
- Docker와 CI/CD
- Docker Swarm 기초 ← 현재 글
- 문제 해결과 트러블슈팅
- Docker 생태계와 미래