分批并委托给负载均衡器,做一次不停机发布
한국어 원문으로 표시합니다.
목표
호스트 집합을 배치로 쪼개고, 배포 중인 서버를 로드밸런서에서 빼고 넣고, 배치마다 상태를 판정해 사고가 다음 배치로 번지지 않게 하는 플레이북을 쓸 수 있게 됩니다.
왜 중요한가
기본 동작에서 Ansible 은 태스크 하나를 전 호스트에서 끝내고 다음 태스크로 갑니다. 서비스를 재시작하는 태스크가 있으면 그 순간 전 호스트가 함께 내려갑니다. 그래서 무중단 배포는 도구가 아니라 플레이북의 구조로 만듭니다. 쪼개고(serial), 빼고 넣고(delegate_to), 배치마다 판정합니다(max_fail_percentage). 이 중 하나만 빠져도 무중단이 아닙니다 - 빼지 않으면 요청이 배포 중인 서버로 들어가고, 판정하지 않으면 망가진 판이 남은 서버로 번집니다. 그리고 serial 을 걸면 run_once 와 핸들러의 의미까지 조용히 바뀝니다. 그 사실을 모르고 쓰면 '한 번만 돌 줄 알았던 태스크' 가 배치 수만큼 돕니다.
단계
/root/ans/roll/inventory/hosts.ini에 web 그룹(web1·web2·web3,ansible_host=127.0.0.1,ansible_port=2222)과 lb 그룹(lb1,ansible_connection=local)을 적으세요./root/ans/roll/p01.yml에serial: 2를 걸고, 호스트마다 자기 배치의 구성원을 쉼표로 이어/root/ans/roll/out/01-<호스트>.txt에 적게 하세요./root/ans/roll/p02.yml에serial을 목록[1, 100%]로 주어 카나리 배치를 만들고, 1단계와 같은 방식으로/root/ans/roll/out/02-<호스트>.txt에 배치 구성원을 적으세요./root/ans/roll/p03.yml에serial: 2를 걸고,run_once: true와delegate_to: lb1을 붙인 태스크 하나로/root/ans/roll/out/03-runonce.txt에batch <배치구성원> ran on <실행한호스트>형식의 줄을 남기세요./root/ans/roll/p04.yml을serial: 1로 만들고, 모든 태스크를 lb1 로 위임해/root/ans/roll/out/lb/디렉터리를 만든 뒤 호스트마다drained-<호스트>.txt와enabled-<호스트>.txt를 각각host=<호스트>내용으로 남기세요./root/ans/roll/p05.yml에서delegate_to: lb1과delegate_facts: true를 함께 준set_fact로lb_pool_size를 플레이 대상 수로 세우고, 그 값을hostvars로 읽어/root/ans/roll/out/05-lbfact.txt에lb_pool_size=<값> on_web=<웹 호스트에서 본 값>형식으로 남기세요. 웹 호스트 쪽에는 값이 없어야 합니다./root/ans/roll/p06.yml을serial: 2로 만들고, 호스트마다/root/ans/roll/out/06-<호스트>.conf를 놓는 태스크가 핸들러를 부르게 하세요. 핸들러는run_once: true와delegate_to: lb1로/root/ans/roll/out/06-handlers.txt에restarted: <배치구성원>줄을 남깁니다./root/ans/roll/p07.yml을serial: 1·max_fail_percentage: 0으로 만들고, 플레이vars의healthy_hosts를[web1, web3]으로 두세요. 태스크는/root/ans/roll/out/07-deployed-<호스트>.txt를 남기는 배포 표식과healthy_hosts에 들어 있는지를 보는assert확인 둘입니다. 실행 출력을/root/ans/roll/out/07-run.txt로 저장하세요./root/ans/roll/p08.yml에 플레이 둘을 두세요. 첫 플레이는 web 을serial: [1, 100%]·max_fail_percentage: 0으로 돌며 배치 기록을/root/ans/roll/out/08-batches.txt에 남기고, 호스트마다/root/ans/roll/out/08/아래에drained-·release-(내용release=2.4.0)·enabled-표식을 남기고 그 사이에assert로 상태를 확인합니다(세 대 모두 정상). 둘째 플레이는 lb1 에서 그 기록을 모아/root/ans/roll/out/rolling.json에batches·drained·enabled를 적습니다. 마지막으로 같은 플레이북을 한 번 더 돌려 출력을/root/ans/roll/out/08-run2.txt에 저장하되changed=0이어야 합니다.
참고
- web1·web2·web3 는 이 파드 안 sshd(127.0.0.1:2222) 한 대를 세 이름으로 흉내 낸 것이고 lb1 은 로컬 연결입니다. 정말 다른 기계로 갔는지는 이 환경에서 증명할 수 없으므로, 확인은 위임이 남긴 기록과 실행 로그의
web1 -> lb1표시로 합니다. - 배치가 몇 번 돌았는지는 실행 로그의
PLAY [...]머리글 수로 셉니다. throttle과strategy: free는 시간과 동시성으로만 드러나는데 이 환경에서는 그 측정이 흔들려 실습에서 뺐습니다. 읽기의 공식 문서 절을 참고하세요.- 흔한 실수: 빼기만 하고 복귀를 빠뜨리는 것. 플레이가 중간에 실패하면 마지막으로 뺀 서버가 로드밸런서 밖에 남습니다.
- 흔한 실수: 산출물 파일을 손으로 고치는 것. 채점은 파일뿐 아니라 플레이북을 점검 모드로 다시 태워 지금도 같은 결과가 나오는지 봅니다.
- Strategies and more · Delegation and local actions · Error handling · Playbook keywords
두 대씩 끊어 올리기
/root/ans/roll/inventory/hosts.ini 에 web 그룹(web1·web2·web3, ansible_host=127.0.0.1, ansible_port=2222)과 lb 그룹(lb1, ansible_connection=local)을 적으세요. /root/ans/roll/p01.yml 에 serial: 2 를 걸고, 호스트마다 자기 배치의 구성원을 쉼표로 이어 /root/ans/roll/out/01-<호스트>.txt 에 적게 하세요.
지금 배치에 누가 들어와 있는지는 실행 중에 변수로 알 수 있습니다. ansible_play_batch 를 쉼표로 이어 적으면 배치가 어떻게 나뉘었는지가 파일에 남습니다.
카나리 한 대 먼저, 나머지 한 번에
/root/ans/roll/p02.yml 에 serial 을 목록 [1, 100%] 로 주어 카나리 배치를 만들고, 1단계와 같은 방식으로 /root/ans/roll/out/02-<호스트>.txt 에 배치 구성원을 적으세요.
목록의 원소는 숫자와 비율을 섞어 쓸 수 있습니다. 마지막 원소를 100% 로 두면 '남은 전부' 라는 뜻이 됩니다.
run_once 는 배치마다 한 번이다
/root/ans/roll/p03.yml 에 serial: 2 를 걸고, run_once: true 와 delegate_to: lb1 을 붙인 태스크 하나로 /root/ans/roll/out/03-runonce.txt 에 batch <배치구성원> ran on <실행한호스트> 형식의 줄을 남기세요.
같은 줄을 여러 번 돌려도 파일이 늘어나지 않아야 합니다. 줄 단위로 '없으면 넣는' 모듈을 쓰세요. 몇 줄이 나오는지 세어 보면 run_once 의 범위가 드러납니다.
로드밸런서에서 빼고 다시 넣기
/root/ans/roll/p04.yml 을 serial: 1 로 만들고, 모든 태스크를 lb1 로 위임해 /root/ans/roll/out/lb/ 디렉터리를 만든 뒤 호스트마다 drained-<호스트>.txt 와 enabled-<호스트>.txt 를 각각 host=<호스트> 내용으로 남기세요.
위임된 태스크 안에서도 대상은 원래 호스트입니다. 파일 이름과 내용에 그 이름을 그대로 쓰면 '누구를 뺐는지' 가 로드밸런서 쪽 기록에 남습니다. 이 단계에서는 배치마다가 아니라 호스트마다 일어나야 합니다.
사실을 누구 앞으로 적을 것인가
/root/ans/roll/p05.yml 에서 delegate_to: lb1 과 delegate_facts: true 를 함께 준 set_fact 로 lb_pool_size 를 플레이 대상 수로 세우고, 그 값을 hostvars 로 읽어 /root/ans/roll/out/05-lbfact.txt 에 lb_pool_size=<값> on_web=<웹 호스트에서 본 값> 형식으로 남기세요. 웹 호스트 쪽에는 값이 없어야 합니다.
플레이 대상 수는 실행 중에 변수로 알 수 있습니다. 웹 호스트 쪽에서 같은 이름을 읽을 때는 없을 수도 있으니 기본값을 주어 없음 이 찍히게 하세요.
핸들러는 플레이 끝이 아니라 배치 끝에 돈다
/root/ans/roll/p06.yml 을 serial: 2 로 만들고, 호스트마다 /root/ans/roll/out/06-<호스트>.conf 를 놓는 태스크가 핸들러를 부르게 하세요. 핸들러는 run_once: true 와 delegate_to: lb1 로 /root/ans/roll/out/06-handlers.txt 에 restarted: <배치구성원> 줄을 남깁니다.
핸들러는 이름으로 이어집니다. 몇 줄이 남는지 세어 보면 핸들러가 언제 도는지 알 수 있습니다 - 플레이 끝에 한 번이라면 한 줄이어야 합니다.
한 대가 무너지면 거기서 멈춘다
/root/ans/roll/p07.yml 을 serial: 1 · max_fail_percentage: 0 으로 만들고, 플레이 vars 의 healthy_hosts 를 [web1, web3] 으로 두세요. 태스크는 /root/ans/roll/out/07-deployed-<호스트>.txt 를 남기는 배포 표식과 healthy_hosts 에 들어 있는지를 보는 assert 확인 둘입니다. 실행 출력을 /root/ans/roll/out/07-run.txt 로 저장하세요.
이 플레이북은 일부러 실패합니다. 출력을 파일로 받을 때 실패로 스크립트가 멈추지 않게 하세요. 세 번째 호스트의 배포 표식이 생기는지 아닌지가 이 단계의 답입니다.
한 바퀴를 돌고 요약을 남긴다
/root/ans/roll/p08.yml 에 플레이 둘을 두세요. 첫 플레이는 web 을 serial: [1, 100%] · max_fail_percentage: 0 으로 돌며 배치 기록을 /root/ans/roll/out/08-batches.txt 에 남기고, 호스트마다 /root/ans/roll/out/08/ 아래에 drained-·release-(내용 release=2.4.0)·enabled- 표식을 남기고 그 사이에 assert 로 상태를 확인합니다(세 대 모두 정상). 둘째 플레이는 lb1 에서 그 기록을 모아 /root/ans/roll/out/rolling.json 에 batches·drained·enabled 를 적습니다. 마지막으로 같은 플레이북을 한 번 더 돌려 출력을 /root/ans/roll/out/08-run2.txt 에 저장하되 changed=0 이어야 합니다.
빼기와 넣기는 로드밸런서에 위임하고 배포는 대상에서 합니다. 표식을 세는 것은 파일을 찾는 모듈로, 배치 기록을 읽는 것은 파일을 읽어 오는 모듈로 하면 두 번째 플레이가 짧아집니다. 두 번째 실행이 조용하려면 모든 태스크가 멱등해야 합니다.