Ansible 동작 제어하기: 우선순위 규칙

Ansible 동작 제어하기: 우선순위 규칙 (Controlling how Ansible behaves: precedence rules)

Ansible은 환경을 관리할 때 최대한의 유연성을 주기 위해 같은 설정을 여러 곳에서 정의할 수 있게 해줘요. 그런데 이 유연성은 우선순위 규칙을 이해하지 못하면 오히려 예상 밖의 결과를 낳을 수 있어요. 이 문서에서는 설정 파일, 커맨드라인 옵션, 플레이북 키워드, 변수라는 네 가지 우선순위 범주를 정리해요.

출처: 문서

본문

Ansible은 환경을 관리할 때 최대한의 유연성을 제공하기 위해 여러 가지 방식으로 동작을 제어하게 해줘요. 관리 노드에 어떻게 연결하는지, 연결한 뒤 어떻게 동작하는지 같은 부분이죠. 많은 서버, 네트워크 장비, 클라우드 리소스를 관리한다면 Ansible 동작을 여러 곳에서 정의하고 그 정보를 여러 방식으로 전달하게 돼요. 이 유연성은 편리하지만, 우선순위 규칙을 이해하지 못하면 역효과가 날 수 있어요.

이 우선순위 규칙은 설정 파일 설정, 커맨드라인 옵션, 플레이북 키워드, 변수처럼 여러 방식으로 정의될 수 있는 모든 설정에 적용돼요.

우선순위 범주 (Precedence categories)

Ansible은 동작을 제어하는 네 가지 원천을 제공해요. 우선순위가 낮은 순(가장 쉽게 덮어쓰이는 순)에서 높은 순(다른 모든 것을 덮어쓰는 순)으로 나열하면 다음과 같아요.

  • 설정 파일 설정 (Configuration settings)
  • 커맨드라인 옵션 (Command-line options)
  • 플레이북 키워드 (Playbook keywords)
  • 변수 (Variables)
  • 직접 지정 (Direct Assignment)

각 범주는 더 낮은 우선순위 범주의 모든 정보를 덮어써요. 예를 들어 플레이북 키워드는 어떤 설정 파일 설정보다도 우선해요.

각 우선순위 범주 안에서도 구체적인 규칙이 적용돼요. 다만 일반적으로는 '마지막에 정의된 것'이 이기고 이전 정의를 덮어써요.

설정 파일 설정 (Configuration settings)

설정 파일 설정은 ansible.cfg 파일의 값과 환경 변수를 모두 포함해요. 이 범주 안에서 설정 파일에 들어 있는 값은 우선순위가 더 낮아요. Ansible은 처음 찾은 ansible.cfg 파일을 사용하고 나머지는 무시해요. Ansible은 다음 위치에서 순서대로 ansible.cfg를 검색해요.

  • ANSIBLE_CONFIG (설정된 경우 환경 변수)
  • ansible.cfg (현재 디렉토리)
  • ~/.ansible.cfg (홈 디렉토리)
  • /etc/ansible/ansible.cfg

환경 변수는 ansible.cfg의 항목보다 우선순위가 높아요. 컨트롤 노드에 환경 변수가 설정되어 있다면, Ansible이 로드하는 어떤 ansible.cfg 파일의 설정보다 우선해요. 특정 환경 변수의 값은 일반적인 셸 우선순위를 따르는데, 마지막에 정의된 값이 이전 값을 덮어써요.

커맨드라인 옵션 (Command-line options)

모든 커맨드라인 옵션은 어떤 설정 파일 설정보다도 우선해요.

커맨드라인에 직접 입력한다면 손으로 만든 값이 모든 것을 덮어써야 한다고 느낄 수 있지만, Ansible은 그렇게 동작하지 않아요. 커맨드라인 옵션은 우선순위가 낮아서 설정만 덮어써요. 플레이북 키워드나 인벤토리·플레이북의 변수는 덮어쓰지 않아요.

