LabHub
배우기 러닝패스 코스

Ansible Fundamentals

We moved the inventory into a directory and half the groups vanished

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

인벤토리 소스가 여러 개일 때 무엇이 합쳐지고 무엇이 이기는지를 하나씩 실측합니다. 마지막에는 '이 변수는 결국 어느 값이 이기는가' 를 답해 주는 도구를 직접 만듭니다.

왜 중요한가

인벤토리가 파일 하나일 때는 읽으면 압니다. 그런데 파일 하나로 끝나는 조직은 드뭅니다 — 공통 호스트는 플랫폼 팀이, 서비스별 호스트는 각 팀이 관리하고, 운영과 스테이징은 파일을 나누며, 클라우드 자원은 동적 소스가 만들어 냅니다. 그러면 사고가 두 종류로 납니다. 같은 그룹 이름 때문에 엉뚱한 서버가 대상에 들어오는 것, 그리고 옛 파일이나 새 group_vars 때문에 엉뚱한 값이 이기는 것입니다. 둘 다 파일을 읽어 추론하는 방식으로는 막지 못합니다. 막는 방법은 하나뿐입니다 — 합쳐진 결과를 실행 전에 기계에게 묻는 것. 이 실습은 그 질문을 여덟 번 던지고, 마지막에 그 질문을 대신 던져 주는 도구를 남깁니다.

단계

  1. /root/ans/inv/src/base.iniweb 그룹(web1, web2)과 [web:vars] tier=base 를, /root/ans/inv/src/extra.iniweb 그룹(web3) · db 그룹(db1) · [web:vars] tier=extra 를 적으세요. 모든 호스트는 ansible_host=127.0.0.1 이고 base.ini[all:vars]ansible_port=2222ansible_user=root 를 둡니다. -i 를 두 번 주어(base.ini 먼저) 합쳐진 결과를 /root/ans/inv/out/merged.json 에, 그래프를 /root/ans/inv/out/merged-graph.txt 에 저장하고, 합쳐진 뒤 web1tier 가 무엇인지를 /root/ans/inv/out/two-sources.txttier=<값> 한 줄로 적으세요.
  2. /root/ans/inv/dir/ 을 만들고 1단계의 두 파일과 같은 내용을 확장자 없이 10-base20-extra 로 넣으세요. 거기에 /root/ans/inv/dir/30-late.ini 를 하나 더 두는데, 이 파일은 web 그룹에 web9 를 넣고 [web:vars] tier=late 를 적습니다. -i /root/ans/inv/dir 로 합쳐진 결과를 /root/ans/inv/out/dir-merged.json 에 저장하고, /root/ans/inv/out/dir-order.txt 에 두 줄을 적으세요 — 첫 줄은 web1tiertier=<값> 으로, 둘째 줄은 디렉터리를 훑을 때 건너뛰어진 파일 이름을 skipped=<파일이름> 으로.
  3. /root/ans/inv/dir/group_vars/all.ymlpool: gv-allowner: platform 을, /root/ans/inv/dir/group_vars/web.ymlpool: gv-web 을, /root/ans/inv/dir/host_vars/web1.ymlpool: hv-web1 을 적으세요. 그리고 /root/ans/inv/out/levels.json 에 세 호스트가 최종적으로 갖는 pool 값을 web1·web2·db1 세 키의 JSON 으로 적으세요.
  4. /root/ans/inv/dir/20-extra[web:vars]region=inline-extra 를 더하고, /root/ans/inv/dir/group_vars/web.ymlregion: file-web 을 더하세요. 그리고 /root/ans/inv/out/inline-vs-file.txt 에 두 줄을 적으세요 — 첫 줄은 web2 가 최종적으로 갖는 값을 region=<값> 으로, 둘째 줄은 그 값이 어디서 왔는지를 source=inline 또는 source=group_vars 중 하나로.
  5. /root/ans/inv/prio/hosts.ini 를 만드세요 — 호스트 app1alphazulu 두 그룹에 모두 속하고, [alpha:vars]stack=from-alpha, [zulu:vars]stack=from-zulu 를 적습니다. 그리고 [alpha:vars]ansible_group_priority=10 을 더해 alpha 가 이기게 하세요. /root/ans/inv/out/priority-before.txt 에는 그 줄이 없을 때 이기는 값을, /root/ans/inv/out/priority-after.txt 에는 그 줄이 있을 때 이기는 값을 각각 stack=<값> 한 줄로 적으세요.
  6. /root/ans/inv/tree/hosts.ini 를 만드세요 — web 그룹에 web1, db 그룹에 db1 을 넣고 두 그룹을 zprod 의 자식으로 묶습니다. [zprod:vars]env=from-zprodowner=platform 을, [web:vars]env=from-web 을 적으세요. 그리고 /root/ans/inv/out/children.txt 에 세 줄을 사전순 그대로 적으세요 — db1.env=<값> · web1.env=<값> · web1.owner=<값>.
  7. /root/ans/inv/pat/hosts.ini 를 만드세요 — web 그룹에 web1·web2·web3, db 그룹에 db1, 두 그룹을 prod 의 자식으로 묶고, staging 그룹에 web3db1 을 넣습니다. 그리고 web:&prod:!staging 패턴에 맞는 호스트 이름만 한 줄에 하나씩 사전순으로 /root/ans/inv/out/pattern-hosts.txt 에 저장하고, 그래프를 /root/ans/inv/out/pat-graph.txt 에 저장하세요.
  8. /root/ans/inv/whowins.sh 를 쓰세요. 인자를 셋 받습니다 — 인벤토리 경로 · 호스트 이름 · 변수 이름. 그 호스트가 최종적으로 갖는 값을 <변수>=<값> 한 줄로 내고, 그 변수가 정의돼 있지 않으면 표준 오류에 까닭을 적고 0 이 아닌 값으로 끝나야 합니다. 그 도구로 /root/ans/inv/out/merge-report.txt 를 네 줄로 만드세요 — dirweb1tier, dirweb1pool, dirweb2region, prio/hosts.iniapp1stack 순서입니다.

