작업 실행 위치 제어: 위임과 로컬 액션

작업 실행 위치 제어: 위임과 로컬 액션 (Controlling where tasks run: delegation and local actions)

기본적으로 Ansible은 플레이북의 hosts 줄과 일치하는 머신에서 팩트를 수집하고 모든 작업을 실행해요. 그런데 때로는 작업을 다른 머신이나 그룹에 위임해야 하거나, 플레이북 전체를 로컬에서 실행해야 할 때가 있습니다. 이 페이지에서는 그러한 위임과 로컬 실행 방법을 다룹니다.

출처: 문서

본문

기본적으로 Ansible은 플레이북의 hosts 줄과 일치하는 머신에서 팩트를 수집하고 모든 작업을 실행해요. 이 페이지는 작업을 다른 머신이나 그룹에 위임하는 방법, 팩트를 특정 머신이나 그룹에 위임하는 방법, 또는 플레이북 전체를 로컬에서 실행하는 방법을 보여줍니다. 이 방식을 사용하면 서로 관련된 환경을 정밀하고 효율적으로 관리할 수 있어요. 예를 들어 웹 서버를 업데이트할 때 로드 밸런스 풀에서 임시로 꺼내야 할 수 있습니다. 이 작업은 웹 서버 자체에서 수행할 수 없어요. 작업을 localhost에 위임하면 모든 작업을 같은 플레이 안에 유지할 수 있습니다.

위임할 수 없는 작업 (Tasks that cannot be delegated)

일부 작업은 항상 컨트롤 노드에서 실행돼요. include, add_host, debug를 포함한 이 작업들은 위임할 수 없습니다. 액션이 위임 가능한지는 connection 속성 문서에서 확인할 수 있어요. connection 속성이 supportFalse 또는 None이면 그 액션은 연결을 사용하지 않으므로 위임할 수 없습니다.

작업 위임하기 (Delegating tasks)

다른 호스트에 대한 참조를 가지고 한 호스트에서 작업을 수행하고 싶다면, 작업에 delegate_to 키워드를 사용하세요. 이는 로드 밸런스 풀의 노드를 관리하거나 중단(outage) 시간대를 제어하는 데 이상적입니다. 위임을 serial 키워드와 함께 사용해 한 번에 실행되는 호스트 수를 제어할 수 있어요:

---
- hosts: webservers
  serial: 5

  tasks:
    - name: Take out of load balancer pool
      ansible.builtin.command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1

    - name: Actual steps would go here
      ansible.builtin.yum:
        name: acme-web-stack
        state: latest

    - name: Add back to load balancer pool
      ansible.builtin.command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1

이 플레이의 첫 번째와 세 번째 작업은 Ansible을 실행하는 머신인 127.0.0.1에서 실행돼요. 작업 단위로 사용할 수 있는 축약 문법도 있습니다: local_action. 위와 같은 플레이북이지만 127.0.0.1로 위임하는 축약 문법을 사용한 예시입니다:

---
# ...

  tasks:
    - name: Take out of load balancer pool
      local_action: ansible.builtin.command
      args:
        cmd: /usr/bin/take_out_of_pool {{ inventory_hostname }}

# ...

    - name: Add back to load balancer pool
      local_action: ansible.builtin.command
      args:
        cmd: /usr/bin/add_back_to_pool {{ inventory_hostname }}

로컬 액션으로 'rsync'를 호출해 파일을 관리 대상 서버로 재귀적으로 복사할 수 있어요:

---
# ...

  tasks:
    - name: Recursively copy files from management server to target
      local_action: ansible.builtin.command
      args:
        cmd: "rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/"

이것이 동작하려면 passphrase 없는 SSH 키 또는 구성된 ssh-agent가 있어야 해요. 그렇지 않으면 rsync가 passphrase를 요구합니다.

더 많은 인자를 지정하려면 다음 문법을 사용하세요:

---
# ...

  tasks:
    - name: Send summary mail
      local_action: community.general.mail
      args:
        subject: "Summary Mail"
        to: "{{ mail_recipient }}"
        body: "{{ mail_body }}"
      run_once: True

참고 (Note)

  • ansible_host 변수와 다른 connection 변수는, 있다면 작업이 위임된 호스트에 대한 정보를 반영하지 inventory_hostname에 대한 정보를 반영하지 않아요.
  • 작업이 위임된 호스트는 위임하는 호스트의 변수를 상속받지 않습니다.

경고 (Warning)

인벤토리에 존재하지 않는 호스트에 delegate_to를 할 수는 있지만(IP 주소, DNS 이름 또는 connection 플러그인이 요구하는 것 추가), 그렇게 해도 호스트가 인벤토리에 추가되지는 않으며 문제를 일으킬 수 있어요. 이런 식으로 위임된 호스트는 "all" 그룹에서 변수를 상속합니다(VARIABLE_PRECEDENCE에 all_inventory가 포함되어 있다고 가정). 인벤토리에 없는 호스트에 delegate_to를 해야 한다면 add_host 모듈을 사용하세요.

