[Ansible] 반복문, 조건문, 핸들러, 블록, 태그

728x90

Ansible 반복문

공식 문서: https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#playbooks-loops

작업(Task)에서 loop, with_, until 으로 반복문을 사용한다.

리스트 반복문

아래와 같이 주로 사용된다.

loop 대신 with_items, with_list 사용할 수 있다. 공식 문서를 참조하면 잘 나와 있다.

[vagrant@controller loop]$ cat test.yml
- hosts: 192.168.100.11
  gather_facts: no
  vars:
    fruits:
      - apple
      - banana
      - carrot
  tasks:
    - debug:
        msg: "{{ item }}"
      loop:
        "{{ fruits }}"
[vagrant@controller loop]$ ansible-playbook test.yml 

PLAY [192.168.100.11] ************************************************************************************************************

TASK [debug] *********************************************************************************************************************
ok: [192.168.100.11] => (item=apple) => {
    "msg": "apple"
}
ok: [192.168.100.11] => (item=banana) => {
    "msg": "banana"
}
ok: [192.168.100.11] => (item=carrot) => {
    "msg": "carrot"
}

PLAY RECAP ***********************************************************************************************************************
192.168.100.11             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

딕셔너리 반복문

반복문 중인 딕셔너리의 밸류값을 뽑기 위해 item.[key] 로 value 를 뽑아줄 수 있다.

loop 대신 with_dict 를 사용할 수 있다. 공식문서 참조하면 알 수 있다.

- name: Add several users
  ansible.builtin.user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }
[vagrant@controller dict]$ cat test.yml
- hosts: 192.168.100.11
  gather_facts: no
  vars:
    fruits:
      - name: apple
        count: 2
      - name: banana
        count: 3
  tasks:
    - debug:
        msg: "{{ item.name }} / {{ item.count }}"
      loop:
        '{{ fruits }}'
[vagrant@controller dict]$ ansible-playbook test.yml

PLAY [192.168.100.11] ************************************************************************************************************

TASK [debug] *********************************************************************************************************************
ok: [192.168.100.11] => (item={u'count': 2, u'name': u'apple'}) => {
    "msg": "apple / 2"
}
ok: [192.168.100.11] => (item={u'count': 3, u'name': u'banana'}) => {
    "msg": "banana / 3"
}

PLAY RECAP ***********************************************************************************************************************
192.168.100.11             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ansible 조건문

공식 문서: https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#basic-conditionals-with-when

테스트 문 공식 문서: https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html#playbooks-tests

vars:
  url: "<https://example.com/users/foo/resources/bar>"

tasks:
    - debug:
        msg: "matched pattern 1"
      when: url is match("<https://example.com/users/.*/resources>")

    - debug:
        msg: "matched pattern 2"
      when: url is search("users/.*/resources/.*")

    - debug:
        msg: "matched pattern 3"
      when: url is search("users")

    - debug:
        msg: "matched pattern 4"
      when: url is regex("example\\.com/\\w+/foo")

when 뒤에 조건문이 오고 조건문 정의시 {{ }} 를 사용하지 않는다.

tasks:

  - shell: /usr/bin/foo
    register: result
    ignore_errors: True

  - debug:
      msg: "it failed"
    when: result is failed

  # in most cases you'll want a handler, but if you want to do something right now, this is nice
  - debug:
      msg: "it changed"
    when: result is changed

  - debug:
      msg: "it succeeded in Ansible >= 2.1"
    when: result is succeeded

  - debug:
      msg: "it succeeded"
    when: result is success

  - debug:
      msg: "it was skipped"
    when: result is skipped

register 등록 변수는 해당 작업의 리턴 밸류를 저장하는 변수로 작업을 실행할 때 리턴 밸류 값을 사용해야 하는 경우 등록 변수를 사용한다.

failed: 작업이 실패했을 때

changed: 작업이 성공하고 실제 값이 변경됐을 때

succeded == success: 작업이 성공했지만 실제 값이 변경되지는 않았을 때

skipped: 작업이 스킵된 경우

조건문에 많이 사용하는 팩트 변수: https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#commonly-used-facts

  • ansible_facts[”distribution”] == ansible_distribution

$ cat /etc/os-release 를 실행하면 해당 리눅스 os 의 계열과 정보 등을 확인할 수 있다.

$ ansible [ip 주소] -m setup 명령어를 실행하면 팩트 변수를 수집하여 보여준다.

[vagrant@controller 03_condition]$ cat test2.yml
- hosts: wp
  tasks:
    - debug:
        msg: "hello CentOS"
      when: ansible_facts["distribution"] == "CentOS"
    - debug:
        msg: "hello Ubuntu"
[vagrant@controller 03_condition]$ ansible-playbook test2.yml 

PLAY [wp] ***********************************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************************
ok: [192.168.100.11]
ok: [192.168.100.12]
ok: [192.168.100.13]

TASK [debug] ********************************************************************************************************************************************************************************************
ok: [192.168.100.11] => {
    "msg": "hello CentOS"
}
ok: [192.168.100.12] => {
    "msg": "hello CentOS"
}
skipping: [192.168.100.13]

TASK [debug] ********************************************************************************************************************************************************************************************
skipping: [192.168.100.11]
skipping: [192.168.100.12]
ok: [192.168.100.13] => {
    "msg": "hello Ubuntu"
}

