IT/Ansible

[Ansible 101] 핸들러 및 작업 실패 처리

Jflip 2024. 1. 21. 08:08
728x90

 

앤서블 모듈멱등(idempotent)이 가능하도록 설계되어 있습니다.

즉, 플레이북을 여러 번 실행해도 결과는 항상 동일합니다.

 

또한 플레이 및 해당 작업은 여러 번 실행할 수 있지만,

해당 호스트는 원하는 상태로 만드는 데 필요한 경우에만 변경됩니다.

 

하지만 한 작업에서 시스템을 변경해야 하는 경우 추가 작업실행해야 할 수도 있습니다.

예를 들어 서비스의 구성 파일을 변경하려면 변경 내용이 적용되도록 서비스를 다시 로드해야 합니다.

이때 핸들러는 다른 작업에서 트리거한 알림에 응답하는 작업이며, 해당 호스트에서 작업이 변경될 때만 핸들러통지합니다.

 

1. 핸들러

#1. Handlers

참조 링크 : https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html

 

앤서블에서 핸들러를 사용하려면 notify 문을 사용하여 명시적으로 호출된 경우에만 사용할 수 있습니다.

또한 핸들러를 정의할 때는 같은 이름으로 여러 개의 핸드러를 정의하기보다는 각각의 고유한 이름을 사용하여 정의하는 것이 좋습니다.

 

1) 플레이북 생성

rsyslog 재시작 태스크가 실행되면 notify 키워드를 통해 print msg라는 핸들러를 호출합니다. 

* 핸들러는 handlers 키워드로 시작합니다.

 

~/my-ansible/handler-sample.yml

---
- hosts: tnode2
  tasks:
    - name: restart rsyslog
      ansible.builtin.service:
        name: "rsyslog"
        state: restarted
      notify:
        - print msg

  handlers:
    - name: print msg
      ansible.builtin.debug:
        msg: "rsyslog is restarted"

 

2) 실행

 

마찬가지로, 한번 더 실행하더라도 동일한 결과를 얻습니다.

앞서 설명드린 듯이, 앤서블은 멱등성을 띄고 있기 때문입니다.

 

#2. 작업 실패 무시

  • 앤서블은 플레이 시 각 작업의 반환 코드를 평가하여 작업의 성공 여부를 판단합니다.
    일반적으로는 작업이 실패하면 앤서블은 이후의 모든 작업을 건너뜁니다.
  • 하지만 작업이 실패해도 플레이를 계속 실행할 수 있습니다. 이는 ignore_errors라는 키워드로 구현할 수 있습니다.

1) 플레이북 생성

다음의 내용은 강제로 apache3 패키지를 설치하는 내용입니다.

어떻게 되는지 한번 보겠습니다.

 

우선 두개의 플레이북을 생성해 주겠습니다.

 

~/my-ansible/ignore-example-1.yml

---
- hosts : tnode1

  tasks:
    - name: Install apache3
      ansible.builtin.apt:
        name: apache3
        state: latest

    - name: Print msg
      ansible.builtin.debug:
        msg: "Before task is ignored"

 

~/my-ansible/ignore-example-2.yml

---
- hosts : tnode1

  tasks:
    - name: Install apache3
      ansible.builtin.apt:
        name: apache3
        state: latest
      ignore_errors: yes

    - name: Print msg
      ansible.builtin.debug:
        msg: "Before task is ignored"

 

위 두 개의 플레이북은 ignore_errors: yes 구문의 유무가 다릅니다.

 

플레이북 1 실행 후,

 

플레이북 2 실행 후,

 

ignore-example-2.yml을 실행했을 때는 ignore_errors를 거쳐서 플레이북이 실행되는 것을 확인하실 수 있습니다.

 

#3. 작업 실패 후 핸들러

  • 앤서블은 일반적으로 작업이 실패하고 해당 호스트에서 플레이가 중단되면 이전 작업에서 알림을 받은 모든 핸들러가 실행되지 않습니다.
  • 하지만 플레이북에 force_handlers: yes 키워드를 설정하면 이후 작업이 실패하여 플레이가 중단되어도 알림을 받은 핸들러가 호출됩니다.

이번 세션에 사용할 모듈은 다음의 세 가지입니다.

ansible.builtin.apt 모듈
- 참조 링크 : https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html

ansible.builtin.dnf 모듈
- 참조 링크 : https://docs.ansible.com/ansible/latest/collections/ansible/builtin/dnf_module.html

Error handling in playbooks

- 참조 링크 :  https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_error_handling.html

 

1) 플레이북 생성

hosts 아래 force_handlers: yes 를 추가하고, install apache2 태스크를 추가합니다.

 

~/my-ansible/force-handler-1.yml

---
- hosts: tnode2

  tasks:
    - name: restart rsyslog
      ansible.builtin.service:
        name: "rsyslog"
        state: restarted
      notify:
        - print msg

    - name: install apache3
      ansible.builtin.apt:
        name: "apache3"
        state: latest

  handlers:
    - name: print msg
      ansible.builtin.debug:
        msg: "rsyslog is restarted"

 

