LabHub

Ansible 기초 · 변수와 팩트 · 이론

변수 우선순위와 팩트

LabHub 에서 이어서 보기

한 줄 요약

Ansible 에서 "변수가 안 먹는다"는 대부분 변수가 없어서가 아니라 더 센 곳에서 정의된 값이 이기고 있어서다.

왜 이게 필요했나

같은 애플리케이션을 dev·stage·prod 에 배포한다고 하자. 포트와 복제 수와 로그 레벨만 다르다. 이때 플레이북을 세 벌 복사하면 6개월 뒤에는 세 파일이 서로 다른 생물이 되어 있다. 값을 코드 밖으로 빼내는 것은 취향이 아니라 분기가 늘어나는 것을 막는 구조적 선택이다.

문제는 값을 넣을 수 있는 자리가 너무 많다는 점이다. 플레이의 vars, 별도 vars_files, group_vars/, host_vars/, 인벤토리 안의 변수, 명령줄 -e, 롤의 defaultsvars, 그리고 실행 중 set_fact 로 만든 값까지. 이 자리마다 우선순위가 다르고, 그 순서를 모르면 "분명히 값을 바꿨는데 반영이 안 되는" 하루를 보낸다.

어떻게 동작하나

세부 순서는 길지만 실무에서 기억할 뼈대는 짧다.

| 강도 | 자리 | 성격 |
| --- | --- | --- |
| 가장 약함 | 롤의 defaults/main.yml | "이 롤의 기본값" — 덮어쓰라고 만든 자리 |
| 약함 | 인벤토리 그룹 변수 | 환경별 공통값 |
| 중간 | 인벤토리 호스트 변수 | 그 서버만의 예외 |
| 강함 | 플레이의 vars, vars_files | 이 실행에서의 값 |
| 매우 강함 | set_fact 로 만든 값 | 실행 중 계산된 값 |
| 가장 강함 | 명령줄 -e (extra vars) | 무엇이든 이긴다 |

두 가지 원칙만 지키면 대부분 해결된다. 첫째, 덮어써도 되는 값은 defaults 에 둔다. 둘째, -e 는 일회성 예외에만 쓴다. -e 가 습관이 되면 그 값이 어디에 기록되지 않아 다음 사람이 재현할 수 없다.

팩트(fact)는 성격이 다르다. 이것은 사람이 적는 값이 아니라 대상 서버에서 수집한 사실이다. gather_facts: true 면 플레이 시작 시 setup 모듈이 돌아 OS 종류, 아키텍처, 호스트 이름, 네트워크 인터페이스, 메모리 같은 것을 모아 ansible_facts 아래에 넣는다. 팩트를 쓰면 "우분투면 apt, RHEL 이면 dnf" 같은 분기를 대상별로 자동으로 태울 수 있다.

수집에는 비용이 있다. 호스트가 수백 대면 팩트 수집만으로 수십 초가 나간다. 팩트가 필요 없는 플레이는 gather_facts: false 로 꺼야 하고, 반복 실행이 잦다면 팩트 캐싱을 고려한다.

register 는 세 번째 종류다. 태스크의 실행 결과 전체(표준 출력, 종료 코드, changed 여부)를 변수에 담는다. 여기서 흔한 실수가 결과 객체 전체를 그대로 파일에 쓰는 것이다. 필요한 것은 대개 .stdout 하나다.

현장에서 만나는 모습

첫째, -e 로 급한 불을 끄고 코드에 반영하지 않는 것. 장애 대응 중 -e replicas=10 으로 넘겨 서비스를 살렸다면, 그 값은 반드시 저장소에 커밋되어야 한다. 그러지 않으면 다음 배포가 조용히 그것을 되돌린다. 이것은 Terraform 의 드리프트와 정확히 같은 구조의 사고다.

둘째, 팩트를 신뢰하되 검증하기. ansible_distribution 같은 팩트는 대체로 정확하지만, 컨테이너나 특수 이미지에서는 예상과 다른 값이 나온다. 팩트로 분기할 때는 예상 밖의 값에 대한 기본 분기를 남겨 둔다.

다음 실습에서 할 것

플레이 변수·변수 파일·그룹 변수·호스트 변수를 각각 만들어 어느 것이 이기는지 눈으로 확인하고, 명령줄 -e 가 그 전부를 이기는 것을 본다. 팩트를 수집해 JSON 으로 남기고, registerset_fact 로 값을 조합해 최종 요약 파일을 만든다.