본문 바로가기
DevOps 스터디 - 도커 & K8S

3주차 Docker Swarm 실습

by yeongki0944 2025. 3. 30.

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