~/my-ansible/force-handler-2.yml

---
- hosts: tnode2
  force_handlers: yes

  tasks:
    - name: restart rsyslog
      ansible.builtin.service:
        name: "rsyslog"
        state: restarted
      notify:
        - print msg

    - name: install apache3
      ansible.builtin.apt:
        name: "apache3"
        state: latest

  handlers:
    - name: print msg
      ansible.builtin.debug:
        msg: "rsyslog is restarted"

 

2) 실행

 

 

플레이북을 실행하면, 두 번째 플레이북에서 install apache3 태스크가 실패했음에도 불구하고 print msg 핸들러가 실행된 것은 앞서 말씀드린 force_handlers: yes 옵션 때문입니다. 

이 옵션은 실패한 태스크가 있더라도 등록된 핸들러를 강제로 실행하게 만듭니다.

이러한 동작은 특히 어떤 태스크가 실패했을 때도 중요한 정리 작업이나 알림을 보내야 할 경우 유용합니다. 

예를 들어, 특정 서비스를 재시작해야 하거나 실패 알림을 보내야 하는 경우 등에 사용됩니다.

 

#4. 작업 실패 조건 지정 (shell script 보다는 module을 사용하자)

  • 앤서블에서 셸 스크립트를 실행한 뒤 결과로 실패 또는 에러 메시지를 출력해도, 앤서블에서는 작업이 성공했다고 간주합니다.
  • 어떤 명령이라도 실행된 경우에는 태스크 실행 상태를 항상 changed 로 합니다.
  • 이런 경우 failed_when 키워드를 사용하여 작업이 실패했음을 나타내는 조건을 지정할 수 있습니다.

1) 스크립트 생성

~/my-ansible/adduser-script.sh

 

# 사용자 추가하는 스크립트 파일 내용 확인
cat ~/my-ansible/Easy-Ansible/chapter_07.3/adduser-script.sh
cp ~/my-ansible/Easy-Ansible/chapter_07.3/adduser-script.sh adduser-script.sh
chmod +x adduser-script.sh
ls -l adduser-script.sh

# 해당 스크립트로 user1 생성해보기
## "passwd: unrecognized option '--stdin'" 에러는 암호 적용 부분에서 발생
sudo ./adduser-script.sh
sudo ./adduser-script.sh "user1" "qwe123"
tail -n 3 /etc/passwd
sudo userdel -rf user1

 

2) tnode1에 스크립트를 복사 후 확인

# 사용자 추가하는 스크립트 파일을 tnode1에 복사
ansible -m copy -a 'src=/home/ubuntu/my-ansible/adduser-script.sh dest=/home/ubuntu/adduser-script.sh' tnode1

# 복사 확인
ssh tnode1 ls -l /home/ubuntu/
-rw-r--r-- 1 root root 846 Jan 13 22:09 adduser-script.sh

# 스크립트 실행 확인
ssh tnode1
---------------
sudo chmod +x adduser-script.sh
sudo ./adduser-script.sh
exit
---------------

 

 

3) 플레이북 생성

~/my-ansible/failed-when-1.yml

---
- hosts: tnode1

  tasks:
    - name: Run user add script
      ansible.builtin.shell: /home/ubuntu/adduser-script.sh
      register: command_result

    - name: Print msg
      ansible.builtin.debug:
        msg: "{{ command_result.stdout }}"

 

 

~/my-ansible/failed-when-2.yml

failed_when 조건식 :

command_result.stdout 변수에 “Please…”라는 문자열이 있으면 작업을 실패(fail)로 처리하겠다는 의미입니다.

---
- hosts: tnode1

  tasks:
    - name: Run user add script
      ansible.builtin.shell: /home/ubuntu/adduser-script.sh
      register: command_result
      failed_when: "'Please input user id and password' in command_result.stdout"

    - name: Print msg
      ansible.builtin.debug:
        msg: "{{ command_result.stdout }}"

 

4) 실행

 

실행하면 첫 번째 플레이북은 정상 동작하는 것으로 보입니다.

스크립트가 0이 아닌 종료 코드를 반환하지 않았기 때문에, Ansible은 이 태스크를 성공적으로 완료한 것으로 간주합니다.
그 결과, 두 번째 태스크인 Print msg가 실행되어 스크립트의 출력 내용을 표시합니다.

 

ansible -m shell -a "tail -n 3 /etc/passwd" tnode1

 

위의 커맨드를 통해서 유저가 추가 됐는지 확인합니다.

 

 

두 번째 플레이북을 실행하면, 다음과 같이 나옵니다.
조건 "'Please input user id and password' in command_result.stdout"는 스크립트의 출력 "Please input user id and password"라는 문자열이 포함되어 있으면 태스크가 실패한 것으로 간주하도록 설정합니다.


스크립트의 실행 결과에서 해당 문자열이 발견되었기 때문에, Ansible은 이 태스크를 실패한 것으로 간주합니다.
따라서 Print msg 태스크는 실행되지 않고, 플레이북의 실행이 중단됩니다.

 

감사합니다.

728x90
반응형