상세 컨텐츠

본문 제목

25.04.01. Docker Swarm && Kubenetes

AWS CLOUD SCHOOL 9기

by AI Engineer crystal 2025. 4. 1. 17:51

본문

Swarm 클러스터에서 외부 볼륨 (Bind Mount: NFS)을 이용한 Persistent Volume 사용하기

목표: Docker Swarm 클러스터에서 NFS를 활용하여 영속적인 데이터 저장소를 제공하고, CI/CD 도구(Jenkins 또는 GitLab)을 통해 자동화된 배포 환경을 설정하여 개발자가 GitHub 또는 GitLab에 푸시한 코드를 자동으로 배포하는 시스템을 구성합니다.

1. Swarm 클러스터에서 NFS 외부 볼륨 사용

NFS 서버 설정:

  • NFS 서버를 설정하여 Swarm 클러스터 노드들 간에 데이터를 공유할 수 있게 합니다.
  • NFS 서버를 설치하고, 공유 디렉토리를 설정합니다.
  • NFS 서버 설정:
    • 공유할 디렉토리 설정: /mnt/nfs_share
    • exports 파일 수정:
    • /mnt/nfs_share *(rw,sync,no_subtree_check)
  • NFS 서버를 실행하고 모든 Swarm 노드에서 NFS 클라이언트를 설치합니다.
    • 클라이언트 설치: sudo apt install nfs-common
    • NFS 공유 디렉토리 마운트:
    • sudo mount -t nfs <NFS_SERVER_IP>:/mnt/nfs_share /mnt/nfs_share

Swarm 서비스에서 외부 볼륨 설정:

  • Docker Compose 파일 예시 (Swarm 서비스 배포):
version: '3.7'

services:
  app:
    image: nginx
    deploy:
      replicas: 3
    volumes:
      - nfs-volume:/usr/share/nginx/html

volumes:
  nfs-volume:
    driver: local
    driver_opts:
      type: nfs
      o: addr=<NFS_SERVER_IP>,nolock,soft,rw
      device: ":/mnt/nfs_share"
  • nfs-volume을 정의하고 driver_opts를 통해 NFS 서버를 마운트합니다.

배포:

  • 위 파일을 사용하여 Swarm 클러스터에 서비스를 배포합니다:
  • docker stack deploy -c docker-compose.yml my_stack

2. CI/CD (Jenkins 또는 GitLab CI/CD) 설정

2.1 Jenkins를 이용한 CI/CD

  • Jenkins 설치: Jenkins를 Swarm 클러스터의 하나의 노드에 설치하거나 Docker로 실행합니다.
  • GitHub/GitLab 연동: GitHub 또는 GitLab 저장소와 Jenkins를 연결하여 소스 코드 변경을 감지하고, 이를 트리거하여 자동 빌드 및 배포합니다.

Jenkins 파이프라인 예시 (Jenkinsfile):

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                git '<https://github.com/your/repository.git>'
            }
        }

        stage('Build') {
            steps {
                sh 'docker build -t your-image:latest .'
            }
        }

        stage('Push') {
            steps {
                sh 'docker push your-image:latest'
            }
        }

        stage('Deploy') {
            steps {
                sh 'docker stack deploy -c docker-compose.yml your_stack'
            }
        }
    }
}
  • 설명:
    1. GitHub에서 코드 클론
    2. Docker 이미지를 빌드
    3. 이미지를 Docker Registry에 푸시
    4. Swarm 클러스터에 서비스 배포

2.2 GitLab CI/CD 설정

  • GitLab에서 GitLab Runner를 설정하여 CI/CD 파이프라인을 구성합니다.
  • GitLab Runner는 Docker 환경에서 컨테이너를 사용하여 파이프라인을 실행할 수 있습니다.

.gitlab-ci.yml 예시:

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - docker build -t your-image:latest .
    - docker push your-image:latest

deploy:
  stage: deploy
  script:
    - docker stack deploy -c docker-compose.yml your_stack
  • 설명:
    1. GitLab에 푸시된 코드로 Docker 이미지를 빌드하고 푸시
    2. Swarm 클러스터에 자동 배포

