LabHub
배우기 러닝패스 코스

Ansible in Practice

Roles — A Reuse Unit Folded by Convention

LabHub 에서 이어서 보기

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

한 줄 요약

롤은 플레이북 조각을 정해진 디렉터리 이름에 나눠 담은 것이고, 그 규약 덕분에 설정 없이 재사용된다.

Concept map: 정해진 디렉터리 이름 · 먼저 · 사용자가 바꿀 것 같은 값은 반드시 defaults 에 둔다. · 첫째, 이름 충돌.

왜 이게 필요했나

플레이북 하나에 nginx 설치, 앱 배포, 로그 로테이션, 모니터링 에이전트까지 다 넣으면 300줄이 된다. 그다음 두 번째 서비스가 생기면 사람들은 그 파일을 복사한다. 복사된 순간부터 두 파일은 서로 다른 속도로 늙는다. 6개월 뒤 "왜 A 서버만 로그가 안 지워지지"의 답은 언제나 "복사본이 갱신되지 않아서"다.

롤은 이 문제를 "재사용 단위를 파일 시스템 구조로 강제한다"로 푼다. 롤 안에서 태스크·기본값·핸들러·템플릿이 각자의 자리를 가지므로, 남이 만든 롤도 열어 보지 않고 어디에 무엇이 있는지 안다.

어떻게 동작하나

디렉터리 담는 것 자동 로드
tasks/main.yml 실행할 태스크 롤 호출 시
defaults/main.yml 덮어쓰기를 기대하는 기본값 가장 낮은 우선순위
vars/main.yml 바뀌면 안 되는 내부 값 높은 우선순위
handlers/main.yml 핸들러 자동 등록
templates/ Jinja2 템플릿 template 모듈이 경로 없이 찾음
files/ 그대로 복사할 파일 copy 모듈이 경로 없이 찾음
meta/main.yml 의존 롤, 메타데이터 의존 롤을 먼저 실행

핵심은 defaultsvars 의 구분이다. 사용자가 바꿀 것 같은 값은 반드시 defaults 에 둔다. vars 에 두면 우선순위가 높아 밖에서 덮어쓰기가 사실상 불가능해지고, 그 롤은 재사용할 수 없게 된다.

meta/main.ymldependencies 는 "이 롤 전에 저 롤이 필요하다"를 선언한다. 같은 의존 롤이 여러 번 나와도 기본적으로 한 번만 실행된다.

현장에서 만나는 모습

첫째, 이름 충돌. 롤이 여러 개면 변수 이름이 겹친다. 그래서 롤 변수에는 롤 이름을 접두어로 붙이는 것이 관례다 — port 가 아니라 webapp_port.

둘째, 롤 안에서 절대 경로를 쓰지 않기. templates/files/ 는 롤 기준으로 자동 탐색되므로 파일 이름만 적으면 된다. 절대 경로를 박으면 그 롤은 그 서버에서만 동작한다.

셋째, 롤도 멱등해야 한다. 롤을 쓰는 플레이북을 두 번 돌려 changed=0 이 나오는지 확인하는 습관은 롤에서도 그대로다.

변수 우선순위가 사고를 만든다

앤서블의 변수는 스물두 단계의 우선순위가 있습니다. 전부 외울 필요는 없지만 자주 부딪히는 다섯 개의 순서 는 알아야 합니다(아래로 갈수록 강함).

1. 롤의 defaults/main.yml     ← 가장 약하다. 덮어쓰라고 있는 것
2. inventory group_vars
3. inventory host_vars
4. play 의 vars
5. -e (extra vars)            ← 가장 강하다. 무엇도 못 이긴다

여기서 나오는 규칙 둘입니다.

값이 어디서 왔는지는 물어보면 됩니다.

ansible -i inv host -m debug -a "var=app_port"
ansible-inventory -i inv --host web-01 --yaml     # 그 호스트에 적용된 전부

멱등성을 깨는 모듈

앤서블의 값어치는 "두 번 돌려도 같다" 입니다. 이것을 깨는 것이 몇 가지 있습니다.

쓰면 안 되는 것 대신
shell: echo x >> /etc/hosts lineinfile, blockinfile
command: mkdir /opt/app file: state=directory
shell: sed -i … lineinfile, template
command: curl … | bash get_url + command (검증 후)

셸을 꼭 써야 한다면 createsremoves 로 조건을 겁니다.

- name: 설치 스크립트 (한 번만)
  command: /opt/setup.sh
  args:
    creates: /opt/.installed      # 이 파일이 있으면 건너뛴다

changed_when: false 는 다른 이야기입니다. 그것은 "이 명령은 상태를 안 바꾼다" 는 선언이라 조회 명령에만 씁니다. 실제로 바꾸는 명령에 붙이면 리포트가 거짓말을 하게 됩니다.

롤을 나누는 기준

한 롤이 커지면 나누고 싶어지는데, 기준이 없으면 조각만 늘어납니다.

세 번째가 실무의 함정입니다. 두 롤이 port 라는 변수를 쓰면 나중 것이 이깁니다. 앤서블은 경고하지 않습니다. 롤 이름을 접두로 붙이는 관례 가 이것을 막습니다.

다음 실습에서 할 것

webapp 롤을 뼈대부터 만들어 기본값·태스크·템플릿·핸들러를 채우고, baseline 롤을 의존으로 걸어 실행 순서를 확인한다. 같은 롤을 다른 변수로 두 번 호출해 재사용성을 증명하고, 두 번째 실행에서 changed=0 을 만든다.