다른 모든 범주와 모든 원천의 다른 모든 설정을 커맨드라인에서 덮어쓰려면 -e 여분 변수(extra variables)를 쓰면 돼요. 다만 그것은 커맨드라인 옵션이 아니라 변수를 전달하는 방식이에요.

커맨드라인에서 단일 값만 받는 매개변수에 여러 값을 전달하면 마지막에 정의된 값이 이깁니다. 예를 들어 이 임시 태스크는 mike가 아니라 carol로 연결해요.

ansible -u mike -m ping myhost -u carol

일부 매개변수는 여러 값을 허용해요. 이런 경우 Ansible은 인벤토리 파일 inventory1과 inventory2에 나열된 호스트의 모든 값을 추가해요.

ansible -i /path/inventory1 -i /path/inventory2 -m ping all

각 커맨드라인 도구의 도움말에는 해당 도구에서 쓸 수 있는 옵션이 나열돼 있어요.

플레이북 키워드 (Playbook keywords)

모든 플레이북 키워드는 어떤 커맨드라인 옵션과 어떤 설정 파일 설정보다도 우선해요.

플레이북 키워드 안에서는 우선순위가 플레이북 자체를 따라 흐르는데, 더 구체적인 것이 더 일반적인 것을 이겨요.

  • play (가장 일반적)
  • blocks/includes/imports/roles (선택적이며 태스크와 서로를 포함할 수 있어요)
  • tasks (가장 구체적)

간단한 예시를 볼게요.

- hosts: all
  connection: ssh
  tasks:
    - name: This task uses ssh.
      ping:

    - name: This task uses paramiko.
      connection: paramiko
      ping:

이 예시에서 connection 키워드는 play 레벨에서 ssh로 설정돼요. 첫 번째 태스크는 그 값을 상속받아 ssh로 연결해요. 두 번째 태스크는 그 값을 상속받은 뒤 덮어써서 paramiko로 연결해요.

같은 논리가 블록과 롤에도 적용돼요. play 안의 모든 태스크·블록·롤은 play 레벨 키워드를 상속받아요. 어떤 태스크·블록·롤은 그 안에서 해당 키워드에 다른 값을 정의해 어떤 키워드든 덮어쓸 수 있어요.

이것들은 키워드(KEYWORD)이지 변수가 아니라는 점을 기억하세요. 플레이북과 변수 파일은 둘 다 YAML로 정의되지만 그 의미는 달라요. 플레이북은 Ansible의 명령 또는 '상태 설명' 구조이고, 변수는 플레이북을 더 동적으로 만들기 위해 쓰는 데이터예요.

변수 (Variables)

Ansible 변수는 우선순위 스택에서 매우 높아요. 어떤 플레이북 키워드, 커맨드라인 옵션, 환경 변수, 설정 파일 설정보다도 우선해요.

플레이북 키워드·커맨드라인 옵션·설정 파일 설정에 대응하는 변수를 연결 변수(Connection variables)라고 불러요. 원래 연결 매개변수용으로 설계됐지만, 이 범주는 임시 디렉토리, Python 인터프리터 같은 다른 핵심 변수도 포함하도록 확장됐어요.

연결 변수는 다른 모든 변수처럼 여러 방식과 장소에서 설정할 수 있어요. 인벤토리에서 호스트·그룹별로 변수를 정의할 수 있고, 플레이북의 vars: 블록에서 태스크·play용 변수를 정의할 수 있어요. 그래도 그것은 여전히 변수예요. 데이터이지 키워드나 설정 파일 설정이 아니죠. 플레이북 키워드·커맨드라인 옵션·설정 파일 설정을 덮어쓰는 변수는 다른 변수와 같은 변수 우선순위 규칙을 따라요.

플레이북에서 설정할 때 변수는 플레이북 키워드와 같은 상속 규칙을 따라요. play 값을 설정한 다음 태스크·블록·롤에서 덮어쓸 수 있어요.

