Docker Swarm
Docker-Compose : 하나의 머신에서만 동작 (따라서 scale up이 의미가 없다.)
scale up이 이루어지려면 머신이 2개 이상은 있어야 한다.
- 네트워크 확인 → Ingress와 bridge가 추가됨
docker node ls
docker network ls
- 새로운 토큰 발급
docker swarm join-token --rotate worker # 다 보이고
docker swarm join-token -q worker # 토큰만 보이고
- 다음 에러를 만나면 방화벽이나 네트워크 연결을 확인하기
Error response from daemon; rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 매니저IP주소:2377: connect: no route to host
*RPC(Remote Procedure Call) eroor 로 원격으로 일을 시키고 있는데 연결이 잘 안되고 있다는 뜻
- worker 제거
- manager에서 수행
docker swarm leave 워커이름
- worker에서 수행 (이름 쓸 필요 없다.)
docker swarm leave
모니터링 도구
dockersamples/visualizer
- 설치
docker service create --name=viz_swarm --publish=7070:8080 --constraint=node.role==manager --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock dockersamples/visualizer
8080 포트를 개방하면 대부분 아파치 톰캣 서버를 사용 -> 자바 사용
grid 데이터를 분산해서 엮어놓는 것
rdbms는 분산된 데이터를 가져와서 join이나 set을 한다.
- 포트 쓰고 있는지 확인
sudo netstat -nlp | grep 7070
- 서버 확인
포트포워딩 해서 192.168.202.9:7070 으로 접속
# GUI를 설치한 경우는 자신의 브라우저에서 localhost:7070을 이용
- swarmpit
- 설치
docker run -it --rm --name swarm-installer --volume /var/run/docker.sock:/var/run/docker.sock swarmpit/install:1.9
서비스 생성과 삭제
3초마다 콘솔에 메시지를 출력하는 서비스를 생성
docker service create --name swarm-start alpine:3 /bin/ash -c "whlie true; do echo 'Docker Swarm mode Start.'; sleep 3; done"
- 제대로 안 깔려서 지우고 싶으면
docker stack rm swarmpit
# docker stack ls, docker service ls, docker ps -a로 확인 가능
docker rmi swarmpit/install:1.9 # 태그도 써줘야 한다.
- 서비스 목록 조회
docker service ls
- 실행 중인 컨테이너 조회
docker service ps swarm-start
- 로그 확인
docker service ls
docker service ps swarm-start
docker service logs -f {serviceID}
만약 잘 안 만들어진다면 docker login 으로 로그인하고 난 후에 다시 해보자!
nignx를 이용한 서비스 컨테이너 배포와 관리
- nginx를 2개의 replic(복제본)로 배포
- 혹시 모르니까 docker pull nginx 해놓고
docker service create --name web-alb --constraint node.role==worker --replicas 2 --publish 8081:80 nginx
- nginx 이미지를 가지고 컨테이너를 생성하는데 worker 노드에 2개 생성을 하고 이 서비스 이름은 web-alb가 된다.
- replicas 1로 했을 때 worker2로 간다고 치면 worker1, 2모두에서 curl이 되는데 worker1에서는 docker ps 했을 때 없다.
- 컨테이너가 여기 없더라도 돌아들어가서 얘한테 간다. (가지고 있다 없다는 큰 의미가 없다.)
- 서비스가 만들어질 때 포트포워딩한 8081번 포트가 매니저와 노드 모두에서 개방이 된다.
- 외부에서 접근할 때는 manager를 통해서 접근한다. (worker를 이용해서 접근이 안되는 것은 아니지만 이렇게 하면 Load Balancing이나 Proxy의 의미가 없어지며 worker의 개수가 여러 개일 때 어떤 worker에 컨테이너가 만들어지는 지 알 수 없기 때문이다.)
- node.role=worker : worker에만 생성된다.
- 이미지 다운로드가 안되면 worker1과 worker2에서 docker pull nginx를 수행하고 실행
- 서비스를 조회 & 컨테이너 확인
- docker service ls docker service ps web-alb
- 모든 컴퓨터에서 8081이 열려있는지 확인
- sudo netstat -nlp | grep 8081
→ docker service 명령으로 서비스를 생성할 때 여러 개의 컨테이너를 생성하면 컨테이너가 배치된 모든 노드의 포트가 동시에 개방이 된다.
- 매니저 노드에서 docker service rm web-alb를 하면 worker1, worker2에 떠있던 컨테이너 다 자동으로 소멸된다.
이미지
Image: disk에 저장되기 때문에 자동 소멸되지 않는다.
- Container: 메모리에 존재하기 때문에 자동 소멸 된다.
Volume: docker-engine이나 hard disk에 데이터를 보관하려고 사용하는 것 → 자동 소멸 x
- Network: container를 묶기 위해서 쓰는 것 → 자동 소멸 가능
실제로 load balancing을 해주는지 확인해보기
- 2개의 컨테이너를 생성
docker service create --name web-alb --constraint node.role==worker --replicas 2 --publish 8081:80 nginx
- worker1에서 수행 (코드를 수정해보면 로드밸런싱이 되는지 안되는지 알 수 있다.)
- vi index.html
<h1>Hello - Docker Swarm worker1</h1>
- docker ps로 컨테이너 이름 확인
- web-alb.1.kt64fwu0qra90fu8il1o5odx3
docker cp index.html web-alb.1.kt64fwu0qra90fu8il1o5odx3:/usr/share/nginx/html/index.html # Successfully copied 2.05kB to web-alb.1.kt64fwu0qra90fu8il1o5odx3:/usr/share/nginx/html/index.html
- worker2에서 수행 (코드 수정)
- vi index.html
<h1>Hello - Docker Swarm worker2</h1>
- docker ps로 컨테이너 이름 확인
- web-alb.2.zs0lah6j3lekwf0209fvp5dqc
docker cp index.html web-alb.2.zs0lah6j3lekwf0209fvp5dqc:/usr/share/nginx/html/index.html ## Successfully copied 2.05kB to web-alb.2.zs0lah6j3lekwf0209fvp5dqc:/usr/share/nginx/html/index.html
동적으로 scale을 변경하는 것이 가능하다.
docker service scale 서비스이름=replicas 숫자
- docker service ps web-alb 로 확인 가능
If 축소하고 싶다면
docker service scale web-alb=replicas
docker service rm 후
모든 애들에게 배치하고 싶다면 replicas 대신에 --mode global을 선택해서 생성
docker service create --name global_nginx --mode global nginx
서비스 유지 관리를 위한 기능 (롤링 업데이트)
- 기본적으로 대부분의 오케스트레이션 도구는 장애 복구 기능을 내장하고 있다.
- 도커 스웜 모드 클러스터에서는 장애 대비를 할 수 있는 --replicas 기능을 제공하고 배포된 서비스 장애 및 노드의 장애가 발생하면 자동으로 복제 수만큼의 서비스를 맞추어 장애에 대한 자동 복구를 수행한다.
- 패키지 버전 변경 수행 시 서비스를 중단하지 않고 롤링 업데이트 기능을 사용하면 새 버전 서비스 컨테이너는 하나씩 늘려가고 이전 버전 서비스 컨테이너는 하나씩 줄여가는 방식으로 버전 업데이트를 수행할 수 있다. → 롤링 업데이트
- 업데이트가 실패하면 다양한 기능을 통해 재시도 및 업데이트 중지 등을 선택 수행할 수 있고 잘못된 업데이트를 취소하기 위해 롤백 기능도 제공한다.
실습
- 서비스 배포
docker service create --name web-alb --replicas 3 --publish 8001:80 nginx
- 서비스 확인
docker service ls
- 실제 컨테이너 확인
docker service ps web-alb
- worker1(컨테이너가 배치된 노드에서 수행)에서 배포된 컨테이너를 삭제
- docker rm -f 컨테이너이름 또는 아이디
- manager에서 docker service ps web-alb 해보면 하나의 컨테이너가 shutdown으로 되어 있고 이와 동시에 새로운 컨테이너가 만들어지는 걸 확인할 수 있다. (자동 → 우리가 할 필요 없음)
Redis로 Rolling Update 실현
- 서비스 생성
docker service create --name my-database --with-registry-auth --replicas 3 redis:6.0-alpine
- 확인
docker service ps my-database
- 롤링 업데이트가 되는지 업데이트 해보기
- 이미지 버전 업데이트로 변경하면서 체크
docker service update --image redis:6.2.5-alpine my-database
→ 예전 거가 shutdown 되어 있고 새로운 것들로 대체되어 있다.
→ worker1에 보면 이전 꺼 지워진 것은 아니다.
- 롤링 업데이트 옵션
--update-failure-action
--update-max-failure-ratio
--update-monitor
--update-order
--update-parallelism
- 서비스의 상세 정보 확인
docker service inspect --pretty my-database
→ rollback 관련, container 스펙 나온다.
- 업데이트 옵션을 추가한 서비스 생성
docker service create --name my-database2 --with-registry-auth --replicas 4 --update-delay 10s --update-parallelism 2 redis:6.0-alpine
→ 업데이트 할 때 10초 대기하고 한 꺼번에 2개씩 업데이트
- 이미지를 바꿔보기
docker service update --image redis:6.2.5-alpine my-database2
(롤백을 하기 위해서 남아 있다.)
→ 내 서비스가 구동되는 데 오래 걸린다면 옵션을 적절히 잘 사용해야 한다.
- 롤백하기 (이미지를 변경하는 업데이트 수행)
docker service rollback my-database2
- 몇 개의 버전을 저장하고 있는지 확인
- docker info 명령을 수행하고 Task History 부분을 확인
- 만약 변경이 자주 일어난다면 Task History의 개수를 늘릴 필요가 있다.
docker swarm update --task-history-limit 개수
특정 노드를 업데이트에서 제외
- 특정 노드의 계획된 유지관리(대부분 하드웨어 교체 작업 및 정기 점검 등)를 수행하기 위해 업데이트 등의 작업에서 제외하는 경우가 있는데 이러한 작업을 drain이라고 한다.
- nginx로 서비스를 생성
docker service create --name my-web --with-registry-auth --replicas 3 nginx:1.19
→ 인증 정보 넘어가도록 --with-registry-auth 붙여주기
→ 항상 만들고 난 이후에는 docker service ps my-web으로 확인해보기
- worker2를 drain
docker node update --availability drain swarm-worker2
- 노드 확인
docker node ls
- 업데이트 수행
docker service update --image nginx:1.21 my-web
- worker2를 다시 활성 모드로 변경
docker node update --availability active swarm-worker2
→ 다시 활성 모드로 돌아오더라도 기존 컨테이너는 재배치 되지 않는다.
- scale 조정으로 재배치
docker service scale my-web=1
docker service scale my-web=3
docker service ps my-web
Stack 배포
도커 스웜 스택은 클러스터 환경에 여러 서비스를 묶어서 하나의 스택 공간을 생성하는 것
- Docker Stack은 분산 애플리케이션의 최상위 계층
- 3 Tier Model
- Front End
- Back End
- Database
실습
- 스택에서 사용할 클러스터 네트워크인 오버레이를 생성 (dailylog-net)
docker network create --driver overlay 이름
docker network create --driver overlay dailylog-net
- 스택 작업을 위한 디렉토리 생성
mkdir dailylog && cd $_ # 만들고 바로 이동
- 스택 배포를 위한 yaml 파일을 생성하고 작성
version: "3.9"
services:
mongodb:
image: dbgurum/dailylog:Db_1.0
ports:
- 17017:27017
networks:
- dailylog-net
deploy:
placement:
constraints: [node.role != manager]
restart_policy:
condition: on-failure # 정상 종료가 아닌 장애 발생시 재시작 조건
max_attempts: 3 # 재시작 시도 최대 횟수
delay: 10s # 재시작 시도 사이의 지연시간
window: 120s # 재시작 정책을 평가하는데 사용되는 시간
ㅑ frontend:
image: dbgurum/dailylog:front_1.0
ports:
- 3000:8000
networks:
- dailylog-net
environment:
- PORT=8000
- DAILYLOG_API_ADDR=backend:8000
deploy:
replicas: 2
placement:
constraints: [node.role != manager]
restart_policy:
condition: on-failure
max_attempts: 3
delay: 10s
window: 120s
depends_on:
- backend
backend:
image: dbgurum/dailylog:backend_1.0
networks:
- dailylog-net
environment:
- PORT=8000
- DAILYLOG_DB_ADDR=mongodb:27027
deploy:
replicas: 2
placement:
constraints: [node.role != manager]
restart_policy:
condition: on-failure
max_attempts: 3
delay: 10s
window: 120s
depends_on:
- mongodb
networks:
dailylog-net:
external: True
- 배포
docker stack deploy --compose-file 파일경로 스택이름
docker stack deploy --compose-file daily-log.yml dailylog
중요! backend와 frontend는 replicas 가 있지만 db는 없음!