TT Lab
시작하기
배우기 러닝패스 코스

Ansible 실전

변수 우선순위 - 표를 외우기 전에 재 보라

TT Lab 에서 이어서 보기

한 줄 요약

Ansible 에서 같은 이름의 변수를 심을 수 있는 자리는 스물두 개이고, 그 순서를 외우는 것보다 자리를 줄이는 설계가 사고를 더 확실히 막는다.

왜 이게 필요했나

"분명히 group_vars 에 포트를 8080 으로 적었는데 9090 으로 뜬다." 이런 신고는 거의 언제나 같은 모양이다. 누군가 급할 때 명령줄에 -e 를 붙여 돌렸고, 그 사실이 어디에도 남지 않았다. 또는 롤 안에 vars/main.yml 이 있었고 그것이 플레이의 vars_files 를 이겼다.

이 문제가 어려운 이유는 틀린 값이 오류로 나타나지 않기 때문이다. 플레이북은 성공하고, 파일은 만들어지고, 다만 내용이 다르다. 문법 검사도 린트도 이걸 잡지 못한다. 잡을 수 있는 것은 "지금 이 자리에서 이 이름이 무엇으로 풀리는가"를 실제로 재 보는 일뿐이다.

그래서 이 모듈은 공식 문서의 목록을 옮겨 적는 대신, 같은 이름을 한 자리씩 더 심어 가며 승자가 어떻게 바뀌는지 측정한다. 한 번 재 본 사람은 표를 외우지 않아도 다음에 같은 상황에서 무엇을 먼저 의심해야 할지 안다.

롤 안에 나란히 있는 defaults 와 vars

같은 롤 디렉터리 안에 있지만 두 파일은 우선순위 표의 양 끝에 가깝다. 본문이 실습에서 잰 열두 자리 기준으로 defaults 는 맨 아래 1번이고 vars/main.yml 은 7번이다.

  • defaults/main.yml맨 아래다. 밖에서 덮어쓰라고 내미는 값이라서 인벤토리의 group_vars 는 물론 플레이의 vars 도 이긴다.
  • vars/main.yml한참 위다. 밖에서 건드리지 말라는 롤 내부 값이라서 플레이의 vars_files 도 이긴다. 롤 저자의 의도가 어느 자리에 두느냐에 담긴다.

여기서 구분할 것 공식 문서는 자리를 스물두 개로 늘어놓고 본문 표는 그 가운데 실습에서 잰 열두 자리다. 틀린 값은 오류가 아니라 다른 내용으로 나타나므로 문법 검사나 린트가 잡지 못한다. 순서를 외우기보다 같은 이름을 심을 자리를 줄이는 설계가 사고를 막는다.

잠깐, 예측해 보세요 롤의 defaults 와 인벤토리의 group_vars/all 에 같은 이름의 변수가 있다. 롤 저자가 defaults 에 둔 것은 어떤 의도이고 태스크에서 보이는 값은 어느 쪽일까?

설명 확인 · 채점 없는 자가 점검

밖에서 덮어써도 된다는 의도다. 표에서 defaults 는 1번, group_vars/all 은 2번이라 group_vars/all 의 값이 보인다.

근거 문서

어떻게 동작하나

공식 문서는 자리를 낮은 것부터 높은 것까지 스물두 개로 늘어놓는다. 실습에서 재는 열두 자리를 낮은 것부터 적으면 이렇다.

순위 자리 성격
1 롤 defaults/main.yml "밖에서 덮어쓰라" 고 내미는 값
2 인벤토리 group_vars/all 모든 호스트의 바탕값
3 인벤토리 group_vars/<그룹> 그룹별 값
4 인벤토리 host_vars/<호스트> 호스트별 값
5 플레이 vars: 이 플레이에서만
6 플레이 vars_files: 이 플레이가 읽어 들인 파일
7 롤 vars/main.yml "밖에서 건드리지 말라" 는 롤 내부 값
8 블록 vars: 블록 안에서만
9 태스크 vars: 태스크 하나에서만
10 set_fact 실행 중에 세운 값
11 롤 호출 인자 롤을 부르며 넘긴 값
12 명령줄 -e 무엇이든 이긴다

여기서 놀라는 자리가 셋이다.

첫째, vars_files 가 플레이 vars: 보다 높다. 같은 플레이 안에서 바로 위에 적은 vars: 가 아래에서 읽어 들인 파일에 진다. 순서를 눈으로 읽는 감각과 반대다.

둘째, 롤의 defaults 와 vars 는 정반대다. 같은 롤 디렉터리 안에 나란히 있지만 defaults 는 맨 아래, vars 는 한참 위다. 이 차이가 곧 롤 저자의 의도다 - 밖에서 바꿔도 되는 값은 defaults 에, 바꾸면 안 되는 값은 vars 에 둔다. 남의 롤을 쓰다가 "아무리 덮어써도 안 바뀐다" 면 그 값은 vars/main.yml 에 있다.