위임 컨텍스트에서의 템플릿팅 (Templating in delegation context)

위임 하에서는 실행 인터프리터(보통 Python), connection, become, shell 플러그인 옵션이 이제 위임된 호스트의 값을 사용해 템플릿팅된다는 점을 알아두세요. inventory_hostname을 제외한 모든 변수는 이제 원래 작업 호스트가 아니라 이 호스트에서 소비됩니다. 그 옵션들에 원래 작업 호스트의 변수가 필요하다면 hostvars[inventory_hostname]['varname']을 사용해야 하며, inventory_hostname_short조차 위임된 호스트를 가리킵니다.

위임과 병렬 실행 (Delegation and parallel execution)

기본적으로 Ansible 작업은 병렬로 실행돼요. 작업을 위임해도 이는 바뀌지 않으며 동시성 문제(여러 fork가 같은 파일에 쓰기)도 처리하지 않습니다. 대부분의 경우 사용자는 모든 호스트에 대해 하나의 위임 대상 호스트에서 단일 파일을 업데이트할 때(예: copy, template, lineinfile 모듈 사용) 이 문제의 영향을 받습니다. 그들은 여전히 병렬 fork(기본 5)로 동작하며 서로를 덮어씁니다.

이것은 여러 가지 방법으로 처리할 수 있어요:

- name: "handle concurrency with a loop on the hosts with `run_once: true`"
  lineinfile: "<options here>"
  run_once: true
  loop: '{{ ansible_play_hosts_all }}'

serial: 1을 사용한 중간 플레이를 두거나 작업 레벨에서 throttle: 1을 사용하는 방법도 있어요. 자세한 내용은 "플레이북 실행 제어: 전략과 그 외"를 참고하세요.

팩트 위임하기 (Delegating facts)

Ansible 작업을 위임하는 것은 현실 세계에서 일을 위임하는 것과 비슷해요 — 누군가 당신 집에 장을 배달해줘도 장은 당신 것이죠. 마찬가지로 위임된 작업이 수집한 모든 팩트는 기본적으로 팩트를 만든 호스트(위임 대상 호스트)가 아니라 inventory_hostname(현재 호스트)에 할당됩니다. 수집된 팩트를 현재 호스트 대신 위임된 호스트에 할당하려면 delegate_factstrue로 설정하세요:

---
- hosts: app_servers

  tasks:
    - name: Gather facts from db servers
      ansible.builtin.setup:
      delegate_to: "{{ item }}"
      delegate_facts: true
      loop: "{{ groups['dbservers'] }}"

이 작업은 dbservers 그룹의 머신에 대한 팩트를 수집하고, 플레이가 app_servers 그룹을 대상으로 하더라도 그 팩트를 해당 머신에 할당해요. 이렇게 하면 dbservers가 플레이의 일부가 아니거나 --limit로 제외되었더라도 hostvars['dbhost1']['ansible_default_ipv4']['address']를 조회할 수 있습니다.

로컬 플레이북 (Local playbooks)

SSH로 연결하는 대신 원격 호스트에서 플레이북을 로컬로 사용하는 것이 유용할 수 있어요. 크론탭에 플레이북을 넣어 시스템 구성을 보장하는 데 유용하며, Anaconda kickstart 같은 OS 인스톨러 안에서 플레이북을 실행하는 데도 사용할 수 있습니다.

플레이북 전체를 로컬로 실행하려면 hosts: 줄을 hosts: 127.0.0.1로 설정하고 다음과 같이 실행하세요:

ansible-playbook playbook.yml --connection=local

또는 로컬 연결을 플레이북의 단일 플레이에서 사용할 수 있습니다. 다른 플레이가 기본 원격 연결 유형을 사용하더라도 말이죠:

---
- hosts: 127.0.0.1
  connection: local

참고 (Note)

연결을 local로 설정하고 ansible_python_interpreter가 설정되어 있지 않으면, 모듈은 {{ ansible_playbook_python }}이 아니라 /usr/bin/python 아래에서 실행돼요. 예를 들어 host_vars/localhost.yml에 ansible_python_interpreter: "{{ ansible_playbook_python }}"를 설정해야 합니다. local_action이나 delegate_to: localhost를 사용하면 이 문제를 피할 수 있습니다.

더 보기 (See also)

  • Ansible 플레이북 — 플레이북 소개.
  • 플레이북 실행 제어: 전략과 그 외 — Ansible이 실행하는 방법과 위치를 제어하는 더 많은 방법.
  • 커뮤니케이션 — 질문이나 도움이 필요하거나 아이디어를 나누고 싶다면 Ansible 커뮤니케이션 안내서를 참고하세요.

더 알아보기 (Learn more)

  • 위임에서 함께 사용하는 serialthrottle 같은 실행 제어 옵션은 "플레이북 실행 제어: 전략과 그 외(playbooks_strategies)" 페이지에서 확인할 수 있어요.