컨테이너 배치전략 - 도커 스웜

## 도커 스웜
- 도커 스웜은 여러 도커 호스트를 클러스터로 묶어주는 오케스트레이션 도구의 한 종류다
- 컴포즈 : 여러 컨테이너로 구성된 도커 애플리케이션을 관리(주로 단일 호스트)
- 스웜 : 클러스터 구축 및 관리(주로 멀티 호스트)
- 서비스 : 스웜에서 클러스터 안의 서비스(컨테이너 하나 이상의 집합)을 관리
- 스택 : 스웜에서 여러 개의 서비스를 함한 전체 애플리케이션을 관리

# 다중 클러스터 구성하기

## (스웜 실습을 위한) Docker in Docker
- 개인이 클러스터를 구성할 서버 노드를 여러 대 준비하는 것은 어려우므로 Dind(Docker in docker)를 이용하여 클러스터를 구성해본다.
- 아래 내용을 복사하여 docker-compose.yml 로 저장하고 실행하자
### 클러스터 구성을 위한 docker-compose.yml
```
services:
  registry:
    image: registry:2.8.3
    ports:
      - 5001:5000
    volumes:
      - "./registry-data:/var/lib/registry"
  manager:
    image: docker:26.1.2-dind
    privileged: true
    tty: true
    ports:
      - 8000:80
      - 9000:9000
    depends_on:
      - registry
    expose:
      - 3375
    command: "--insecure-registry registry:5000"
    volumes:
      - "./stack:/stack"
  worker01:
    image: docker:26.1.2-dind
    privileged: true
    tty: true
    depends_on:
      - manager
      - registry
    expose:
      - 7946
      - 7946/udp
      - 4789/udp
    command: "--insecure-registry registry:5000"
  worker02:
    image: docker:26.1.2-dind
    privileged: true
    tty: true
    depends_on:
      - manager
      - registry
    expose:
      - 7946
      - 7946/udp
      - 4789/udp
    command: "--insecure-registry registry:5000"
  worker03:
    image: docker:26.1.2-dind
    privileged: true
    tty: true
    depends_on:
      - manager
      - registry
    expose:
      - 7946
      - 7946/udp
      - 4789/udp
    command: "--insecure-registry registry:5000"
```
## 생성된 컨테이너 확인하기
- 정상적으로 compose up이 되었다면 5개의 컨테이너가 실행된다. 
    - registry 1개 : 빌드된 이미지를 저장할 보관소이다. 
    - manager 1개 : swarm으로 관리되는 노드를 관리하는 컨테이너이다.
    - worker 3개  : 애플리케이션이 실행되는 컨테이너들이 실제 배포된다.
- 아직은 클러스터로 동작하는 상태는 아니므로 서로 연결해주어야 한다. 
## swarm 활성화
- manager 컨테이너로 attach shell을 이용하여 들어가보자.
![[Pasted image 20240511144606.png]]
- `$ docker swarm init` 을 입력하여 swarm을 활성화 한다.
![[Pasted image 20240511144822.png]]
- 중간에 나오는 `docker swarm join .....` 부분을 카피해두자 
- docker swarm join --token SWMTKN-1-65nd9v1zpdxmp6w16bhz4xlq17ugb8795qkn7b9o3nqt0mq2ts-54uzt4s8pr59570unfmdg20me 172.19.0.3:2377
## manager에 worker를 노드로 등록하기 
- 각 worker 로 진입하여 카피해둔 명령어를 실행하자. worker 3개다 작업을 해주어야 한다.
![[Pasted image 20240511145203.png]]
- 정상실행이 된다면 아래처럼 joined라는 글자가 보일 것이다.
![[Pasted image 20240511145325.png]]

## 등록된 node 확인
- manager 로 다시 attach shell을 한다음 다음의 명령어를 실행하자
- `$ docker node ls`
![[Pasted image 20240511145628.png]]
- manager 자신을 포함한 총 4개의 노드가 보인다. 
## 레지스트리에 image push 하기
![[Pasted image 20240511151622.png]]
- 아래 처럼 레지스트리에 등록했다. 
![[Pasted image 20240511151651.png]]

