Docker

Docker 스웜과 서비스

쿠와와 2021. 1. 20. 18:59

호스트에서 도커 엔진을 구동하다가 CPU, 메모리, 디스크 용량과 같은 자원이 부족하면 어떻게 해결하나 ?? 

 

1. 매우 성능이 좋은 서버를 새로 산다.

2. 서버를 클러스터로 만들어 자원을 벙렬로 확장한다. 

 

ex. 필요 자원 32GB 

1. 32GB의 서버를 삼

2. 8GB 서버를 4개 사용함

 

1번의 방법은 자원의 확장성, 비용측면에서 좋은 해답이 아님 

2번방법이 필요한 확장하기도 좋고 비용측에서도 더 좋은 해결방안임 

 

그러나 여러 대의 서버를 하난의 자원 풀로 만드는 것은 어려운 작업이다. 

1. 서버를 발견 

2. 컨테이너 할당법 

3. 클러스터 내의 서버가 다운됐을 때 고가용성 보장 문제

등등

 

그래서 제공하는 것이 도커 스웜이다. ( 지금은 많이 사용하지 않음, 하지만 개념은 알아야함 )

 

스웜 클래식과 도커 스웜

여러 댜의 도커 서버를 하나의 클러스터로 만들어 컨테이너를 생성하는 여러 기능을 제공, 또한 유동적으로 서버를 확장할 수 있고 관리를 쉽게 할 수 있도록 도와줌

  1. 분산 코디네이터 : 클러스터에 영입할 새로운 서버의 발견, 각종 설정 저장, 데이터 동기화
  2. 서버 매니저 : 클러스터 내의 서버를 관리하고 제어
  3. 서버 제어 에이전트가 필요 : 각 서버를 제어 

 

서버 클러스터에서의 컨테이너 관리에 익숙하지 않다면 쿠버네티스를 하기 전에 한번 해봐야함 

 

도커 스웜은 목적에 따라 두개로 나눨 수 있음 

1. 스웜 클래식 : 여러 대의 도커 서버를 하나의 지점에서 사용하도록 단일 접근점을 제공

  • 분산 코디네이터, 에이전트 등이 별도로 실행 되어야함

 

2. 도커 스웜 모드  : 마이크로서비스 아키텍처의 컨테이너를 다루기 위한 클러스링 기능에 초점을 맞춤 

  • 클러스터링을 위한 모든 도구가 도커 엔진 자체에 내장되어있어 클래식보다 쉽게 서버 구축 가능

 

스웜 모드가 서비스 확장성, 안정성 등 여러 측면에서 클래식 보다 뛰어나기 때문에 일반적으로 스웜모드를 많이 사용 

 

스웜 모드 

별도의 설치 과정이 필요하지 않으며 도커 엔진 자체에 내장돼있다.

docker info 명령어를 통해 도커 엔진의 스웜 모드 클러스터 정보를 확인할 수 있다. 

docker infor | grep Swarm 

Swarm: inactive 

=> 비활성화 상태 

 

 

도커 스웜 모드의 구조

스웜모드는 매니저 노드와 워커 노드로 구성돼 있다. 워커 노드는 실제 컨테이너가 생성되고 관리되는 도커 서버이고 매니저 노드는 워커 노드를 관리하기 위한 도커 서버이다. (매너저 노드도 기본적으로 워커 노드의 역활을한다.)

 

매니저 노드는  1개 이상 있어야 하지만 워커 노드는 없을 수도 있다. 실제 운영 환경에서 스윔 모드로 도커 클러스터를 구성하려면 매니저 노드를 다중화 하는 것을 권장한다. 

- 매니저의 부화를 분산 

- 특정 매니저 노드가 다운 됐을 때 정상적으로 스웜 클러스터를 유지 가능

- 매니저 노드는 리더와 매니저로 나뉜다. -> 리더 매니저는 모든 매니저 노드에 대한 데이터 동기화와 광리를 담당한다.

 

구축

swarm-manager IP_1

swarm-worker1 IP_2

swarm-worker2 IP_3

 

다른 도커가 매니저 노드에 접근 - 스웜 매니저는 기본적으로 2377번 포트를 사용한다.
또한 노드 사이의 통신에 7946/tcp,udp, ingress 오버레이 네트워크 4789/tcp,udp 포트를 사용 -호스트머신에서 포트를 열어두자 

docker swarm init --advertise-addr IP_1

-> docker join command를 제공해준다. 그 커맨드를 워커 노드에서 입력해줘야한다. (노출되지 않게 조심)

 

