비동기 작업과 폴링

비동기 작업과 폴링 (Asynchronous actions and polling)

기본적으로 Ansible은 작업을 동기적으로 실행해요. 원격 노드 연결을 작업이 끝날 때까지 계속 붙들고 있죠. 그래서 오래 걸리는 작업이 SSH 세션 시간을 넘겨 타임아웃이 나거나, 다른 작업을 동시에 진행하고 싶을 때가 문제가 됩니다. 비동기 모드는 바로 이런 오래 실행되는 작업의 실행 방식을 제어하게 해줘요.

출처: 문서

본문

기본적으로 Ansible은 작업을 동기적으로 실행하며, 액션이 완료될 때까지 원격 노드에 대한 연결을 열어 둡니다. 즉 플레이북 안에서 각 작업은 기본적으로 다음 작업을 블로킹하고, 현재 작업이 완료될 때까지 이후 작업이 실행되지 않아요. 이 동작은 어려움을 만들 수 있습니다. 예를 들어 작업이 SSH 세션이 허용하는 것보다 오래 걸려 타임아웃이 발생할 수도 있고, 다른 작업을 동시에 수행하는 동안 오래 실행되는 프로세스를 백그라운드에서 실행하고 싶을 수도 있죠. 비동기 모드는 오래 실행되는 작업이 어떻게 실행될지를 제어하게 해줍니다.

비동기 임시(ad hoc) 작업 (Asynchronous ad hoc tasks)

임시(ad hoc) 작업으로 오래 실행되는 작업을 백그라운드에서 실행할 수 있어요. 예를 들어 long_running_operation을 타임아웃(-B) 3600초, 폴링 없이(-P) 비동기로 백그라운드에서 실행하려면:

$ ansible all -B 3600 -P 0 -a "/usr/bin/long_running_operation --do-stuff"

나중에 작업 상태를 확인하려면, 원래 작업을 백그라운드로 실행했을 때 반환된 작업 ID를 async_status 모듈에 전달합니다:

$ ansible web1.example.com -m async_status -a "jid=488359678239.2844"

Ansible은 폴링으로 오래 실행되는 작업의 상태를 자동으로 확인할 수도 있어요. 대부분의 경우 Ansible은 폴링 사이에도 원격 노드에 대한 연결을 열어 둡니다. 30분 동안 실행하고 60초마다 상태를 폴링하려면:

$ ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"

폴링 모드는 똑똑해서, 어떤 머신에서든 폴링이 시작되기 전에 모든 작업이 시작됩니다. 모든 작업을 아주 빨리 시작하고 싶다면 충분히 높은 --forks 값을 사용하세요. 시간 제한(초) -B이 지나면 원격 노드의 프로세스는 종료됩니다.

비동기 모드는 오래 실행되는 셸 명령이나 소프트웨어 업그레이드에 가장 적합해요. 예를 들어 copy 모듈을 비동기로 실행해도 백그라운드 파일 전송은 되지 않습니다.

비동기 플레이북 작업 (Asynchronous playbook tasks)

플레이북도 간소화된 문법으로 비동기 모드와 폴링을 지원해요. 플레이북에서 비동기 모드를 사용해 연결 타임아웃을 피하거나 이후 작업을 블로킹하지 않을 수 있습니다. 플레이북에서 비동기 모드의 동작은 poll 값에 따라 달라집니다.

연결 타임아웃 피하기: poll > 0 (Avoid connection timeouts)

플레이북의 특정 작업에 더 긴 타임아웃 한도를 설정하려면 async와 함께 양수 값의 poll을 사용하세요. Ansible은 여전히 플레이북의 다음 작업을 블로킹하고, 비동기 작업이 완료되거나 실패하거나 타임아웃될 때까지 기다립니다. 다만 작업은 async 매개변수로 설정한 타임아웃 한도를 넘어설 때만 타임아웃돼요.

작업의 타임아웃을 피하려면 최대 실행 시간과 상태를 폴링할 빈도를 지정하세요:

---

- hosts: all
  remote_user: root

  tasks:

  - name: Simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec
    ansible.builtin.command: /bin/sleep 15
    async: 45
    poll: 5

참고 (Note)

기본 poll 값은 DEFAULT_POLL_INTERVAL 설정으로 정해져요. async 시간 제한에는 기본값이 없습니다. async 키워드를 생략하면 작업은 동기적으로 실행되며, 이는 Ansible의 기본 동작이에요.