PLAY RECAP **********************************************************************************************************************************************************************************************
192.168.100.11             : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.100.12             : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.100.13             : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

핸들러

가능하면 멱등성을 만족해야 한다.

모든 모듈, 모듈의 파라미터가 멱등성을 만족하지는 않는다.

멱등성에 문제가 있는 코드, 플레이북을 실행할 때 마다 매번 서비스를 리스타트한다. 멱등성을 위배!

- hosts: 192.168.100.12
  vars:
    web_svc_port: "8080"
  tasks:
    - yum:
        name: httpd
    - lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^Listen'
        line: 'Listen {{ web_svc_port }}'
      register: result
    - service:
        name: httpd
        state: restarted
        enabled: yes

등록 변수를 사용해서 포트가 변경됐을 때만 서비스를 재시작하도록 설정했다.

- hosts: 192.168.100.12
  vars:
    web_svc_port: "8080"
  tasks:
    - yum:
        name: httpd
    - lineinfile:
        path: /etc/httpd/conf/httpd.conf
        regexp: '^Listen'
        line: 'Listen {{ web_svc_port }}'
      register: result
    - service:
        name: httpd
        state: started
        enabled: yes
    - service: 
        name: httpd
        state: restarted
      when: result is changed

핸들러 공식 문서: https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html#controlling-when-handlers-run

핸들러는 특정 작업이 변경 사항을 발생하는 경우에만 실행하기 위한 작업을 지정

handlers, notify 와 name 을 이용하여 핸들링할 수 있다

- name: Verify apache installation
  hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root

  tasks:
    - name: Ensure apache is at the latest version
      yum:
        name: httpd
        state: latest

    - name: Write the apache config file
      template:
        src: /srv/httpd.j2
        dest: /etc/httpd.conf
      notify:
      - Restart apache

    - name: Ensure apache is running
      service:
        name: httpd
        state: started

    handlers:
      - name: Restart apache
        ansible.builtin.service:
          name: httpd
          state: restarted

핸들러가 실행되는 순서?

  • 알림을 받은 핸들러 작업만 순서대로 실행
  • 모든 작업(tasks)이 끝난 이후에 핸들러가 실행된다.
  • 알림을 받은 횟수와 상관없이 한 번만 실행된다.

핸들러가 실행되지 않고 후속 작업에서 실패한 경우

결론: 핸들러가 실행되지 않음

강제로 핸들러를 실행하게 하는 설정은 아래와 같다.

- name: Flush handlers
  meta: Flush_handlers
$ ansible-playbook test.yml -b --force-hadnlers

블록

공식 문서: https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html#playbooks-blocks

작업들(tasks)을 여러개 묶어 놓은 그룹을 블록이라고 한다.

어떤 작업들에 똑같은 조건을 사용해야 할 경우, 블록문을 만들고 블록에 조건을 적용시킬 수 있다. 아래 예를 살펴보자.

tasks:
   - name: Install, configure, and start Apache
     block:
       - name: Install httpd and memcached
         ansible.builtin.yum:
           name:
           - httpd
           - memcached
           state: present

       - name: Apply the foo config template
         ansible.builtin.template:
           src: templates/src.j2
           dest: /etc/foo.conf

       - name: Start service bar and enable it
         ansible.builtin.service:
           name: bar
           state: started
           enabled: True
     when: ansible_facts['distribution'] == 'CentOS'
     become: true
     become_user: root
     ignore_errors: yes

블록의 기능

  1. 여러 작업에 공통의 키워드를 부여할 수 있다. (ex: 조건문)
  2. java 나 typescript 의 try catch 구문 처럼 블록의 작업이 실패했을 시에 실행될 작업을 rescue 에 적어놓으면 실행이 된다. (block, rescue)
  3. try catch finall 에서 finall 에 해당하는 always 문을 작성할 수 있다. 블록의 작업이 실패하든 성공하든 상관없이 always 문에 있는 작업은 항상 실행된다.
- hosts: 192.168.100.11

  tasks:
    - block:
        - debug:
            msg: hello world
        - command: /usr/bin/false
        - debug:
            msg: hello world2
      ignore_errors: yes

      rescue:
        - debug:
            msg: It's rescue

      always:
        - debug:
            msg: It's Always

태그

공식 문서: https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html#tags

작업에 태그를 부여하고 특정 태그의 작업만 실행할 수 있다.

all 태그: 모든 작업이 속한다.

untagged 태그: 태그가 설정되어 있지 않는 작업이 속한다.

ansible-playbook --tags==태그이름 으로 플레이북에서 특정 태그만 실행시킬 수 있다.

태그가 붙지 않은 녀석들을 실행하고 싶으면 ansible-playbook --tags==untagged 를 실행하면 된다.

혹은 여러 태그들을 포함해서 실행하고 싶을 경우 ansible-playbook --tags==stage,prod 처럼 실행하면 된다.

태그 관련 확인하는 명령어는 아래와 같다.

ansible-playbook test.yml --lists-tags
ansible-playbook test.tml --lists-tasks

작업 제어

작업을 하나 하나 실행하거나 실행하지 않거나 제어할 수 있다.

ansible-playbook test.yml --step

start-at-task

해당 하는 태스크에서 작업을 시작할 수 있다. 해당 태스크 이전의 태스크는 실행하지 않는다.

ansible-playbook test.yml --start-at-task="태스크 이름"
ansible-playbook test.yml --start-at-task="태스크 이름" 
728x90