Docker Swarm 실습 가이드
1. 소개
Docker Swarm은 Docker의 네이티브 클러스터링 솔루션으로, 여러 Docker 호스트를 단일 가상 호스트로 전환하여 애플리케이션을 쉽게 확장할 수 있게 해줍니다.
2. 사전 요구사항
- Amazon Linux 2023 EC2 인스턴스
- 적절한 IAM 권한 (EC2 태그 접근 권한 필요)
- 인스턴스 간 네트워크 통신이 가능한 보안 그룹 설정
2.1. 권장 EC2 인스턴스 타입
- Manager 노드: t3.medium (2 vCPU, 4 GiB RAM) 또는 t3.small (최소 사양)
- Worker 노드: t3.small 또는 t3.micro (최소 사양)
- 스토리지: 최소 8GB EBS 볼륨 (gp3 타입 권장)
2.2. 보안 그룹 설정
Docker Swarm 통신을 위해 다음 포트를 개방해야 합니다:
- TCP 2377: 클러스터 관리 통신
- TCP/UDP 7946: 노드 간 통신
- UDP 4789: 오버레이 네트워크 트래픽
3. Docker Swarm 설정 스크립트 (설치, 초기화, 조인, 리셋)
3.1. 스크립트 개요 및 파일 목록
Docker Swarm 환경을 쉽게 구성할 수 있도록 다음 스크립트 파일들을 제공합니다. 각 스크립트는 특정 역할을 수행하며, 필요에 따라 실행하면 됩니다.
파일명 목적 실행 대상 노드
setup-docker-swarm-node.sh | Docker 설치 및 기본 설정 | 모든 노드 (Manager, Worker) |
setup-swarm-manager.sh | Swarm 클러스터 초기화 및 조인 토큰 생성 | Manager 노드 |
setup-swarm-worker.sh | Swarm 클러스터에 Worker 노드로 조인 | Worker 노드 |
reset-swarm.sh | Swarm 모드 비활성화 및 노드 분리 | 모든 노드 (필요시) |
아래는 각 스크립트의 전체 코드입니다. 스크립트를 생성할 때 아래 내용을 복사하여 사용하세요.
3.2. Docker 설치 스크립트 (setup-docker-swarm-node.sh)
이 스크립트는 Amazon Linux 2023 인스턴스에 Docker를 설치하고 기본 설정을 수행합니다. 모든 노드(Manager와 Worker 모두)에서 실행해야 합니다.
vi setup-docker-swarm-node.sh
#!/bin/bash
# Amazon Linux 2023에 Docker 설치 스크립트 (모든 노드용)
# 터미널 설정에 따라 색상 사용 여부 결정
if [ -t 1 ]; then
# 색상 정의
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
else
# 색상 없음
GREEN=''
BLUE=''
YELLOW=''
CYAN=''
NC=''
fi
echo -e "${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker 기본 설치 스크립트 - Amazon Linux 2023${NC}"
echo -e "${GREEN}============================================================${NC}"
# 목차 출력
echo -e "\n${CYAN}[스크립트 수행 작업 목차]${NC}"
echo -e "${CYAN}1. 시스템 패키지 업데이트${NC}"
echo -e "${CYAN}2. AWS CLI 설치${NC}"
echo -e "${CYAN}3. 호스트명 설정 (EC2 Name 태그 기반)${NC}"
echo -e "${CYAN}4. Docker 패키지 설치${NC}"
echo -e "${CYAN}5. Docker 서비스 시작 및 자동 시작 설정${NC}"
echo -e "${CYAN}6. 사용자를 docker 그룹에 추가${NC}"
echo -e "${CYAN}7. Docker 설치 확인${NC}"
echo -e "\n${GREEN}작업을 시작합니다...${NC}\n"
# IMDSv2 토큰 받기 - 스크립트 초반에 한 번만 생성
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# 1단계: 시스템 패키지 업데이트
echo -e "\n${GREEN}[1/7] 시스템 패키지 업데이트 중...${NC}"
sudo dnf update -y
echo -e "${GREEN}✓ 시스템 패키지 업데이트 완료${NC}"
# 2단계: AWS CLI 설치
echo -e "\n${GREEN}[2/7] AWS CLI 설치 중...${NC}"
sudo dnf install -y aws-cli
echo -e "${GREEN}✓ AWS CLI 설치 완료${NC}"
# 3단계: 호스트명 설정
echo -e "\n${GREEN}[3/7] 호스트명 설정 중...${NC}"
# 인스턴스 ID 가져오기
INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/instance-id)
# 인스턴스의 리전 가져오기
REGION=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/placement/region)
# 인스턴스의 Name 태그 가져오기
INSTANCE_NAME=$(aws ec2 describe-tags --region $REGION --filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Name" --query "Tags[0].Value" --output text)
# 만약 Name 태그가 없다면 인스턴스 ID를 hostname으로 사용
if [ -z "$INSTANCE_NAME" ] || [ "$INSTANCE_NAME" == "None" ]; then
INSTANCE_NAME=$INSTANCE_ID
fi
# hostname 설정
sudo hostnamectl set-hostname $INSTANCE_NAME
# hostname을 /etc/hosts 파일에 추가
echo "127.0.0.1 $INSTANCE_NAME" | sudo tee -a /etc/hosts
echo -e "${GREEN}✓ 호스트명이 '$INSTANCE_NAME'으로 설정되었습니다${NC}"
# 4단계: Docker 패키지 설치
echo -e "\n${GREEN}[4/7] Docker 패키지 설치 중...${NC}"
sudo dnf install -y docker
echo -e "${GREEN}✓ Docker 패키지 설치 완료${NC}"
# 5단계: Docker 서비스 시작 및 부팅 시 자동 시작 설정
echo -e "\n${GREEN}[5/7] Docker 서비스 시작 및 자동 시작 설정 중...${NC}"
sudo systemctl start docker
sudo systemctl enable docker
echo -e "${GREEN}✓ Docker 서비스 시작 및 자동 시작 설정 완료${NC}"
# 6단계: 사용자를 docker 그룹에 추가
echo -e "\n${GREEN}[6/7] 사용자를 docker 그룹에 추가 중...${NC}"
sudo usermod -aG docker $USER
# 현재 세션에 docker 그룹 권한 적용
if ! groups $USER | grep -q docker; then
echo "docker 그룹 권한을 현재 세션에 적용합니다..."
exec sg docker -c "bash -c 'cd $(pwd) && $0'"
exit 0
fi
echo -e "${GREEN}✓ 사용자를 docker 그룹에 추가 완료 (현재 세션에 적용됨)${NC}"
# 7단계: Docker 설치 확인
echo -e "\n${GREEN}[7/7] Docker 설치 확인 중...${NC}"
docker --version
docker info | grep "Swarm:" | awk '{print $2}'
echo -e "${GREEN}✓ Docker 설치 확인 완료${NC}"
echo -e "\n${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker 기본 설치가 성공적으로 완료되었습니다!${NC}"
echo -e "${BLUE}Manager 노드는 이제 'setup-swarm-manager.sh' 스크립트를 실행하세요.${NC}"
echo -e "${BLUE}Worker 노드는 Manager에서 생성된 조인 토큰으로 Swarm에 참여하세요.${NC}"
echo -e "${GREEN}============================================================${NC}"
chmod +x setup-docker-swarm-node.sh
./setup-docker-swarm-node.sh
3.3. Swarm Manager 초기화 스크립트 (setup-swarm-manager.sh)
이 스크립트는 Manager 노드에서 Docker Swarm을 초기화하고 Worker 및 Manager 조인 토큰을 생성합니다.
vi setup-swarm-manager.sh
#!/bin/bash
# Docker Swarm Manager 초기화 스크립트 (Manager 노드용)
# 터미널 설정에 따라 색상 사용 여부 결정
if [ -t 1 ]; then
# 색상 정의
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
RED='\033[0;31m'
NC='\033[0m' # No Color
else
# 색상 없음
GREEN=''
BLUE=''
YELLOW=''
CYAN=''
RED=''
NC=''
fi
echo -e "${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker Swarm Manager 초기화 스크립트${NC}"
echo -e "${GREEN}============================================================${NC}"
# 목차 출력
echo -e "\n${CYAN}[스크립트 수행 작업 목차]${NC}"
echo -e "${CYAN}1. Docker Swarm 상태 확인${NC}"
echo -e "${CYAN}2. Docker Swarm 초기화${NC}"
echo -e "${CYAN}3. Worker 노드 조인 토큰 생성 및 저장${NC}"
echo -e "${CYAN}4. Manager 노드 조인 토큰 생성 및 저장${NC}"
echo -e "\n${GREEN}작업을 시작합니다...${NC}\n"
# 1단계: Docker Swarm 상태 확인
echo -e "\n${GREEN}[1/4] Docker Swarm 상태 확인 중...${NC}"
SWARM_STATUS=$(docker info | grep "Swarm:" | awk '{print $2}')
echo -e "현재 Swarm 상태: ${YELLOW}$SWARM_STATUS${NC}"
if [ "$SWARM_STATUS" == "active" ]; then
echo -e "${RED}이 노드는 이미 Swarm 모드가 활성화되어 있습니다.${NC}"
echo -e "${YELLOW}기존 Swarm 설정을 유지하려면 스크립트를 종료하세요.${NC}"
read -p "기존 Swarm을 초기화하고 새로 설정하시겠습니까? (y/n): " RESET_SWARM
if [[ "$RESET_SWARM" != "y" && "$RESET_SWARM" != "Y" ]]; then
echo -e "${GREEN}스크립트를 종료합니다. 기존 Swarm 설정이 유지됩니다.${NC}"
exit 0
else
echo -e "${YELLOW}기존 Swarm을 초기화하고 새로 설정합니다...${NC}"
docker swarm leave --force
fi
fi
# 2단계: Docker Swarm 초기화
echo -e "\n${GREEN}[2/4] Docker Swarm 초기화 중...${NC}"
# IMDSv2 토큰 받기
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# 프라이빗 IP 가져오기
PRIVATE_IP=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/local-ipv4)
# IP가 제대로 가져와졌는지 확인
if [ -z "$PRIVATE_IP" ]; then
echo -e "${YELLOW}프라이빗 IP를 가져오는데 실패했습니다. 다른 방법으로 시도합니다...${NC}"
PRIVATE_IP=$(hostname -I | awk '{print $1}')
fi
echo -e "Swarm 초기화에 사용할 IP 주소: ${YELLOW}$PRIVATE_IP${NC}"
# Swarm 초기화
docker swarm init --advertise-addr $PRIVATE_IP
# Swarm 초기화 성공 여부 확인
if [ $? -ne 0 ]; then
echo -e "${RED}Swarm 초기화에 실패했습니다. 오류를 확인하세요.${NC}"
exit 1
fi
echo -e "${GREEN}✓ Docker Swarm이 성공적으로 초기화되었습니다${NC}"
# 현재 시간 가져오기
CURRENT_DATE=$(date +"%Y%m%d-%H%M")
EXPIRE_DATE=$(date -d "+24 hours" +"%Y%m%d-%H%M")
# 토큰 디렉토리 설정
TOKEN_DIR="./swarm-tokens"
# 기존 토큰 디렉토리가 있는지 확인하고 처리
if [ -d "$TOKEN_DIR" ]; then
echo -e "${YELLOW}기존 토큰 디렉토리가 존재합니다: $TOKEN_DIR${NC}"
echo -e "${YELLOW}이 디렉토리에는 이전 토큰 정보가 포함되어 있을 수 있습니다.${NC}"
read -p "기존 디렉토리를 삭제하고 새로 생성하시겠습니까? (y/n): " DELETE_DIR
if [[ "$DELETE_DIR" == "y" || "$DELETE_DIR" == "Y" ]]; then
echo -e "${YELLOW}기존 토큰 디렉토리를 삭제합니다...${NC}"
rm -rf $TOKEN_DIR
echo -e "${GREEN}✓ 기존 토큰 디렉토리가 삭제되었습니다${NC}"
else
echo -e "${YELLOW}기존 토큰 디렉토리를 유지합니다. 새 토큰 파일이 추가됩니다.${NC}"
fi
fi
# 토큰 디렉토리 생성 (존재하지 않는 경우에만 생성됨)
mkdir -p $TOKEN_DIR
echo -e "토큰 저장 디렉토리: ${YELLOW}$TOKEN_DIR${NC}"
# 3단계: Worker 노드 조인 토큰 생성 및 저장
echo -e "\n${GREEN}[3/4] Worker 노드 조인 토큰 생성 및 저장 중...${NC}"
WORKER_TOKEN=$(docker swarm join-token worker -q)
WORKER_JOIN_CMD=$(docker swarm join-token worker | grep "docker swarm join")
# 토큰과 조인 명령어를 파일로 저장
WORKER_TOKEN_FILE="$TOKEN_DIR/worker-token-$CURRENT_DATE-to-$EXPIRE_DATE.txt"
echo "===== Docker Swarm Worker 노드 조인 정보 =====" > $WORKER_TOKEN_FILE
echo "생성 일시: $(date)" >> $WORKER_TOKEN_FILE
echo "만료 예정: $(date -d "+24 hours")" >> $WORKER_TOKEN_FILE
echo "Worker 토큰: $WORKER_TOKEN" >> $WORKER_TOKEN_FILE
echo "" >> $WORKER_TOKEN_FILE
echo "조인 명령어:" >> $WORKER_TOKEN_FILE
echo "$WORKER_JOIN_CMD" >> $WORKER_TOKEN_FILE
echo -e "${GREEN}✓ Worker 노드 조인 토큰이 생성되어 $WORKER_TOKEN_FILE 에 저장되었습니다${NC}"
ls -la $WORKER_TOKEN_FILE
# 4단계: Manager 노드 조인 토큰 생성 및 저장
echo -e "\n${GREEN}[4/4] Manager 노드 조인 토큰 생성 및 저장 중...${NC}"
MANAGER_TOKEN=$(docker swarm join-token manager -q)
MANAGER_JOIN_CMD=$(docker swarm join-token manager | grep "docker swarm join")
# 토큰과 조인 명령어를 파일로 저장
MANAGER_TOKEN_FILE="$TOKEN_DIR/manager-token-$CURRENT_DATE-to-$EXPIRE_DATE.txt"
echo "===== Docker Swarm Manager 노드 조인 정보 =====" > $MANAGER_TOKEN_FILE
echo "생성 일시: $(date)" >> $MANAGER_TOKEN_FILE
echo "만료 예정: $(date -d "+24 hours")" >> $MANAGER_TOKEN_FILE
echo "Manager 토큰: $MANAGER_TOKEN" >> $MANAGER_TOKEN_FILE
echo "" >> $MANAGER_TOKEN_FILE
echo "조인 명령어:" >> $MANAGER_TOKEN_FILE
echo "$MANAGER_JOIN_CMD" >> $MANAGER_TOKEN_FILE
echo -e "${GREEN}✓ Manager 노드 조인 토큰이 생성되어 $MANAGER_TOKEN_FILE 에 저장되었습니다${NC}"
ls -la $MANAGER_TOKEN_FILE
# 요약 정보 출력
echo -e "\n${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker Swarm Manager 초기화가 성공적으로 완료되었습니다!${NC}"
echo -e "${GREEN}============================================================${NC}"
echo -e "${YELLOW}Worker 노드 조인 명령어:${NC}"
echo -e "$WORKER_JOIN_CMD"
echo -e "\n${YELLOW}Manager 노드 조인 명령어:${NC}"
echo -e "$MANAGER_JOIN_CMD"
echo -e "\n${BLUE}토큰 정보는 다음 위치에 저장되었습니다:${NC}"
echo -e "Worker 토큰: ${CYAN}$WORKER_TOKEN_FILE${NC}"
echo -e "Manager 토큰: ${CYAN}$MANAGER_TOKEN_FILE${NC}"
echo -e "${BLUE}토큰은 24시간 동안 유효합니다.${NC}"
echo -e "${GREEN}============================================================${NC}"
chmod +x setup-swarm-manager.sh
./setup-swarm-manager.sh
3.4. Worker 노드 조인 스크립트 (setup-swarm-worker.sh)
이 스크립트는 Worker 노드에서 Docker Swarm 클러스터에 조인하기 위해 사용합니다.
vi setup-swarm-worker.sh
#!/bin/bash
# Docker Swarm Worker 노드 조인 스크립트
# 터미널 설정에 따라 색상 사용 여부 결정
if [ -t 1 ]; then
# 색상 정의
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
RED='\033[0;31m'
NC='\033[0m' # No Color
else
# 색상 없음
GREEN=''
BLUE=''
YELLOW=''
CYAN=''
RED=''
NC=''
fi
echo -e "${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker Swarm Worker 노드 조인 스크립트${NC}"
echo -e "${GREEN}============================================================${NC}"
# 목차 출력
echo -e "\n${CYAN}[스크립트 수행 작업 목차]${NC}"
echo -e "${CYAN}1. Docker Swarm 상태 확인${NC}"
echo -e "${CYAN}2. Docker Swarm 클러스터 조인${NC}"
echo -e "\n${GREEN}작업을 시작합니다...${NC}\n"
# 1단계: Docker Swarm 상태 확인
echo -e "\n${GREEN}[1/2] Docker Swarm 상태 확인 중...${NC}"
SWARM_STATUS=$(docker info | grep "Swarm:" | awk '{print $2}')
echo -e "현재 Swarm 상태: ${YELLOW}$SWARM_STATUS${NC}"
if [ "$SWARM_STATUS" == "active" ]; then
echo -e "${RED}이 노드는 이미 Swarm 모드가 활성화되어 있습니다.${NC}"
# 노드 역할 확인
IS_MANAGER=$(docker info | grep "Is Manager:" | awk '{print $3}')
if [ "$IS_MANAGER" == "true" ]; then
echo -e "${YELLOW}이 노드는 현재 Manager 역할로 구성되어 있습니다.${NC}"
echo -e "${YELLOW}Manager 노드를 떠나려면 --force 옵션이 필요합니다.${NC}"
fi
echo -e "${YELLOW}기존 Swarm 설정을 유지하려면 스크립트를 종료하세요.${NC}"
read -p "기존 Swarm에서 나가고 새로 조인하시겠습니까? (y/n): " RESET_SWARM
if [[ "$RESET_SWARM" != "y" && "$RESET_SWARM" != "Y" ]]; then
echo -e "${GREEN}스크립트를 종료합니다. 기존 Swarm 설정이 유지됩니다.${NC}"
exit 0
else
echo -e "${YELLOW}기존 Swarm에서 나가고 새로 조인합니다...${NC}"
# 노드 역할에 따라 적절한 leave 명령 실행
if [ "$IS_MANAGER" == "true" ]; then
echo -e "${YELLOW}Manager 노드를 강제로 제거합니다...${NC}"
docker swarm leave --force
else
echo -e "${YELLOW}Worker 노드를 제거합니다...${NC}"
docker swarm leave
fi
# leave 명령 성공 여부 확인
if [ $? -ne 0 ]; then
echo -e "${RED}Swarm 떠나기에 실패했습니다. 수동으로 'docker swarm leave --force' 명령을 실행한 후 다시 시도하세요.${NC}"
exit 1
fi
# Swarm 상태 재확인
SWARM_STATUS=$(docker info | grep "Swarm:" | awk '{print $2}')
if [ "$SWARM_STATUS" == "active" ]; then
echo -e "${RED}Swarm을 떠나는 데 실패했습니다. 수동으로 확인이 필요합니다.${NC}"
exit 1
else
echo -e "${GREEN}✓ Swarm을 성공적으로 떠났습니다.${NC}"
fi
fi
fi
# 2단계: Docker Swarm 클러스터 조인
echo -e "\n${GREEN}[2/2] Docker Swarm 클러스터 조인 중...${NC}"
# 조인 토큰 입력 받기
read -p "Manager에서 제공한 전체 조인 명령어를 입력하세요: " JOIN_CMD
# 조인 명령어 확인
if [[ $JOIN_CMD != *"docker swarm join"* ]]; then
echo -e "${RED}유효한 조인 명령어가 아닙니다. 'docker swarm join'으로 시작하는 명령어를 입력하세요.${NC}"
exit 1
fi
# 명령어 실행
echo -e "${YELLOW}다음 명령어를 실행합니다: $JOIN_CMD${NC}"
eval $JOIN_CMD
# 조인 성공 여부 확인
if [ $? -ne 0 ]; then
echo -e "${RED}Swarm 클러스터 조인에 실패했습니다. 오류를 확인하세요.${NC}"
exit 1
fi
# Swarm 상태 재확인
NEW_SWARM_STATUS=$(docker info | grep "Swarm:" | awk '{print $2}')
NODE_ROLE=$(docker info | grep "Is Manager:" | awk '{print $3}')
echo -e "${GREEN}✓ Docker Swarm 클러스터 조인이 성공적으로 완료되었습니다${NC}"
echo -e "현재 Swarm 상태: ${YELLOW}$NEW_SWARM_STATUS${NC}"
if [ "$NODE_ROLE" == "true" ]; then
echo -e "노드 역할: ${YELLOW}Manager${NC}"
else
echo -e "노드 역할: ${YELLOW}Worker${NC}"
fi
echo -e "\n${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker Swarm Worker 노드 설정이 성공적으로 완료되었습니다!${NC}"
echo -e "${GREEN}============================================================${NC}"
chmod +x setup-swarm-worker.sh
./setup-swarm-worker.sh
3.5. Swarm 초기화 취소 스크립트 (reset-swarm.sh)
이 스크립트는 Docker Swarm 모드를 비활성화하기 위해 사용합니다.
vi reset-swarm.sh
#!/bin/bash
# Docker Swarm 모드 초기화 취소 스크립트
# 터미널 설정에 따라 색상 사용 여부 결정
if [ -t 1 ]; then
# 색상 정의
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
RED='\033[0;31m'
NC='\033[0m' # No Color
else
# 색상 없음
GREEN=''
BLUE=''
YELLOW=''
CYAN=''
RED=''
NC=''
fi
echo -e "${GREEN}============================================================${NC}"
echo -e "${RED}Docker Swarm 모드 초기화 취소 스크립트${NC}"
echo -e "${GREEN}============================================================${NC}"
# 1단계: Docker Swarm 상태 확인
echo -e "\n${GREEN}[1/3] Docker Swarm 상태 확인 중...${NC}"
SWARM_STATUS=$(docker info | grep "Swarm:" | awk '{print $2}')
echo -e "현재 Swarm 상태: ${YELLOW}$SWARM_STATUS${NC}"
if [ "$SWARM_STATUS" != "active" ]; then
echo -e "${YELLOW}Swarm 모드가 이미 비활성화되어 있습니다. 추가 작업이 필요하지 않습니다.${NC}"
exit 0
fi
# 2단계: 노드 역할 확인
echo -e "\n${GREEN}[2/3] 노드 역할 확인 중...${NC}"
IS_MANAGER=$(docker info | grep "Is Manager:" | awk '{print $3}')
if [ "$IS_MANAGER" == "true" ]; then
echo -e "현재 노드 역할: ${YELLOW}Manager${NC}"
# 매니저 노드 수 확인
MANAGER_COUNT=$(docker node ls --filter "role=manager" | grep -c "Ready")
if [ "$MANAGER_COUNT" -eq 1 ]; then
echo -e "${RED}경고: 이 노드는 클러스터의 유일한 Manager입니다!${NC}"
echo -e "${RED}이 노드를 제거하면 전체 클러스터가 파괴되며 복구가 불가능합니다.${NC}"
else
echo -e "${YELLOW}주의: Manager 노드를 제거하면 클러스터 관리가 일부 제한될 수 있습니다.${NC}"
echo -e "${YELLOW} 현재 클러스터에는 총 $MANAGER_COUNT 개의 Manager가 있습니다.${NC}"
fi
else
echo -e "현재 노드 역할: ${YELLOW}Worker${NC}"
fi
# 확인 요청
read -p "정말로 이 노드를 Swarm에서 제거하고 Swarm 모드를 비활성화하시겠습니까? (y/n): " CONFIRM
if [[ "$CONFIRM" != "y" && "$CONFIRM" != "Y" ]]; then
echo -e "${GREEN}스크립트를 종료합니다. Swarm 설정이 유지됩니다.${NC}"
exit 0
fi
# 3단계: Swarm 모드 비활성화
echo -e "\n${GREEN}[3/3] Swarm 모드 비활성화 중...${NC}"
if [ "$IS_MANAGER" == "true" ]; then
echo -e "${YELLOW}Manager 노드를 강제로 제거합니다...${NC}"
docker swarm leave --force
else
echo -e "${YELLOW}Worker 노드를 제거합니다...${NC}"
docker swarm leave
fi
# 결과 확인
if [ $? -ne 0 ]; then
echo -e "${RED}Swarm 모드 비활성화에 실패했습니다. 오류를 확인하세요.${NC}"
echo -e "${YELLOW}수동으로 'docker swarm leave --force' 명령을 실행해보세요.${NC}"
exit 1
fi
# Swarm 상태 재확인
NEW_SWARM_STATUS=$(docker info | grep "Swarm:" | awk '{print $2}')
if [ "$NEW_SWARM_STATUS" == "active" ]; then
echo -e "${RED}Swarm 모드 비활성화에 실패했습니다.${NC}"
echo -e "${YELLOW}Docker 데몬을 다시 시작해보세요: 'sudo systemctl restart docker'${NC}"
exit 1
fi
echo -e "현재 Swarm 상태: ${YELLOW}$NEW_SWARM_STATUS${NC}"
echo -e "${GREEN}✓ Swarm 모드가 성공적으로 비활성화되었습니다${NC}"
echo -e "\n${GREEN}============================================================${NC}"
echo -e "${BLUE}Docker Swarm 모드가 성공적으로 비활성화되었습니다!${NC}"
echo -e "${GREEN}============================================================${NC}"
chmod +x reset-swarm.sh
./reset-swarm.sh
4. 기본 Docker Swarm 명령어
4.1. Swarm 초기화 및 관리
Swarm 상태 확인:
docker info | grep Swarm
Swarm 모드 초기화하기 (Manager 노드에서):
docker swarm init --advertise-addr <Manager IP>
Worker 노드 조인 토큰 생성:
docker swarm join-token worker
Manager 노드 조인 토큰 생성:
docker swarm join-token manager
Swarm 떠나기 (Worker 노드에서):
docker swarm leave
Swarm 떠나기 (Manager 노드에서):
docker swarm leave --force
4.2. 노드 관리
노드 목록 보기:
docker node ls
쉘 변수로 워커 노드 ID 저장하기
WORKER_NODE_ID=gscjt15xvt545yfs07ysoimb5
특정 노드 상세 정보 보기:
docker node inspect $WORKER_NODE_ID
노드 역할 변경 (Worker -> Manager):
docker node promote $WORKER_NODE_ID
노드 역할 변경 (Manager -> Worker):
docker node demote $WORKER_NODE_ID
노드 가용성 변경 (drain: 컨테이너 배포 불가):
docker node update --availability drain $WORKER_NODE_ID
노드 가용성 변경 (active: 컨테이너 배포 가능):
docker node update --availability active $WORKER_NODE_ID
노드에 라벨 추가:
docker node update --label-add environment=production $WORKER_NODE_ID
노드 라벨 조회:
# 노드의 모든 정보 확인(라벨 포함)
docker node inspect $WORKER_NODE_ID
# 라벨만 추출하여 조회
docker node inspect $WORKER_NODE_ID --format '{{ .Spec.Labels }}'
# grep으로 라벨 부분만 추출
docker node inspect $WORKER_NODE_ID | grep Labels -A5
4.3. 서비스 배포 및 관리
기본 서비스 명령어
서비스 생성하기:
docker service create --name <서비스명> --replicas <복제본수> <이미지명>
서비스 목록 보기:
docker service ls
서비스 상세 정보 보기:
docker service inspect <서비스명>
서비스의 태스크(컨테이너) 목록 보기:
docker service ps <서비스명>
서비스 확장하기 (복제본 수 조절):
docker service scale <서비스명>=<복제본수>
서비스 업데이트 (이미지 변경):
docker service update --image <새 이미지> <서비스명>
서비스 삭제하기:
docker service rm <서비스명>
실제 Nginx 웹 서비스 배포 및 테스트
Nginx 웹 서버 서비스 배포:
# 포트 80을 외부에 노출하는 Nginx 서비스 생성 (3개 복제본)
docker service create --name webserver \
--replicas 3 \
--publish published=80,target=80 \
nginx:latest
서비스 상태 확인:
# 서비스 목록 확인
docker service ls
# 서비스 상세 정보 확인
docker service inspect webserver
# 서비스 태스크(컨테이너) 상태 확인
docker service ps webserver
서비스 접속 테스트 (Manager 노드에서):
# curl로 웹 서버 접속 테스트
curl http://localhost:80
# 또는 간단히
curl localhost
# 응답 헤더 확인
curl -I localhost
# 접속 반복 테스트 (부하 분산 확인)
for i in {1..10}; do curl -s localhost | grep -o "<title>.*</title>"; sleep 1; done
서비스 스케일링:
# 서비스 복제본 수 조정 (5개로 증가)
docker service scale webserver=5
# 스케일링 결과 확인
docker service ps webserver
서비스 업데이트:
# 서비스 이미지 변경 (httpd로 변경)
docker service update --image httpd:latest webserver
# 업데이트 상태 확인
docker service ps webserver
시각화 도구 배포 (선택사항):
# Docker Swarm 시각화 도구 배포
docker service create \
--name=visualizer \
--publish=8080:8080 \
--constraint=node.role==manager \
--mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
dockersamples/visualizer
# 접속 테스트
curl localhost:8080
# 또는 웹 브라우저에서 http://<manager-ip>:8080 접속
4.4. 네트워크 관리
네트워크 변수 설정
# 네트워크 이름 변수 저장
OVERLAY_NETWORK=my-overlay-net
오버레이 네트워크 생성:
# 기본 오버레이 네트워크 생성
docker network create --driver overlay $OVERLAY_NETWORK
암호화된 오버레이 네트워크 생성:
# 암호화된 오버레이 네트워크 생성
docker network create --driver overlay --opt encrypted ${OVERLAY_NETWORK}-secure
네트워크 목록 보기:
docker network ls | grep overlay
특정 네트워크 상세 정보 보기:
docker network inspect $OVERLAY_NETWORK
서비스를 특정 네트워크에 연결:
# 생성된 오버레이 네트워크를 사용하는 웹 서비스 배포
docker service create --name webapp \
--network $OVERLAY_NETWORK \
--replicas 3 \
nginx:latest
멀티 네트워크 서비스 예제
# 프론트엔드 네트워크 생성
docker network create --driver overlay frontend
# 백엔드 네트워크 생성
docker network create --driver overlay backend
# 프론트엔드와 백엔드 네트워크에 모두 연결된 API 서비스 생성
docker service create --name api-gateway \
--network frontend \
--network backend \
--replicas 3 \
nginx:latest
# 네트워크 연결 확인
docker service inspect api-gateway --format '{{.Spec.TaskTemplate.Networks}}'
5. 고급 Docker Swarm 기능
5.1. 스택 배포 (Compose 파일 사용)
샘플 compose 파일 생성:
# 샘플 docker-compose.yml 파일 생성
cat > docker-compose.yml << 'EOL'
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "80:80"
deploy:
replicas: 2
visualizer:
image: dockersamples/visualizer
ports:
- "8080:8080"
deploy:
placement:
constraints: [node.role == manager]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
EOL
# 파일 확인
cat docker-compose.yml
스택 배포하기:
# my-stack이라는 이름으로 스택 배포
docker stack deploy -c docker-compose.yml my-stack
스택 목록 보기:
docker stack ls
스택의 서비스 목록 보기:
docker stack services my-stack
스택의 태스크 목록 보기:
docker stack ps my-stack
접속 테스트:
# 웹 서비스 접속 테스트
curl localhost
# 시각화 도구 접속 테스트
curl localhost:8080
스택 삭제하기:
docker stack rm my-stack
5.2. 비밀 데이터(Secret) 관리
비밀 데이터 파일 생성 및 저장:
# 비밀 데이터 파일 생성
echo "MySecretPassword123!" > db_password.txt
# 비밀 데이터 생성
docker secret create db_password db_password.txt
# 생성 후 로컬 파일 제거 (보안)
rm db_password.txt
비밀 데이터 목록 보기:
docker secret ls
비밀 데이터 상세 정보 보기:
docker secret inspect db_password
서비스 생성 시 비밀 데이터 사용:
# 비밀 데이터를 환경 변수로 노출
docker service create \
--name mysql-db \
--secret source=db_password,target=mysql_root_password \
--env MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password \
mysql:8.0
# 서비스 상태 확인
docker service ps mysql-db
5.3. 설정 데이터(Config) 관리
설정 데이터 파일 생성:
# Nginx 설정 파일 생성
cat > nginx.conf << 'EOL'
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
add_header Content-Type text/plain;
return 200 'Hello from Docker Swarm! Config works!\n';
}
}
EOL
# 설정 파일 확인
cat nginx.conf
설정 데이터 생성:
docker config create nginx_config nginx.conf
설정 데이터 목록 보기:
docker config ls
설정 데이터 상세 정보 보기:
docker config inspect nginx_config
서비스 생성 시 설정 데이터 사용:
# 설정 파일을 사용하는 Nginx 서비스 생성
docker service create \
--name web-with-config \
--config source=nginx_config,target=/etc/nginx/conf.d/default.conf \
--publish 8000:80 \
nginx:latest
# 서비스 상태 확인
docker service ps web-with-config
# 접속 테스트
curl localhost:8000
5.4. 업데이트 및 롤백 전략
롤백 기능이 있는 서비스 생성:
# 롤백 및 업데이트 전략이 정의된 서비스 생성
docker service create \
--name webapp-rollback \
--replicas 4 \
--publish 8001:80 \
--update-parallelism 2 \
--update-delay 10s \
--update-failure-action rollback \
--rollback-parallelism 2 \
--rollback-delay 5s \
nginx:1.20
# 서비스 상태 확인
docker service ps webapp-rollback
업데이트 병렬처리와 지연시간 설정:
# 서비스 업데이트 (성공 케이스)
docker service update \
--image nginx:1.21 \
--update-parallelism 2 \
--update-delay 10s \
webapp-rollback
# 업데이트 진행 관찰
watch docker service ps webapp-rollback
실패 시 자동 롤백 테스트:
# 존재하지 않는 이미지로 업데이트 (실패 케이스)
docker service update \
--image nginx:invalid-tag \
webapp-rollback
# 롤백 진행 관찰
watch docker service ps webapp-rollback
수동 롤백 실행:
# 수동으로 롤백 실행
docker service update --rollback webapp-rollback
# 롤백 결과 확인
docker service ps webapp-rollback