워커  노드로 사용할 각 서버에서 입력해야할 명령어 

docker swarm join --token [위에서 제공된 커맨드] IP_1:2377

 

docker node ls 로 확인해 보자 

 

 

새로운 매니저 노드 추가 

docker swarm join-token manager 

 

새로운 워커 추가

docker swarm join-token worker

 

위에서 발금된 커맨드 코드를 재발급 받아야 할 때가 있을 것이다. (노출시 누구나 해당 스웜 클러스터에 노드 추가할 수 있게 됨)

docker swarm join-token --rotate manager 

 

추사된 워커 노드를 삭제하고 싶다면 해당 워커 노드에서 아래의 명령어를 사용하면 된다. -> down 이 됨

docker swarm leave

그 후 매니저 노드에서

docker node rm docker_ID 

해주면 된다. 

 

하지만 매니저 노드는 docker swarm leave --force 까지 추가해야 삭제할 수 있다. 

 

워커 노드를 매니저 노드로 변경하려면 promote 명령어를 사용하면 된다.

docke node promote swarm-worker1

매니저 노드 -> 워커 노드 할 때는 demote 를 사용하면 된다. 매니저 리더 노드에 demote를 사용하면 다른 매니저 노드중 새로운 리더가 선출된다. 

 

 

소웜 모드 서비스 개념

지금까지의 도커 명령어 = 컨테이터 제어

스웜 모드에서 제어하는 단위 = 서비스 제어 (컨테이너(Task) 집합)

 

스웜 -> 서비스의 컨테이너들에 대한 상태를 계속 확인하고 있다가 서비스 내에 정의된 레프리카의 수만큼 컨테이너가 쉬웜 클러스터에 존재하지 않으면 새로운 컨테이너 레플리카를 생성 

 

 

서비스 생성

서비스를 제어하는 도커 명령어는 전부 매니저 노드에서만 사용할 수 있다. (docker run -d 옵션을 사용해 동작할 수 있는 이미지를 사용해야함 그렇지 않으면 장애가 생긴것으로 판단해 계속 컨테이너를 생성할 것이다.)

 

docker service create ubuntu:18:04 /bin/sh -c "while ture; do echo hello world; sleep 1; done"

 

생성 됬는지 확인해보자 

docker service ls

 

상세 정보 

docker service ps [서비스 이름]

 

서비스 제거

docker service rm [서비스 이름]

 

 

이번에는 nginx를 이용해 웹 서버 서비스를 만들어보자

 

서비스의 모드는 2가지 

1. 복제 모드 -> 말그대로 그만큼 생성해서 사용

docker service create --name myweb --replicas 2 -p 80:80 nginx

=> myweb.1과 myweb.2가 생성된 것을 확인할 수 있다. 포트 80:80을 사용하는 

 

Tip. replicas 대신 scale을 사용해서 조절할 수도 있다.

docker service scale myweb=4

 

 

2. 글로벌 모드 -> 클러스터 내에서 사용할 수 있는 모든 노드에 컨테이너를 반드시 하나씩 생성해서 사용 

docker service create --name global_web --mode global nginx

 

 

 

서비스 복구 

컨테이너가 정지하거나 특정 노드가 다운되면 스웜 매니저는 새로운 컨테이너를 생성해 자동으로 복구 

 

docker service ps 명령어에서 NAME 항목에 \_가 붙어있는 컨테이너는 어떠한 이유로든 동작을 멈춘 컨테이너로서, 서비스에서 컨테이너 병경 기록을 나타낸다. 

 

이때 다운됐던 노드가 다시 시작해 정상적인 상태를 회복해도 장애를 복구하기 위해 다른 노드로 옮겨진 컨테이너가 해당 노드에 자동으로 할당되지는 않는다. 

-> rebalance 되지 않음, 즉 다시 스케일링 해줘야함 

docker service scale myweb=1 

docker service scale myweb=4

줄였다가 다시 늘려줘야함  

 

업데이트 

docker service update --image nginx:1.11 myweb2 

=> 해당 이미지 업데이트 해줌 

 

옵션 

- 롤링 업데이트의 주기

ex. --update-delay 10s 

 

- 업데이트를 동시에 진행할 컨테이너의 수

ex. --update-parallelism 2 

 

- 업데이트에 실패했을 때 어떻게 할 것인지 [pause, continue]

ex. --update-failure-action continue 

 

=> 이러한 서비스의 롤링 업데이트 설정은 docker service inspect, docker inspect --type service 로 확인 가능하다.

 

롤백 또한 가능하다.

docker service rollback myweb3

 

 