3. GitHub/GitLab 저장소 연동 및 자동 배포

  • GitHub 연동:
    1. Webhook: GitHub에 푸시 이벤트를 트리거하여 Jenkins 또는 GitLab CI/CD가 자동으로 실행되도록 설정합니다.
    2. Jenkins 또는 GitLab Runner는 소스 코드를 클론하고, 이를 빌드하여 Docker 이미지를 생성하고 푸시합니다.
    3. 푸시된 이미지는 Swarm 클러스터에 배포됩니다.
  • GitLab 연동:
    1. GitLab은 자체 CI/CD를 제공하며, .gitlab-ci.yml 파일을 기반으로 자동 빌드 및 배포가 이루어집니다.
    2. GitLab에서 푸시된 코드가 GitLab Runner를 통해 Jenkins와 유사한 방식으로 처리됩니다.

4. 자동화된 배포 및 관리

  • 자동 배포:
    • GitHub/GitLab에 푸시된 코드가 Jenkins 또는 GitLab CI/CD를 통해 자동으로 배포됩니다.
    • Swarm 클러스터에서 서비스가 자동으로 업데이트됩니다.
  • 영속적 저장소:
    • NFS를 활용한 Persistent Volume으로 서비스가 중단되더라도 데이터는 안전하게 유지됩니다.

결론

이 구성은 Swarm 클러스터에서 NFS 기반 Persistent Volume을 사용하여 데이터를 안전하게 유지하고, Jenkins 또는 GitLab CI/CD를 이용해 개발자가 GitHub/GitLab에 푸시한 코드를 자동으로 클러스터에 배포하는 완전한 자동화된 개발/배포 환경을 만듭니다. 이는 코드 변경이 발생하면 즉시 빌드 및 배포가 이루어져 CI/CD 파이프라인을 효율적으로 자동화할 수 있습니다.


복습

고가용성을 위한 Docker Compose 사용 시, yml 파일을 이용해 하나의 서버에서 두 개의 컨테이너를 실행할 수 있습니다. 하지만, 하나의 호스트 포트를 두 개의 컨테이너에 연결할 수 없기 때문에 각 컨테이너는 다른 포트를 사용하여 접속하게 됩니다.

서버를 2개 이상 사용할 경우, 각 서버는 독립된 리소스를 사용할 수 있는 장점이 있지만, IP가 다르더라도 동일한 포트를 사용할 수 있다는 점이 장점입니다. 이때 **NFS(Network File System)**를 사용해 마운트 및 구성을 각각 해야 합니다.

클러스터를 사용하면 여러 서버에서 컨테이너, 네트워크, 볼륨을 일괄적으로 관리할 수 있습니다. 이를 위해 컨테이너 오케스트레이션 툴을 사용하게 되며, 주요 툴로는 **쿠버네티스(Kubernetes)**와 **도커 스웜(Docker Swarm)**이 있습니다.

쿠버네티스

사용 방법에 따라 세 가지로 나눌 수 있습니다:

  1. 구성형: kubeadm, kubespray 등
  2. 설치형: Rancher, OpenShift (RedHat 계열)
  3. 관리형: 클라우드 서비스 제공자(CSP)에서 제공하는 관리형 서비스로, EKS(AWS), GKE(Google Cloud), AKS(Azure), NKS(Nutanix) 등이 있습니다.

이러한 툴을 통해 고가용성 환경을 구축하고 관리할 수 있습니다.

 

  • Pod는 Kubernetes에서 하나 이상의 컨테이너를 포함하며, 이 컨테이너들은 네트워크와 볼륨을 공유합니다.
  • 같은 Pod 내의 컨테이너는 밀접하게 연관된 작업을 수행하는 경우가 많습니다.

도커 스웜

**매니저(Manager)**와 워커(Worker) 노드로 구성됩니다. 이들 각각은 토큰을 가지고 있으며, 워커는 매니저에게 조인하여 매니저에 의해 관리됩니다. 도커 스웜은 클러스터 내에서 컨테이너의 네트워크를 일괄적으로 관리합니다.

