LabHub
배우기 러닝패스 코스

Ansible Fundamentals

The Inventory — Automation's Address Book

LabHub 에서 이어서 보기

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

한 줄 요약

Ansible 은 "무엇을 할지"보다 "누구에게 할지"를 먼저 묻는다. 그 답이 인벤토리다.

Layer map: "어느 노드에 무엇을 했는지"를 사람이 기억하는 순간부터 실수가 시작된다 · 그룹이 계층을 이룬다 · 더 좁은 범위가 이긴다 · 첫째, "왜 한 대만 안 됐지".

왜 이게 필요했나

서버가 세 대일 때는 터미널 세 개를 열면 된다. 일곱 대가 되면 창을 잘못 고르는 사고가 난다. 홈랩을 3노드에서 7노드로 늘린 기록을 보면, 노드를 붙이는 절차 자체는 어렵지 않은데 "어느 노드에 무엇을 했는지"를 사람이 기억하는 순간부터 실수가 시작된다. 실제로 새로 붙인 두 노드에는 예전 클러스터의 잔재(구버전 kubelet, 옛 인증서)가 남아 있었고, 그걸 정리하는 절차를 손으로 하다 보면 한 대는 빠뜨린다.

인벤토리는 이 문제를 "목록을 파일로 만든다"로 뒤집는다. 파일에 적혀 있지 않은 서버는 자동화 대상이 아니고, 파일에 적힌 서버는 전부 같은 대접을 받는다. 이 단순한 규칙이 "한 대만 설정이 다른" 상황을 구조적으로 없앤다.

어떻게 동작하나

인벤토리에는 세 가지가 들어간다.

요소 무엇인가
호스트 접속할 대상 하나 web1
그룹 호스트의 묶음 [web], [db]
변수 호스트/그룹에 딸린 값 ansible_port=2222, app_port=8080

핵심은 그룹이 계층을 이룬다는 점이다. [prod:children] 아래에 webdb 를 넣으면 prod 는 두 그룹의 모든 호스트를 포함한다. 그리고 모든 호스트는 자동으로 all 그룹에 속한다. 변수는 위에서 아래로 흐르되, 더 좁은 범위가 이긴다all 의 값보다 그룹의 값이, 그룹의 값보다 호스트의 값이 우선한다.

형식은 INI 와 YAML 두 가지다. INI 는 짧아서 손으로 쓰기 좋고, YAML 은 중첩 구조와 복잡한 변수를 담기 좋다. 둘 중 무엇을 쓰든 ansible-inventory --list 로 뽑아 보면 결국 같은 JSON 이 된다. 인벤토리를 의심할 때는 파일을 노려보지 말고 이 명령으로 실제 해석 결과를 봐라. 오타 하나로 그룹이 통째로 비어 있는 것을 3초 만에 알 수 있다.

현장에서 만나는 모습

첫째, "왜 한 대만 안 됐지". 대상을 좁힐 때 --limit 를 쓰지 않고 인벤토리에서 호스트를 잠시 지우는 사람이 있다. 그러면 그 파일이 그대로 커밋되어 며칠 뒤 그 서버만 패치에서 빠진다. 대상 축소는 인벤토리가 아니라 실행 옵션으로 한다.

둘째, 접속 정보도 변수다. ansible_host, ansible_port, ansible_user 는 특별한 변수처럼 보이지만 그냥 변수다. 그래서 점프 호스트나 비표준 포트 같은 환경 차이를 코드 수정 없이 인벤토리에서 흡수할 수 있다. 이 실습 환경도 sshd 가 127.0.0.1:2222 에 떠 있어서 ansible_port 로 그 차이를 다룬다.

셋째, 동적 인벤토리. 클라우드에서는 서버 목록이 매일 바뀌므로 파일 대신 스크립트가 목록을 만든다. 그래도 개념은 같다 — 그룹과 변수를 담은 JSON 을 만들어 주는 것뿐이다. 정적 인벤토리를 제대로 이해하면 동적 인벤토리는 출력 형식만 다른 같은 물건이다.

변수를 어디에 둘 것인가

인벤토리 파일 안에 변수를 잔뜩 적으면 금방 읽기 어려워진다. 그래서 실무에서는 변수를 별도 디렉터리로 뺀다. 인벤토리 옆에 group_vars/host_vars/ 를 두면, group_vars/web.yml 은 web 그룹 전체에, host_vars/web1.yml 은 그 호스트 하나에 적용된다. 파일 이름이 곧 적용 범위라서 어디를 고쳐야 하는지 헤맬 일이 없다.

우선순위는 앞에서 본 대로 좁은 쪽이 이긴다. 다만 실제 순서는 그보다 길고, 자주 부딪히는 것만 정리하면 이렇다.

  1. 명령줄의 -e(가장 강하다)
  2. 작업이나 블록에 직접 적은 값
  3. host_vars/
  4. group_vars/(자식 그룹이 부모 그룹을 이긴다)
  5. group_vars/all
  6. 역할의 기본값(defaults/, 가장 약하다)

역할의 기본값이 가장 약한 것은 의도된 설계다. 역할은 "이 값이 없으면 이렇게 하겠다" 를 적는 자리이고, 그것을 쓰는 쪽이 언제나 덮어쓸 수 있어야 한다. 반대로 역할 안의 vars/ 는 훨씬 강해서 덮어쓰기 어려우므로, 정말 바뀌면 안 되는 것에만 쓴다.

여기에 실무 규칙 하나를 더한다. 비밀은 인벤토리에 평문으로 두지 않는다. 저장소에 커밋되는 순간 되돌릴 수 없고, 지워도 이력에 남는다. 암호화된 변수 파일이나 외부 비밀 저장소에서 가져오는 방식을 쓰되, 어느 쪽이든 비밀이 아닌 값과 파일을 나눠 두는 편이 좋다. 한 파일에 섞여 있으면 평범한 설정 하나를 고치려고 매번 암호를 풀어야 하고, 그러다 보면 결국 아무도 암호화를 쓰지 않게 된다.

다음 실습에서 할 것

/root/ans/inventory/hosts.ini 에 web·db 그룹과 prod 상위 그룹을 만들고, 같은 구조를 YAML 로도 표현한다. 그다음 애드혹 명령으로 세 호스트에 한 번에 접속하고, --limit 로 대상을 좁혀 본다. 마지막에는 인벤토리를 JSON 으로 뽑아 그룹별 호스트 보고서를 만든다.