외부에서 서비스하려면 우리의 환경이 맞춘 설정 파일이나 값들이 필요하다. 이를 위해 스웜은 secretconfig라는 기능을 제공한다. (docker run에서는 사용 못함)

secret : 비밀번호나 SSH키 인증거 키와 같이 보안에 민감한 테이터 전송

config : 레지스트리 설정 파일과 같이 암호화할 필요가 없는 설정값들에 대해 사용

 

 

secret 

생성 (비밀번호는 내가 임의로 1q2w3e4r로 만들었다.)

echo 1q2w3e4r | docker secret create my_pw -

 

확인 -> 실제 값은 확인할 수 없음 

docker secret ls 

 

생성 후 사용 법 (서비스를 만들 때 사용)

docker service create \

--name mysql \

--replicas 1 \

--secret source=my_pw, target=mysql_root_password \

--secret source=my_pw, target=mysql_password \

-e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/myslq_root_password" \

-e MTSQL_PASSWORD_FILE="/run/secrets/mysql_password" \

-e MYSQL_DATEBASE="workdpress" \

mysql:5.7 

 

=> 이때 만든 비밀번호로 접속할 수 있다. (1q2w3e4r)

 

config 

생성 (registry-config라는 이름으로 설정)

docker config create registry-config [레지스트리 설정 파일] 

이때 나오는 Data 값을 가져와서 base64로 인코딩한 뒤 저장한다. 

 

그렇다는 것은 우리가 base64로 디코딩하면 원래의 값을 확인할 수 있다는 덧이다.

echo [data 값] | base64 -d 

 

사용법

docker service create --name yml_registry -p 5000:5000 \

--config source=registry-config, target=/etc/docker/registry/config.yml \  <- 여기는 레지스트리 파일 위치 

registry2.6

 

 

 

스웜 네트워크

여러 개의 도커 엔진에 같은 컨테이너를 분산해서 할당하기 때문에 네트워크 풀이 필요하다. 

 

우선 매니저 노드에서 docker network ls 명령어로 네트워크 목록을 확인해보자 

=> ingress, none, bridge, host, docker_gwbridge 등등 여러기의 내트워크가 있다. 

 

- ingress : 로드 밸런싱과 라우팅 메시에 사용됨, 즉 서비스 내의 컨테이너에 접근할 수 있게 설정하는 메시 구성과 접근을 라운드 로빈 방식으로 분산하는 로드 밸런싱 담당 

 

클러스터에 등록된 노드 ingress 네트워크로 생성 

docker network ls | grep ingress 

 

하지만 모두 ingress 네트워크를 사용해서 외부에 노출 되는 것은 아니다. 직접 컨테이너에 연결 할 수도 있다.

docker service create --publish mode=host, target=80,published=8080, protocol=tcp --name web nginx

 

하지만 가급적이면 ingress 사용하자 

ingress 네트워크는 오버레이 네트워크 드라이버를 사용한다. 오버레이는 여러 개의 도커 데몬을 하나의 네트워크 풀로 만드는 네트워크 가상화 기술의 하나로서, 도커에 오버레이 네트워크를 적용하면 여러 도커 데몬에 존재하는 컨테이너가 서로 통신할 수 있다

 

- docker_gwbridge : 오버레이 네트워크를 사용할 때 사용 됨

오버레이를 사용하지 않는 컨테이너는 브리지 네트워크를 사용해 외부와 연견한다. 그러나 ingress를 포함한 모든 오버레이 네트워크는 이와 다른 브리지 네트워크인 docker_gwbridge 와 함께 사용된다. 

 

 

오버레이 네트워크 사용자 정의 

 

docker network create --subnet [IP/24] -d overlay myoverlay 

오버레이 서브넷 설정돼 이름 설정 

 

이 때 docker service create 명령어에 --network 옵션을 사용해 오버레이 네트워크를 서비스에 적용해 컨테이너를 생성할 수 있음

 

docker service create --name overlay_service --network myoverlay --replicas 2 alicek106/book:hostname

 

 

서비스 디스커버리 

같은 컨테이너를 여러 개 만들어 사용할 대 무엇이 새로 생겼는지, 삭제되었는지 감지하는 것이 중요하다. 일반적으로 이 동작은 주키퍼, etcd 등의 분산 코디네이터를 외부에 두고 사용해서 해결하지만 스웜 모드는 자체적으로 지원한다.

스웜 모드에서는 'B'라는 이름으로 서비스 B의 컨테이너에 모두 접근할 수 있다. 즉 IP 주소를 알 필요도 없고 새롭게 생성된 사실도 알 필요가 없으며 서비스 이름만 알면 된다. 