## worker 노드에서 레지스트리 이미지 pull 하기
- worker01에 attach shell 로 입장하고 다음 명령어로 이미지를 pull 할 수 있는지 테스트해보자
- `$ docker image pull registry:5000/greeting:1.0`
- localhost:5001라고 안하고 registry:500라고 한 이유는 worker01 입장에서는 'registry:5000' 이기 때문이다.
![[Pasted image 20240511155008.png]]
## 여기까지 성공했다면 
- 다중 클러스터 구성 완료

# 도커 스웜 - 서비스

- 애플리케이션은 단일 컨테이너로 만들수도 있고, 여러개의 컨테이너 묶음으로 이루어질 수도 있다. 
- 예) 백엔드 구축시 장애방지를 위해 2개 이상의 서버를 이용
- 이런 묶음을 제허하기 위한 단위를 도커 스웜에서는 "서비스" 라고 한다. 
## manager 에서 '서비스' 생성하기
- manager에 attach shell 한다. 
- 아래 명령어 입력
- `$ docker service create --replicas 1 -p 9090:8080 --name greeting registry:5000/greeting:1.0`
![[Pasted image 20240511160341.png]]
- 서비스가 생성되었다.
## 서비스 복제하기
- `$ docker service scale greeting=6` 을 실행하면 replica 수를 6개로 늘릴 수 있다. 
![[Pasted image 20240511160756.png]]

![[Pasted image 20240511161305.png]]

- 레플리카 수를 늘리면 자동으로 컨테이너를 복제하고 [여러 노드]에 자동 배치한다. (이런 기능이 없다면 수동으로 명령어를 입력해야한다.  😭)
- `docker service rm greeting`으로 지우자

# 도커 스웜 - 스택

- 스택은 하나 이상의 서비스를 그룹으로 묶은 단위이다. 서비스는 image를 하나 밖에 다루지 못하지만 스택은 여러개를 다룰 수 있다. 
## overlay 네트워크
- 스택을 사용해 배포된 서비스 그룹은 overlay 네트워크에 속한다. 
- overlay 네트워크란 여러 도커 호스트에 걸쳐 배포된 컨테이너 그룹을 같은 네트워크에 배치하기 위한 기술을 말한다. 
- 따라서 스택은 동일 overlay 네트워크에 있어야 한다. 
- manager 에서 overlay 네트워크로 'bootnet' 이라는 network를 생성해보자
- `$ docker network create --driver=overlay --attachable bootnet`
## 스택 만들기
- manager의 '/stack' 폴더에 'bootapi.yml' 파일을 아래와 같이 만들자
- '/stack' 폴더는 처음에 manager 만드는 docker-compose.yml에 정의했다.
- nignx 와 boot 앱으로 구성되어있다.
```
services:
  nginx:
    image: nginx
    deploy:
      replicas: 3
      placement:
        constraints: [node.role != manager]
    depends_on:
      - api
    networks:
      - bootnet
  api:
    image: registry:5000/greeting:1.0
    deploy:
      replicas: 3
      placement:
        constraints: [node.role != manager]
    networks:
      - bootnet
networks:
  bootnet:
    external: true
```

## 스택 배포하기
- `$ docker stack deploy -c /stack/bootapi.yml greeting-stack`
![[Pasted image 20240511164922.png]]
- `$ docker stack ps greeting-stack`
![[Pasted image 20240511165132.png]]

## 스택 삭제하기
- `$ docker stack rm greeting-stack`

# 외부에서 도커 스웜 내부 접근

- 여러 서버에 걸쳐 컨테이너가 동작중이므로 proxy 서버를 이용하여야 한다. 
## haproxy 이용하기
- stack 폴더에 아래와 같이  haproxy-ingress.yml 작성
```
services:
  haproxy:
    image: haproxy
    networks:
      - bootnet
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      mode: global
      placement:
        constraints:
          - node.role == manager
    ports:
      - 8080:8080
      - 1936:1936
networks:
  bootnet:
    external: true
```
- stack 실행
	- `$ docker stack deploy -c /stack/haproxy-ingress.yml ingress`

댓글

이 블로그의 인기 게시물

Session 대신 JWT를 사용하는 이유

VSCode에서의 VIM 단축키와 키보드 구매 가이드

우분투에서 테스트링크(testlink)와 맨티스(mantis)로 테스팅 서버 구성하기