주요 특징:

  1. 도커 네트워크:
    • 기존의 docker0와 달리, 도커 스웜에서는 docker gwbridge가 생성됩니다.
    • docker gwbridge는 로컬 스코프로 동작합니다.
    • 인그레스 네트워크가 생성되며, 이는 오버레이(overlay) 드라이버를 사용하여 스웜 스코프로 동작합니다. 즉, 클러스터 내에서만 사용됩니다.
  2. 네트워크 흐름:
    • 외부 사용자는 물리적 인터페이스를 통해 docker gwbridge와 연결됩니다.
    • 이때, 연결된 스위치인그레스 VIP(Virtual IP)로 트래픽을 전달합니다.
    • VIP는 로드밸런서 역할을 하며, 예를 들어 HAProxy가 외부의 공인 IP를 받아 백엔드의 사설 IP로 라운드 로빈 방식으로 트래픽을 전달합니다.
  3. 인그레스 네트워크 동작:
    • 인그레스 네트워크도 위와 같은 방식으로 동작하며, 로드밸런서 역할을 통해 클러스터 내 서비스로 트래픽을 분배합니다.

1. 도커 컨테이너와 도커 서비스

  • 도커 서비스에 컨테이너를 추가하려면, docker container run --attachable 옵션을 사용해야 합니다. 이 옵션은 컨테이너를 서비스에 연결 가능하도록 설정합니다.

2. 도커 스택(Docker Stack)

  • 도커 스택도커 컴포즈도커 스웜을 결합한 개념입니다.
  • docker stack을 사용하면 yml 파일을 통해 여러 서비스와 네트워크, 볼륨 등을 정의하고, 이를 클러스터에서 관리할 수 있습니다. 즉, 도커 스택도커 스웜 클러스터 환경에서 컴포즈처럼 여러 서비스를 한 번에 배포하고 관리하는 방법입니다.
    • 도커 스웜에서는 서비스 단위로 애플리케이션을 관리합니다. 이를 통해 **서비스의 확장(scale out)**이나 배포를 보다 효율적으로 관리할 수 있습니다.
    • 예를 들어, docker service scale <서비스명>=<갯수> 명령을 사용하여 해당 서비스의 컨테이너 수를 동적으로 조정할 수 있습니다.
  • 서비스 단위 관리

도커 스택은 여러 서비스를 포함하며, 각 서비스는 하나 이상의 컨테이너로 구성됩니다.

프로비전 && 디플로이

  • 인프라가 구성되었다는 것은 **프로비전(provision)**이 완료되었다는 의미입니다.
    • 프로비전은 서버, 네트워크, 스토리지 등 인프라 리소스를 설정하고 준비하는 과정입니다.
  • 애플리케이션 설치가 되었다는 것은 **디플로이(deploy)**가 완료되었다는 의미입니다.
    • 디플로이는 애플리케이션을 실제 운영 환경에 배포하고 실행하는 과정입니다.
  • 프로비전: 인프라 리소스를 준비하고 설정하는 과정.
  • 디플로이: 애플리케이션을 배포하여 운영 환경에서 실행되도록 하는 과정.

VLAN (Virtual Local Area Network):

  • VLAN은 같은 네트워크 상에서 논리적으로 구분된 네트워크입니다.
  • VLAN 내의 장치들은 서로 통신할 수 있지만, 다른 VLAN에 있는 장치들과는 통신할 수 없습니다.
  • 스위치 2대가 있을 때, 같은 VLAN에 속한 장치들은 서로 통신할 수 있습니다. 하지만 라우터를 건너지 못합니다.
  • VLAN 번호12비트를 사용하여 설정되며, 0번부터 4095번까지 사용할 수 있습니다.

VXLAN (Virtual Extensible LAN):

  • VXLANVLAN의 확장으로, 더 많은 가상 네트워크를 지원합니다.
  • VXLAN은 최대 1600만 개의 가상 네트워크를 사용할 수 있습니다.
  • VXLAN은 라우터를 건너 다른 네트워크와도 통신할 수 있기 때문에 VLAN보다 더 확장성이 뛰어납니다.

실습 내용 요약

이 실습에서는 Docker Swarm 환경에서 오버레이 네트워크스택 배포를 이용해 서비스를 구성하고, 이를 YAML 파일로 정의하여 Docker Stack으로 배포하는 과정입니다.

1. 오버레이 네트워크 생성

먼저, 오버레이 네트워크를 생성합니다:

docker network create --driver overlay testnet1
  • -driver overlay: 오버레이 네트워크 드라이버를 사용하여 클러스터 내에서 네트워크를 생성합니다.
  • testnet1: 네트워크 이름

2. 서비스 생성

서비스를 생성하여 컨테이너를 배포합니다:

docker service create --name testsvc1 --replicas 3 --constraint 'node.role == worker' --network testnet1 -p 8001:80 nginx
  • -replicas 3: 서비스의 복제본을 3개 생성
  • -constraint 'node.role == worker': 작업 노드에서만 서비스 실행
  • -network testnet1: testnet1 네트워크에 연결
  • p 8001:80: 포트 8001을 80으로 맵핑
  • nginx: NGINX 이미지를 사용하여 서비스 배포

3. 서비스 삭제

docker service rm testsvc1
  • testsvc1 서비스 삭제

4. 네트워크 삭제

docker network rm testnet1
  • testnet1 네트워크 삭제

5. YAML 파일 생성 및 수정

net1.yml 파일을 생성하여 서비스와 네트워크를 정의합니다:

version: '3.8'

services:
  nginx:
    image: nginx:latest
    ports:
      - "8002:80"
    networks:
      - testnet2
    deploy:
      replicas: 2
      placement:
        constraints: [node.role != manager]

networks:
  testnet2:
    driver: overlay
    attachable: true
  • nginx 서비스:
    • nginx:latest 이미지를 사용하고, 포트 8002를 컨테이너의 80번 포트에 매핑
    • testnet2 네트워크에 연결
    • replicas: 2: 서비스 복제본 2개 실행
    • placement.constraints: 매니저 노드 제외, 워커 노드에서만 실행
  • testnet2 네트워크:
    • 오버레이 네트워크로 생성되며, attachable: true로 설정하여 외부에서 컨테이너가 이 네트워크에 연결할 수 있게 합니다.

6. 스택 배포

docker stack deploy 명령어를 사용하여 스택 배포:

docker stack deploy -c net1.yml nginxstack
  • nginxstack: 배포할 스택의 이름

7. 스택 상태 확인

  • docker stack ls로 현재 배포된 스택 확인:
  • NAME SERVICES ORCHESTRATOR nginxstack 1 Swarm
  • docker stack ps nginxstack로 서비스 상태 확인:
    • nginxstack_nginx: nginx 서비스가 worker2와 worker3에서 실행 중
  • ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS rkq80lczhc3i nginxstack_nginx.1 nginx:latest worker3 Running Running 17 seconds ago svks0cgppiq1 nginxstack_nginx.2 nginx:latest worker2 Running Running 17 seconds ago

8. 서비스 상태 확인

  • docker service ls로 서비스 확인:
    • nginxstack_nginx: 2개의 복제본이 실행 중이며, 포트 8002가 80번 포트에 맵핑됨
  • ID NAME MODE REPLICAS IMAGE PORTS cfxxj1siwq5q nginxstack_nginx replicated 2/2 nginx:latest *:8002->80/tcp

실습

NFS 서버를 활용한 Docker에서 영구 볼륨(Persistent Volume) 사용

1. NFS 서버 설정 (Manager)

  1. 필요한 패키지 설치
  2. sudo apt install -y nfs-common sudo apt install -y nfs-server
  3. 공유 디렉토리 생성 및 권한 설정
  4. sudo mkdir /nginx sudo chmod 777 /nginx
  5. NFS 서버 설정 파일 수정
    • /etc/exports 파일을 수정하여 NFS 공유 디렉토리를 설정합니다.
    • /nginx 디렉토리를 211.183.3.0/24 네트워크 대역으로 읽기/쓰기가 가능하도록 설정합니다.
    sudo vi /etc/exports
    # 파일에 아래 라인 추가:
    /nginx          211.183.3.0/24(rw,sync,no_root_squash)
    
  6. NFS 서버 재시작
  7. sudo systemctl restart nfs-server
  8. NFS 서버 상태 확인
  9. sudo systemctl status nfs-server

2. 워커 노드에서 NFS 공유 접속 (Worker)

  1. 필요한 패키지 설치
  2. sudo apt install -y nfs-common
  3. NFS 서버 접속 확인
  4. sudo showmount -e 211.183.3.200 # 결과: /nginx 211.183.3.0/24
  5. NFS 공유 디렉토리 마운트
  6. sudo mount -t nfs 211.183.3.200:/nginx /home/user1/mounttest
  7. 마운트 상태 확인
  8. sudo mount | grep /nginx # 결과: 211.183.3.200:/nginx on /home/user1/mounttest type nfs4 (rw,...)
  9. 마운트 해제
  10. sudo umount /home/user1/mounttest

3. Docker Stack을 통한 NFS 볼륨 사용

  1. Docker Compose 파일 (nginx.yml) 작성
    • NFS 볼륨을 Docker 서비스에 연결하여 nginx 웹 서버를 배포합니다.