참고

소스를 두 개 주면 무엇이 합쳐지나

/root/ans/inv/src/base.iniweb 그룹(web1, web2)과 [web:vars] tier=base 를, /root/ans/inv/src/extra.iniweb 그룹(web3) · db 그룹(db1) · [web:vars] tier=extra 를 적으세요. 모든 호스트는 ansible_host=127.0.0.1 이고 base.ini[all:vars]ansible_port=2222ansible_user=root 를 둡니다. -i 를 두 번 주어(base.ini 먼저) 합쳐진 결과를 /root/ans/inv/out/merged.json 에, 그래프를 /root/ans/inv/out/merged-graph.txt 에 저장하고, 합쳐진 뒤 web1tier 가 무엇인지를 /root/ans/inv/out/two-sources.txttier=<값> 한 줄로 적으세요.

호스트와 그룹은 합집합이 되고 같은 이름의 변수는 나중에 읽힌 소스가 이깁니다. 합쳐진 결과를 보는 명령은 --list--graph 두 가지이고, 한 호스트의 최종 변수만 보려면 --host 를 씁니다. 값을 짐작해서 적지 말고 실제로 물어서 적으세요 — 채점기도 같은 방법으로 다시 계산해 대조합니다.

디렉터리를 주면 파일 이름이 순서를 정한다

/root/ans/inv/dir/ 을 만들고 1단계의 두 파일과 같은 내용을 확장자 없이 10-base20-extra 로 넣으세요. 거기에 /root/ans/inv/dir/30-late.ini 를 하나 더 두는데, 이 파일은 web 그룹에 web9 를 넣고 [web:vars] tier=late 를 적습니다. -i /root/ans/inv/dir 로 합쳐진 결과를 /root/ans/inv/out/dir-merged.json 에 저장하고, /root/ans/inv/out/dir-order.txt 에 두 줄을 적으세요 — 첫 줄은 web1tiertier=<값> 으로, 둘째 줄은 디렉터리를 훑을 때 건너뛰어진 파일 이름을 skipped=<파일이름> 으로.

디렉터리 안의 파일은 이름 순서대로 읽힙니다. 그런데 셋 중 하나는 읽히지 않습니다 — 그 파일이 넣으려던 호스트가 결과에 있는지 보면 바로 알 수 있습니다. 설정 항목 inventory_ignore_extensions 의 기본 목록을 ansible-config list 로 확인해 보세요. 파일 이름만 적습니다(경로가 아닙니다).

그룹 변수와 호스트 변수가 만드는 세 층

/root/ans/inv/dir/group_vars/all.ymlpool: gv-allowner: platform 을, /root/ans/inv/dir/group_vars/web.ymlpool: gv-web 을, /root/ans/inv/dir/host_vars/web1.ymlpool: hv-web1 을 적으세요. 그리고 /root/ans/inv/out/levels.json 에 세 호스트가 최종적으로 갖는 pool 값을 web1·web2·db1 세 키의 JSON 으로 적으세요.

이 디렉터리들은 인벤토리 에 있어야 읽힙니다. 넓은 것부터 좁은 것 순서로 덮이고 좁은 것이 이깁니다 — 모두에게 걸리는 것, 그 그룹에만 걸리는 것, 그 호스트에만 걸리는 것. 세 값을 손으로 추론하지 말고 호스트마다 물어서 적으세요.

인벤토리 파일 안의 그룹 변수가 가장 약하다