참고 (Note)

Ansible 2.3부터 async는 체크 모드를 지원하지 않으며, 체크 모드로 실행하면 작업이 실패해요. 체크 모드에서 작업을 건너뛰는 방법은 "작업 검증: 체크 모드와 diff 모드"를 참고하세요.

참고 (Note)

폴링을 활성화한 채 비동기 작업이 완료되면, 임시 async 작업 캐시 파일(기본적으로 ~/.ansible_async/)은 자동으로 제거돼요.

작업을 동시에 실행하기: poll = 0 (Run tasks concurrently)

플레이북에서 여러 작업을 동시에 실행하고 싶다면 async와 함께 poll을 0으로 설정하세요. poll: 0으로 설정하면 Ansible은 작업을 시작하고 결과를 기다리지 않고 즉시 다음 작업으로 넘어갑니다. 각 비동기 작업은 완료되거나 실패하거나 타임아웃(async 값보다 오래 실행)될 때까지 실행됩니다. 플레이북 실행은 비동기 작업을 확인하지 않고 끝납니다.

플레이북 작업을 비동기로 실행하려면:

---

- hosts: all
  remote_user: root

  tasks:

  - name: Simulate long running op, allow to run for 45 sec, fire and forget
    ansible.builtin.command: /bin/sleep 15
    async: 45
    poll: 0

참고 (Note)

플레이북의 이후 명령이 같은 리소스에 대해 실행될 것으로 예상된다면, 배타적 잠금(exclusive lock)이 필요한 작업(예: yum 트랜잭션)에는 poll 값을 0으로 지정하지 마세요.

참고 (Note)

--forks에 더 높은 값을 사용하면 비동기 작업을 더 빨리 시작할 수 있고, 폴링 효율도 높아져요.

참고 (Note)

poll: 0으로 실행할 때 Ansible은 async 작업 캐시 파일을 자동으로 정리하지 않습니다. mode: cleanup과 함께 async_status 모듈로 수동으로 정리해야 해요.

비동기 작업과 동기화 지점이 필요하다면 작업을 등록해 작업 ID를 얻고, 이후 작업에서 async_status 모듈로 관찰할 수 있어요. 예를 들면:

- name: Run an async task
  ansible.builtin.yum:
    name: docker-io
    state: present
  async: 1000
  poll: 0
  register: yum_sleeper

- name: Check on an async task
  async_status:
    jid: "{{ yum_sleeper.ansible_job_id }}"
  register: job_result
  until: job_result is finished
  retries: 100
  delay: 10

참고 (Note)

async: 값이 충분히 높지 않으면, async_status:가 찾는 임시 상태 파일이 기록되지 않거나 더 이상 존재하지 않아 "나중에 확인" 작업이 실패할 수 있어요.

참고 (Note)

비동기 플레이북 작업은 항상 changed를 반환해요. 작업이 사용자가 changed_when, creates 등으로 변경을 표시해야 하는 모듈을 사용한다면, 그런 표시를 다음 async_status 작업에 추가해야 합니다.

여러 비동기 작업을 실행하면서 동시에 실행되는 작업 수를 제한하려면:

#####################
# main.yml
#####################
- name: Run items asynchronously in batch of two items
  vars:
    sleep_durations:
      - 1
      - 2
      - 3
      - 4
      - 5
    durations: "{{ item }}"
  include_tasks: execute_batch.yml
  loop: "{{ sleep_durations | batch(2) | list }}"

#####################
# execute_batch.yml
#####################
- name: Async sleeping for batched_items
  ansible.builtin.command: sleep {{ async_item }}
  async: 45
  poll: 0
  loop: "{{ durations }}"
  loop_control:
    loop_var: "async_item"
  register: async_results

- name: Check sync status
  async_status:
    jid: "{{ async_result_item.ansible_job_id }}"
  loop: "{{ async_results.results }}"
  loop_control:
    loop_var: "async_result_item"
  register: async_poll_results
  until: async_poll_results is finished
  retries: 30

더 보기 (See also)

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

더 알아보기 (Learn more)

  • 비동기 작업과 관련된 체크 모드 동작은 "작업 검증: 체크 모드와 diff 모드(playbooks_checkmode)" 페이지에서 확인할 수 있어요.