- hosts: cloud
  gather_facts: false
  become: true
  vars:
    ansible_become_user: admin
  tasks:
    - name: This task uses admin as the become user.
      dnf:
        name: some-service
        state: latest
    - block:
        - name: This task uses service-admin as the become user.
          # a task to configure the new service
        - name: This task also uses service-admin as the become user, defined in the block.
          # second task to configure the service
      vars:
        ansible_become_user: service-admin
    - name: This task (outside of the block) uses admin as the become user again.
      service:
        name: some-service
        state: restarted

변수 범위: 값이 얼마나 오래 사용 가능한가?

플레이북에서 설정한 변수 값은 그 값을 정의한 플레이북 객체 안에서만 존재해요. 이 '플레이북 객체 범위' 변수는 다른 play를 포함한 이후 객체에는 사용할 수 없어요.

인벤토리, vars 플러그인, 또는 set_fact·include_vars 같은 모듈로 정의한 변수를 포함해 호스트·그룹에 직접 연결된 변수 값은 모든 play에서 사용 가능해요. 이 '호스트 범위' 변수는 hostvars[] 딕셔너리를 통해서도 접근할 수 있어요.

extravars로 설정한 변수는 현재 실행에 대해 전역 범위를 가지며 '플레이북 객체 변수'와 'hostvars' 모두로 존재해요.

커맨드라인에서 -e 여분 변수 사용하기

다른 모든 변수를 덮어쓰려면 커맨드라인에서 --extra-vars 또는 -e 여분 변수를 쓸 수 있어요. -e로 전달된 값은 그 자체로는 커맨드라인 옵션이지만 변수 중에서 가장 높은 우선순위를 가져요. 그리고 변수 자체가 우선순위가 높기 때문에, 직관에 반하지만 대부분의 설정 원천 중에서도 더 높은 우선순위가 돼요. 예를 들어 이 태스크는 carol이 아니라 brian으로 연결해요.

ansible -u carol -e 'ansible_user=brian' -a whoami all

--extra-vars에는 변수 이름과 값 둘 다 지정해야 해요.

직접 지정 (Direct Assignment)

이 범주는 직접 옵션을 받는 것, 일반적으로 모듈과 일부 플러그인 유형에만 적용돼요. 대부분의 모듈과 액션 플러그인은 다른 방식으로 설정을 지정할 수 없어서 이런 맥락에서 우선순위가 나올 일이 거의 없지만, 일부는 가능하고 문서에 반영되어야 해요.

- debug: msg='this is a direct assignment option to an action plugin'

- ping:
    data: also a direct assignment

태스크 액션 외에 가장 눈에 띄는 '직접 지정'은 lookup, filter, test 플러그인에서 볼 수 있어요.

lookup('plugin', direct1='value', direct2='value2')

'value_directly_assigned'|filter('another directly assigned')

'direct value' is testplugin

대부분은 다른 방식으로 구성되지 않지만, 특히 test 같은 경우 플러그인과 필터는 문서에 명시되어 있다면 다른 설정 원천의 입력을 사용할 수 있어요.

인벤토리 플러그인은 '인벤토리 소스(inventory sources)'를 사용하기 때문에 조금 까다로워요. 이 소스는 설정 파일처럼 보이기도 하고 커맨드라인 옵션으로 전달되기도 하지만 여전히 '직접 지정'으로 간주돼요. 인라인 소스 -ihost1,host2,host3를 쓸 때가 파일 소스 -i/path/to/inventory_source를 쓸 때보다 명확해 보이지만, 둘 다 같은 우선순위예요.

더 알아보기 (Learn more)

  • 우선순위와 관련된 설정 파일 항목은 Ansible 설정 문서를 확인해요.
  • 변수 우선순위에 대한 더 자세한 내용은 Ansible 변수 우선순위 문서를 참고해요.