Ansible 실전 · 무중단 배포는 플레이북의 구조 문제다 · 실습
배치로 쪼개고 로드밸런서에 위임해 무중단으로 올리기
목표
호스트 집합을 배치로 쪼개고, 배포 중인 서버를 로드밸런서에서 빼고 넣고, 배치마다 상태를 판정해 사고가 다음 배치로 번지지 않게 하는 플레이북을 쓸 수 있게 됩니다.
왜 중요한가
기본 동작에서 Ansible 은 태스크 하나를 전 호스트에서 끝내고 다음 태스크로 갑니다. 서비스를 재시작하는 태스크가 있으면 그 순간 전 호스트가 함께 내려갑니다. 그래서 무중단 배포는 도구가 아니라 플레이북의 구조로 만듭니다. 쪼개고(serial), 빼고 넣고(delegate_to), 배치마다 판정합니다(max_fail_percentage). 이 중 하나만 빠져도 무중단이 아닙니다 - 빼지 않으면 요청이 배포 중인 서버로 들어가고, 판정하지 않으면 망가진 판이 남은 서버로 번집니다. 그리고 serial 을 걸면 run_once 와 핸들러의 의미까지 조용히 바뀝니다. 그 사실을 모르고 쓰면 '한 번만 돌 줄 알았던 태스크' 가 배치 수만큼 돕니다.
단계
1. /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 에 적게 하세요.
2. /root/ans/roll/p02.yml 에 serial 을 목록 [1, 100%] 로 주어 카나리 배치를 만들고, 1단계와 같은 방식으로 /root/ans/roll/out/02-<호스트>.txt 에 배치 구성원을 적으세요.
3. /root/ans/roll/p03.yml 에 serial: 2 를 걸고, run_once: true 와 delegate_to: lb1 을 붙인 태스크 하나로 /root/ans/roll/out/03-runonce.txt 에 batch <배치구성원> ran on <실행한호스트> 형식의 줄을 남기세요.
4. /root/ans/roll/p04.yml 을 serial: 1 로 만들고, 모든 태스크를 lb1 로 위임해 /root/ans/roll/out/lb/ 디렉터리를 만든 뒤 호스트마다 drained-<호스트>.txt 와 enabled-<호스트>.txt 를 각각 host=<호스트> 내용으로 남기세요.
5. /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=<웹 호스트에서 본 값> 형식으로 남기세요. 웹 호스트 쪽에는 값이 없어야 합니다.
6. /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: <배치구성원> 줄을 남깁니다.
7. /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 로 저장하세요.
8. /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](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html) · [Delegation and local actions](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_delegation.html) · [Error handling](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html) · [Playbook keywords](https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html)
단계 8개
- 두 대씩 끊어 올리기
- 카나리 한 대 먼저, 나머지 한 번에
- run_once 는 배치마다 한 번이다
- 로드밸런서에서 빼고 다시 넣기
- 사실을 누구 앞으로 적을 것인가
- 핸들러는 플레이 끝이 아니라 배치 끝에 돈다
- 한 대가 무너지면 거기서 멈춘다
- 한 바퀴를 돌고 요약을 남긴다