/root/ans/inv/dir/20-extra[web:vars]region=inline-extra 를 더하고, /root/ans/inv/dir/group_vars/web.ymlregion: file-web 을 더하세요. 그리고 /root/ans/inv/out/inline-vs-file.txt 에 두 줄을 적으세요 — 첫 줄은 web2 가 최종적으로 갖는 값을 region=<값> 으로, 둘째 줄은 그 값이 어디서 왔는지를 source=inline 또는 source=group_vars 중 하나로.

같은 디렉터리에 있어도 두 자리의 세기가 다릅니다. 공식 우선순위 목록에서 inventory file group vars 와 inventory group_vars 중 어느 쪽이 아래에 있는지가 답입니다. web1 이 아니라 web2 로 물어야 호스트 변수에 가려지지 않습니다.

같은 깊이의 그룹은 사전순, 그것을 뒤집는 손잡이

/root/ans/inv/prio/hosts.ini 를 만드세요 — 호스트 app1alphazulu 두 그룹에 모두 속하고, [alpha:vars]stack=from-alpha, [zulu:vars]stack=from-zulu 를 적습니다. 그리고 [alpha:vars]ansible_group_priority=10 을 더해 alpha 가 이기게 하세요. /root/ans/inv/out/priority-before.txt 에는 그 줄이 없을 때 이기는 값을, /root/ans/inv/out/priority-after.txt 에는 그 줄이 있을 때 이기는 값을 각각 stack=<값> 한 줄로 적으세요.

손잡이가 없을 때의 기본 규칙은 이름입니다 — 사전순으로 병합되고 뒤가 이깁니다. 그 값을 확인하려면 그 줄을 뺀 사본을 잠깐 만들어 물어보면 됩니다(원본은 그대로 두세요). 이 변수는 인벤토리 소스 안에 적어야 듣습니다. group_vars 파일에 적으면 아무 일도 일어나지 않습니다.

자식 그룹이 부모 그룹을 이긴다

/root/ans/inv/tree/hosts.ini 를 만드세요 — web 그룹에 web1, db 그룹에 db1 을 넣고 두 그룹을 zprod 의 자식으로 묶습니다. [zprod:vars]env=from-zprodowner=platform 을, [web:vars]env=from-web 을 적으세요. 그리고 /root/ans/inv/out/children.txt 에 세 줄을 사전순 그대로 적으세요 — db1.env=<값> · web1.env=<값> · web1.owner=<값>.

부모 이름을 일부러 사전순으로 뒤에 오게 지었습니다 — 그래야 이긴 이유가 이름이 아니라 깊이라는 것이 드러납니다. 부모는 넓고 자식은 좁으며 언제나 좁은 것이 이깁니다. 자식이 정의하지 않은 변수는 부모의 값이 그대로 내려옵니다. 세 값 모두 물어서 적으세요.

패턴으로 대상을 좁히고 눈으로 확인하기

/root/ans/inv/pat/hosts.ini 를 만드세요 — web 그룹에 web1·web2·web3, db 그룹에 db1, 두 그룹을 prod 의 자식으로 묶고, staging 그룹에 web3db1 을 넣습니다. 그리고 web:&prod:!staging 패턴에 맞는 호스트 이름만 한 줄에 하나씩 사전순으로 /root/ans/inv/out/pattern-hosts.txt 에 저장하고, 그래프를 /root/ans/inv/out/pat-graph.txt 에 저장하세요.

패턴 기호는 합집합·교집합·차집합 셋입니다. 대상 목록만 뽑아 주는 옵션이 있는데, 그 출력의 첫 줄은 개수라 호스트 이름이 아닙니다. 공백도 함께 들어오니 다듬어 저장하세요. 차집합은 결과가 비어도 오류가 아니므로 실행 전에 눈으로 세어 보는 습관이 중요합니다.

이 변수는 결국 어느 값이 이기는가 — 도구로 만들기

/root/ans/inv/whowins.sh 를 쓰세요. 인자를 셋 받습니다 — 인벤토리 경로 · 호스트 이름 · 변수 이름. 그 호스트가 최종적으로 갖는 값을 <변수>=<값> 한 줄로 내고, 그 변수가 정의돼 있지 않으면 표준 오류에 까닭을 적고 0 이 아닌 값으로 끝나야 합니다. 그 도구로 /root/ans/inv/out/merge-report.txt 를 네 줄로 만드세요 — dirweb1tier, dirweb1pool, dirweb2region, prio/hosts.iniapp1stack 순서입니다.

파일을 grep 해서 답하면 group_vars 도 그룹 우선순위도 자식 그룹도 보지 못합니다. 합쳐진 결과를 내놓는 명령에게 직접 물으세요. 값이 없는 것과 값이 빈 문자열인 것을 구분하려면 키가 있는지를 먼저 확인해야 합니다. 채점기는 자기가 만든 인벤토리로도 이 도구를 돌려 보고, 정의되지 않은 변수를 물었을 때 어떻게 끝나는지도 봅니다.