셋째, 범위가 좁을수록 높다. 플레이 < 블록 < 태스크 순서는 외울 것이 아니라 규칙이다. 좁은 자리에 적은 사람이 더 구체적인 의도를 가졌다고 보는 것이다.

측정에 쓰는 도구도 알아 둘 값어치가 있다. 인벤토리 안에서의 승부는 ansible-inventory --list 가 이미 합쳐진 결과를 JSON 으로 보여 준다. 플레이 안에서의 승부는 debug 태스크 하나를 끼워 넣고 돌려 보는 것이 가장 빠르다.

ansible-inventory -i inventory --list   # 인벤토리 세 자리가 합쳐진 결과
ansible-inventory -i inventory --graph  # 그룹 구조

인벤토리를 디렉터리로 줄 때 걸리는 함정이 하나 있다. 디렉터리 안의 .ini 확장자 파일은 기본 설정에서 무시된다(INVENTORY_IGNORE_EXTS). 파일 하나를 -i 로 줄 때는 잘 되던 hosts.ini 가 디렉터리 안에 들어가는 순간 사라지는 것이다. 호스트가 하나도 안 보이면 이것부터 의심한다.

현장에서 만나는 모습

첫째, 딕셔너리는 합쳐지지 않는다. svc_limits: {cpu: "1", memory: 1Gi} 를 낮은 자리에 두고 높은 자리에서 svc_limits: {memory: 2Gi} 를 주면 결과는 {memory: 2Gi} 다. cpu 는 사라진다. 합치고 싶으면 combine 필터로 명시해야 한다. 전역 설정 hash_behaviour = merge 로 바꾸는 방법도 있지만, 그 설정은 저장소 전체의 동작을 바꾸므로 공식 문서도 권하지 않는다.

둘째, -e 는 되돌릴 수 없다. 명령줄 값은 어느 자리보다 높고 플레이북 안에서 덮을 방법이 없다. 편리해서 쓰기 시작하면 결국 "누가 언제 무엇을 줬는지" 가 기록에서 사라진다. 사고 대응용으로만 쓰고, 쓴 사실을 남기는 팀 규칙이 필요하다.

셋째, 자리를 줄이는 설계. 표를 아는 것보다 강한 방어는 같은 이름을 심을 자리를 줄이는 것이다. 흔한 규칙은 셋이다 - 환경별 값은 인벤토리 group_vars 한 곳에만 둔다, 롤은 밖에서 바꿔도 되는 값만 defaults 에 둔다, -e 는 예외 상황에만 쓴다. 이 셋을 지키면 우선순위 표를 몰라도 사고가 거의 나지 않는다.

넷째, vars_prompt. 실행할 때 사람에게 물어 받는 자리도 있다(플레이 vars: 와 vars_files: 사이). 자동화 파이프라인에서는 실행이 멈춰 버리므로 CI 에 들어갈 플레이북에는 쓰지 않는다. 이 실습도 자동 채점이라 다루지 않는다.

다음 실습에서 할 것

svc_tier 라는 이름 하나를 열두 자리에 한 자리씩 더 심어 가며 승자가 어떻게 바뀌는지 직접 잰다. 인벤토리 세 자리는 ansible-inventory --list 로, 나머지는 플레이북을 돌려 산출물로 확인한다. 마지막에는 측정한 순서를 사람이 읽을 수 있는 표로 남기고, 딕셔너리가 합쳐지지 않는 것과 combine 으로 합치는 것을 나란히 확인한다.

딕셔너리는 합쳐지지 않고 덮인다

낮은 자리에 cpu 와 memory 를 가진 딕셔너리가 있고, 높은 자리에서 memory 만 가진 같은 이름의 딕셔너리를 줬다. 값은 설명용 예시다.

  • 그냥 높은 자리에서 준다결과는 memory 하나만 가진 딕셔너리다. 높은 자리가 같은 이름을 통째로 이기므로 cpu 는 사라진다.
  • combine 필터로 합친다합친다는 뜻을 코드에 명시한다. 낮은 자리의 항목에 높은 자리의 항목을 얹으면 cpu 는 남고 memory 는 높은 쪽의 값이 된다.

여기서 구분할 것 전역 설정 hash_behaviour 를 merge 로 바꾸는 방법도 있지만 저장소 전체의 동작을 바꾸므로 공식 문서도 권하지 않는다고 본문은 말한다. 필요한 자리에서 combine 으로 명시하는 편이 안전하다.

잠깐, 예측해 보세요 딕셔너리가 안 합쳐져 불편하다. hash_behaviour 를 merge 로 한 번 바꿔 두면 끝이니 그렇게 하는 편이 낫지 않을까?

설명 확인 · 채점 없는 자가 점검

그 설정은 저장소 전체의 동작을 바꾼다. 지금까지 덮이는 것을 전제로 짠 곳까지 결과가 달라질 수 있어서 본문은 공식 문서도 권하지 않는다고 말한다. 합칠 곳에서 combine 을 쓰면 어디가 합쳐지는지가 코드에 보인다.

근거 문서

참고 문서