이때 서비스 내부에서는 VIP(가상 아이피)를 가지게 되고 그 아이피를 통해 연결된다. 그리고 이 IP는 컨테이너의 네트워크 네임스페이스 내부에서 실제 서비스의 컨테이너의 IP로 포워딩된다. 

 

 

스웜 모드 볼륨

스웜에서 도커 볼륨을 사용하는 서비스를 생성하려면 서비스를 생성할 때 --mount 옵션의 type 값에 volumn을 지정한다. 

 

docker service --name ubuntu --mount type=volume,source=myvol,target=/root ubuntu:18.04 ping docker.com

이때 source를 명시하지 않으면 임의의 16진수 이름을 절성한다.

 

타입이 bind를 쓰면 bind 타입의 볼륨이 생성된다. 

서비스의 컨테이너에서 볼륨에 공유할 컨테이너의 딜렉터리에 파일이 이미 존재한다면 볼륨에 복사가 되고 호스트에서 별도의 공간을 차지한다.

이를 막기위해 volume-nocopy를 추가하면 복사하지 않도록 설정할 수 있다. (target 뒤에 ,를 쓰고 이어 붙이자)

 

스웜 모드에서 볼륨의 한계점 

서비스를 할당받을 수 있는 모든 노드가 볼륨 데이터를 가지고 있어야한다. 따라서 여러 개의 도커 데몬을 관리해야 하는 스웜 모드에서는 적합하지 않은 기능일 수 있다. 

또 PaaS같은 시스템을 구축하려고 하면 더 큰 문제가 된다.  

 

이를 해결하기 위한 일반적인 문제는 어느 노드에서도 접근 가능한 퍼시스턴드 스토리지를 사용하는 것이다.

 서비스의 컨테이너가 각 노드에 할당될 때 퍼시스턴트 스토리지를 마운트해 사용하면 노드에 볼륨을 생성하지 않아도 되며, 컨테이너가 어느 노드에 할당되든 컨테이너에 필요한 파일을 읽고 쓸 수 있다. 

 

하지만 플로그인, nfs, dfs를 사용해야함 

 

 

도커 스웜 모드 노드 다루기 

 

노드 확인

docker node ls 

 

Active

새로운 노드가 스웜 클러스터에 추가되면 기본적으로 설정되는 상태 = active

노드가 서비스의 컨테이너를 할당받을 수 있음을 의미함 

 

하지만 active 상태 아닌 노드를 active로 만들려면 아래의 명령어가 필요 

docker node update --availability active name

 

 

Drain

이 상태가 되면 매니저의 스케줄러는 컨테이너를 해당 노드에 할당하지 않는다. 

docker node update --availability drain name

 

Pause

drain 상태와 비슷하지만 실행 중인 컨테이너가 중지되지 않는다는 점이 다르다.

docker node update --availability pause name 

 

 

노드 분류(라벨 추가)

라벨을 생성하면 서비스를 할당할 때 컨테이너를 생성할 노드의 그룹을 선택하는 것이 가능해진다. 

docker node update --label-add storage=ssd name

 

docker node inspect 로 확인해보자 

 

서비스를 만들 때 --constraint 옵션을 추가해 제약 조건을 설정할 수 있다

1. node.labels 

위에서 설명한 것 처럼 노드 라벨을 추가할 수 있다. 

docker service create .... \

--constraint 'node.lavels.storage == ssd' \  -> 특정 조건을 선택하지 않도록 할 때 != 도 가능함

.

.

name

 

2)node.id 

ID를 명시해 서비스의 컨테이너를 할당할 노드를 선택할 수 있다. 

--constraint 'node.id == 2gn6.....3uv83hlj' \

위에 id에는 출력된 ID를 전부 입력해야한다.

 

3)node.hostname, node.role 제약 조건

--constraint 'node.hostname == swarm-worker ' \

--constraint 'node.role != manager' \

 

4) engine.labels

도커 엔진(데몬) 자체에 라벨을 설정해 제한 조건을 설정할 수 있다. 하지만 이를 사용하려면 도커 데몬의 실행 옵션을 변경해야한다. 다루지 않겠다. 

 

'Docker' 카테고리의 다른 글

kubernetes 시작하기  (0) 2021.01.29
Kubernetes 설치(쿠버네티스)  (0) 2021.01.25
도커 컴포즈  (0) 2021.01.12
Docker File  (0) 2021.01.04
Docker 이미지  (0) 2021.01.04