version: '3.8'

services:
  nginx:
    image: nginx:latest
    deploy:
      replicas: 3
      placement:
        constraints: [node.role == worker]  # 워커 노드에만 배포
    volumes:
      - nginx_vol:/usr/share/nginx/html  # NFS 볼륨을 nginx HTML 디렉토리에 마운트
    ports:
      - "8888:80"  # 포트 매핑

volumes:
  nginx_vol:
    driver: local
    driver_opts:
      type: "nfs4"
      o: "addr=211.183.3.200,rw"  # NFS 서버 주소와 rw 권한
      device: ":/nginx"  # NFS 서버의 공유 디렉토리
  1. Docker Stack 배포
    • nginxtest라는 이름으로 스택을 배포합니다. NFS 볼륨은 nginx_vol이라는 이름으로 생성됩니다.
  2. docker stack deploy -c nginx.yml nginxtest
  3. NFS 서버 내용 확인
    • nginx 디렉토리 내에 있는 50x.html과 index.html 파일을 확인합니다.
    sudo ls /nginx
    
  4. 서비스 상태 확인
  5. docker service ls # 결과: # ID NAME MODE REPLICAS IMAGE PORTS # td06z2fsyznh nginxtest_nginx replicated 3/3 nginx:latest
  6. 서비스 세부 정보 확인
  7. docker service inspect nginxtest_nginx # 출력 예시: # "Mounts": [ # { # "Type": "volume", # "Source": "nginxtest_nginx_vol", # "Target": "/usr/share/nginx/html", # "VolumeOptions": { # "DriverConfig": { # "Name": "local", # "Options": { # "device": ":/nginx", # "o": "addr=211.183.3.200,rw", # "type": "nfs4" # } # } # } # } # ]
  8. Docker 볼륨 정보 확인
    • nginxtest_nginx_vol 볼륨의 정보를 확인합니다.
    docker volume inspect nginxtest_nginx_vol
    # 출력 예시:
    # "Driver": "local",
    # "Options": {
    #   "device": ":/nginx",
    #   "o": "addr=211.183.3.200,rw",
    #   "type": "nfs4"
    # }
    

Docker Stack 삭제 및 네트워크 추가 작업

  1. 기존 Stack 삭제:
    • 기존에 배포한 nginxtest 스택을 삭제합니다.
    docker stack rm nginxtest
    
  2. nginx.yml 파일 수정 (네트워크 추가):
    • nginx_net 네트워크를 추가하여 서비스가 해당 네트워크에 연결되도록 수정합니다.
    • nginx 서비스에 nginx_net 네트워크를 연결하고, 네트워크 드라이버로 overlay를 사용합니다. 또한, attachable: true 옵션을 설정하여 컨테이너가 해당 네트워크에 연결할 수 있게 합니다.
version: '3.8'

services:
  nginx:
    image: nginx:latest
    deploy:
      replicas: 3
      placement:
        constraints: [ node.role == worker]  # 워커 노드에만 배포
    volumes:
      - nginx_vol:/usr/share/nginx/html  # NFS 볼륨을 nginx HTML 디렉토리에 마운트
    ports:
      - "8888:80"  # 포트 매핑
    networks:
      - nginx_net  # 새로운 네트워크 추가

volumes:
  nginx_vol:
    driver: local
    driver_opts:
      type: "nfs4"
      o: "addr=211.183.3.200,rw"
      device: ":/nginx"  # NFS 서버의 공유 디렉토리

networks:
  nginx_net:
    driver: overlay
    attachable: true  # 네트워크에 외부 컨테이너를 연결할 수 있게 설정
  1. 수정된 nginx.yml 파일로 Stack 재배포:
  2. docker stack deploy -c nginx.yml nginxtest
  3. Portainer 컨테이너 실행:
    • nginxtest_nginx_net 네트워크에 연결된 Portainer 컨테이너를 실행합니다. Portainer는 Docker 환경을 관리할 수 있는 웹 UI를 제공합니다.
    • 실행 명령어:
    docker run -d -p 9000:9000 --network nginxtest_nginx_net --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.9.1
    
  4. Portainer 접속:
    • Portainer 웹 UI에 접속하기 위해 브라우저에서 http://211.183.3.200:9000 주소로 접속합니다.

관련글 더보기