ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Ansible 101] 핸들러 및 작업 실패 처리
    IT/Ansible 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
    반응형
Designed by Tistory.