ansible playbook에서의 오류처리

ansible에서는 각 task의 return code를 평가하여 task의 성공 여부를 판단한다. 일반적으로 task에서 하나가 실패하는 즉시 ansible은 해당 호스트의 나머지 play를 중단하고 종료된다. 하지만 작업이 실패한다 하더라도 play를 계속할 수 있어야 한다. 예를들어 특정 작업이 실패할 것으로 예상하고 몇가지 다른 작업을 조건부로 실행하여 복구하려고 할 수도 있기 때문이다.

 

 

작업 실패 무시하기 : ignore_errors

- 각각의 모듈 task에 대해 ignore_errors: yes 라고 명시할 수 있고, 이렇게 명시되면 task가 실패해도 무시하고 그대로 playbook이 진행된다.

- name: latest version of notapkg is installed
  yum:
    name: notapkg
    state: latest
  ignore_errors: yes

- 위 예시의 경우, notapkg를 설치하지 못하는 경우 실패할 것이지만 ignore_errors: yes이므로 그대로 진행된다.

 

작업 실패 후 핸들러 강제 실행하기 : force_handlers

- 예를들어 마지막 task가 실패하여 해당 호스트에서 play가 중단되면, 이전 task에 대해 trigger된 모든 핸들러가 실행되지 않는다. 

- 따라서 다른 task에서 작업이 실패해도 핸들러는 작동하게 하려면, force_handlers 지시문을 아래와 같이 적용한다.

---
- hosts: all
  force_handlers: yes
  
  tasks:
    - name: a task which always notifies its handler
      command: /bin/true
      notify: restart the database

    - name: "a task which fails because the package doesn't exist"
      yum:
        name: notapkg
        state: latest

  handlers:
    - name: restart the database
      service:
        name: mariadb
        state: restarted

 

작업 실패 조건 지정 : failed_when

- 이것은 조건문인데, 명령이 성공이었다고 하더라도 특정 조건을 만족하면 fail로 만들라는 조건문이다.

- 예를 들어 아래 구문은, task가 성공적이었다 하더라도 결과에 "Password missing"이라는 구문이 있다면 fail로 만드는 것이다. task가 성공이므로 changed라고 뜨겠지만, 실제로는 password에 문제가 있는 것이므로 이것은 좋지 않다. 문제가 있는 상태에서 핸들러가 작동할수도 있다.

- 아래처럼 이렇게 하면 changed가 남지 않으므로 핸들러를 설정한 경우 핸들러가 작동하지 않을 것이다. 

tasks:
  - name: Run user createion script
    shell: /usr/local/bin/create_users.sh
    register: command_result
    failed_when: "'Password missing' in command_result.stdout"

 

- 또 다른 방식으로, failed 모듈을 사용해 작업 실패를 강제할 수 있다. 이 방식은 위 내용과 결과가 완전히 동일하며, 조금 복잡하지만 명확한 실패 메시지를 제공할 수 있다.

tasks:
  - name: Run user createion script
    shell: /usr/local/bin/create_users.sh
    register: command_result
    ignore_errors: yes

  - name: Report script failure
    fail:
      msg: "the password is missing in the output"
    when: "'Password missing' in the command_result.stdout"

- 여기서는 fail 모듈과 조건문 when을 사용하여, task가 잘 되었다 하더라도 "Password missing" 이라는 구문이 포함되면 해당 구문을 fail시키고 사전에 정의해둔 메시지를 출력한다. 

 

 

작업 결과를 changed로 보고하는 시점 지정 : changed_when

* changed_when: false 사용

- 이 키워드는 task에서 changed 결과를 보고하는 시점을 제어할 수 있다. 실제로 changed가 나와야 되는 task에 대해서도 changed_when: false 지시문을 포함하면 changed 로 보고되지 않는다. ok로 보고된다. 만약 true로 한다면 changed로 보고된다.

---
- name: play to setup web server
  hosts: web.example.com
  tasks:
    - name: latest httpd version installed
      yum:
        name: httpd
        state: absent
      register: uninstall_result
      changed_when: false
    - name: debug install_result
      debug:
        var: uninstall_result

- 분명히 변경이 있는데, (삭제작업수행) ok로 뜬다.

 

* changed_when: 조건문 사용

- when이 붙었으므로 이것도 조건문을 사용할 수 있다. 이 조건이 맞으면, 즉 true이면, changed로 보고한다.

- 모든 모듈에 이 지시문을 쓸 수 있겠지만, 일반적으로 command, shell, raw 같이 무조건 changed로 보고되는 모듈에 대해 결과에 대한 반환값을 컨트롤하기 위해 자주 사용된다.

- 아래 예시를 참고하자.

---
- name: changed_when test
  hosts: web.example.com
  tasks:
    - shell:
        cmd: /tmp/upgrade-database
      register: command_result
      changed_when: "'completed' in command_result.stdout"
      notify:
        - restart_httpd

    - debug:
        var: command_result

  handlers:
    - name: restart_httpd
      service:
        name: httpd
        state: restarted

현재 httpd와 mariadb가 설치되어 있고, database를 업그레이드 하면 httpd를 재시작하는 핸들러를 가진다.  shell 모듈을 썼으므로 결과는 무조건 changed로 나올 것이다. 여기서 upgrade-database라는 프로그램의 결과가  "changed failed" 라고 가정하자(문제 발생을 가정한다). 즉 문제가 발생하면 handler는 실행되면 안된다. 따라서 위와 같이 changed_when: 조건이 completed가 결과에  포함되어있으면 false를 출력하도록  ansible-playbook을 만든다.  이렇게 false가 되면 ok를 출력하게 된다. 따라서 핸들러를 실행하지 않는다.

 

작업을 논리적으로 그룹화하기 : block

playbook에서, block은 task 들을 논리적으로 그룹화한다. 이 방법은 작업을 실행하는 방법을 제어할 때 사용할 수 있다. 크게 2가지 방법을 사용한다. 첫번째는 여러개의 task 중 몇개를 묶어서 뭔가 작업을 할 때, 그리고 두번째는 blocks와 함께 rescue, always를 함께 사용하여 작업 루틴을 설정할 때 사용한다.

 

* task를 몇개 묶어서 작업할 때 사용

- 아래는 총 task가 3개인데, 그 중 2개는 block에 묶여있고 when 조건이 적용되며, 남은 하나는 block과 연관없이 단독으로 수행된다.

- name: block example
  hosts: web.example.com
  tasks:

    - block:
      - name: package needed by yum
        yum:
          name: yum-plugin-versionlock
          state: present

      - name: lock version of tzdata
        lineinfile:
          dest: /etc/yum/pluginconf.d/versionlock.list
          line: tzdata-2016j-1
          state: present
        register: check_result
      when: ansible_distribution == "CentOS"

    - name: check result
      debug:
        var: check_result

해당 서버가 CentOS가 맞으므로 block 안에 있는 2개의 task가 실행되었다.

 

 

* block과 rescue, always 문을 함께 사용하여 오류처리

- 아래와 같이 작업 실패 여부에 따른 루틴을 정의하여 오류처리를 할 수 있다.

     - block : 실행할 기본 작업을 정의

     - rescue: block에 정의된 작업이 실패하는 경우에만 실행되는 작업을 정의

     - always: block과 rescue 문에 정의된 작업의 성공/실패 여부와 상관없이 항상 실행되는 작업을 정의

- 아래 예시를 살펴보자.

- name: block example
  hosts: web.example.com
  tasks:
    - block:
        - name: upgrade the database
          shell:
            cmd: /usr/local/lib/upgrade-database
      rescue:
        - name: revert the database upgrade
          shell:
            cmd: /usr/local/lib/revert-database
      always:
        - name: always restart the database
          service:
            name: mariadb
            state: restarted

- /usr/local/lib/upgrade-database 파일이 없기 때문에 에러가 났다. 에러가 나면 일반적으로 playbook이 종료되지만 여기서는 그렇지 않다.

- block에서 에러가 났으므로 rescue가 실행된다. 실행이 잘 되었고, 그다음 always 는 항상 실행되므로 실행된다. 둘다 잘 실행되었다.

 

 

 

 

 

연습문제

* ignore_errors: yes 사용하기

http라는 패키지는 없으므로 에러가 발생한다. 하지만 ignore_errors: yes 이므로 그대로 진행해서 아래까지 완료한다.

---
- name: Task Failure Exercise
  hosts: db.example.com
  vars:
    web_package: http
    db_package: mariadb-server
    db_service: mariadb

  tasks:
    - name: Install {{ web_package }} package
      yum:
        name: "{{ web_package }}"
        state: present
      ignore_errors: yes

    - name: Install {{ db_package }} package
      yum:
        name: "{{ db_package }}"
        state: present

 

* changed_when, failed_when 사용하기

- command: date 이 부분은 항상 changed가 된다. 따라서 이것을 그냥 ok로 하기 위해 changed_when: false를 사용한다.

- Install httpd package부분은 이미 설치된 상태에서 수행했기 때문에 already installed가 뜬다. 하지만 fail은 아니고 ok가 원래 떠야 한다. 그런데 failed_when 조건에 맞기 때문에 그냥 failed가 떠버렸다. 

- block부분에 failed가 떴으므로, rescue 부분의 install mariadb-server package 부분이 실행된다. always는 항상 실행된다.

---
- name: Task Failure Exercise
  hosts: db.example.com
  vars:
    web_package: httpd
    db_package: mariadb-server
    db_service: mariadb

  tasks:

    - name: Check local time
      command: date
      register: command_result
      changed_when: false

    - name: print local time
      debug:
        var: command_result.stdout


    - block:
        - name: Install {{ web_package }} package
          yum:
            name: "{{ web_package }}"
            state: present
          failed_when: web_package == "httpd"
      rescue:
        - name: Install {{ db_package }} package
          yum:
            name: "{{ db_package }}"
            state: present
      always:
        - name: Start {{ db_service }} service
          service:
            name: "{{ db_service }}"
            state: started

 

 

 

 

 

참조링크

 

- 플레이북에서 오류 처리 ansible 설명서

docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html

 

Error handling in playbooks — Ansible Documentation

When Ansible receives a non-zero return code from a command or a failure from a module, by default it stops executing on that host and continues on other hosts. However, in some circumstances you may want different behavior. Sometimes a non-zero return cod

docs.ansible.com

- 오류처리 ansible 설명서

docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html#error-handling

 

Blocks — Ansible Documentation

Blocks create logical groups of tasks. Blocks also offer ways to handle task errors, similar to exception handling in many programming languages. All tasks in a block inherit directives applied at the block level. Most of what you can apply to a single tas

docs.ansible.com

 

 

 

 

'Ansible' 카테고리의 다른 글

15장. 병렬 구성 작업  (1) 2021.02.27
14장. ansible에서 jinja2 사용하기  (0) 2021.02.26
12장. 작업 제어 구현 - 핸들러  (0) 2021.02.24
11장. 작업 제어 구현 - 반복문과 조건문  (0) 2021.02.23
10장. ansible vault  (0) 2021.02.23

핸들러란?

필요에 따라 한 작업에서 시스템을 변경하는 경우, 추가 작업이 필요한 경우가 있다. 예를 들어, 특정 데몬 서비스의 구성파일을 변경했으면, 변경한 구성이 적용되도록 서비스 데몬을 reload 해야 한다. 핸들러는 다른 작업에서 trigger한 알림에 응답하는 작업이다.

 

즉 정확한 핸들러의 목적은, task가 ansible client에 변경 (changed)를 할 때 추가적인 조치를 수행하기 위한 목적을 가지고 있다. 정상적인 일반 task를 대체하기 위해 사용되어서는 안된다. 일반적인 사용 예시로서 핸들러는 호스트를 재부팅하고 서비스를 다시 시작하는데 자주 사용된다. ansible-playbook에서는 notify 라는 구문과 handlers 라는 구문을 사용해서 구현한다. 

 

 

핸들러 사용 예시 

 

* 예시1

이 구문은 ansible host에 있는 test.conf.source 파일을 ansible client인 web.example.com 의 /tmp/test.conf 로 복사하고, 복사가 잘 되어 changed가 떴다면, 그 아래 "restart httpd" 라는 핸들러를 실행시키는 구문이다.

---
- name: after cp file then trigger handler
  hosts: web.example.com
  tasks:
    - name: copy file
      template:
        src: /tmp/test.conf.source
        dest: /tmp/test.conf
      notify:
        - restart httpd
  handlers:
    - name: restart httpd
      service:
        name: httpd
        state: restarted

 

* 예시2

여러개의 핸들러가 있을 때 순서가 어떻게 되는지 확인할 수 있다.

---
- hosts: was.example.com
  tasks:
    - command: echo 'first messages'
      notify:
        - test handler
        - new handler

    - debug:
        msg: second message

  handlers:
    - name: new handler
      debug:
        msg: new handler messages.

    - name: test handler
      debug:
        msg: message in handler

 

 

 

handler의 속성

- 핸들러는 notify 구문을 사용해 명시적으로 호출된 경우에만 trigger되는 비활성 작업이다.

- task는 ansible client에서 작업이 changed라고 떴을 때만 핸들러에 통지를 한다.  (ok, failed로 뜨면 trigger되지 않음)

- notify문을 포함한 작업이 changed 결과를 보고하지 않으면 핸들러가 trigger되지 않는다. (예를들어, 패키지가 이미 설치되어있는데 패키지 설치를 동일하게 하면 changed가 없을 것임) 즉 change가 없으면 핸들러는 skip 된다.

 

- 각 핸들러에는 전역적으로 고유한 이름을 가지며, 플레이북의 작업 블록 끝에서 trigger된다.

- task에서 핸들러에게 이름으로 알리지 않으면 핸들러가 실행되지 않는다.

- 하나 이상의 task를 핸들러에게 알리면 play의 다른 모든 작업이 완료된 후에 핸들러가 정확하게 한 번 실행된다.

- 핸들러는 task이므로 관리자가 다른 작업에 사용하려는 핸들러에 같은 모듈을 사용할 수 있다.

 

- notify 구문이 하나가 아니라 여러개라면, 핸들러는 배열로 취급해서 여러개 명시된걸 모두 다 수행한다.

- 핸들러의 작동 순서는, task의 notify 문을 나열한 순서대로 하지 않으며 handlers: 에 명시된 순서대로 실행된다.

- 핸들러는 일반적으로 play에 있는 다른 모든 작업이 완료된 후 실행한다. 즉 tasks 부분의 작업에서 호출한 핸들러는 tasks 아래에 있는 모든 작업들이 다 처리된 후에 실행을 한다. (예외는 있음)

- 둘 이상의 task에서 하나의 핸들러를 trigger하는 경우, 해당 핸들러는 한 번만 실행된다. 

- task가 핸들러를 trigger하지 않는 경우, 핸들러가 실행되지 않는다.

 

 

 

 

 

참고 : 플레이북의 handler 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_intro.html

 

Intro to Playbooks — Ansible Documentation

Docs » User Guide » Working With Playbooks » Intro to Playbooks You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained versio

docs.ansible.com

 

Intro to Playbooks — Ansible Documentation

Docs » User Guide » Working With Playbooks » Intro to Playbooks You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained versio

docs.ansible.com

 

 

 

 

'Ansible' 카테고리의 다른 글

14장. ansible에서 jinja2 사용하기  (0) 2021.02.26
13장. 작업 제어 구현 - 오류처리  (0) 2021.02.25
11장. 작업 제어 구현 - 반복문과 조건문  (0) 2021.02.23
10장. ansible vault  (0) 2021.02.23
9장. fact 변수 관리  (0) 2021.02.20

ansible-playbook에서 반복문 사용

반복문을 사용하면 관리자는 동일한 모듈을 사용하는 여러개의 작업을 작성할 필요가 없고, 구문을 간단하게 만들 수 있다. 예를 들어, 5명의 사용자가 존재하는지 확인하기 위해 5개의 작업을 만들 필요가 없고, 5명의 사용자에 대해 반복하는 하나의 작업을 작성하면 된다.

 

ansible에서는 작업 반복에 대해 loop 키워드를 사용한다. 여기서는 간단하게만 설명하며, 더 자세한 반복문 시나리오와 관련 설명은 설명서 링크를 참고할 것.

 

반복문 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_loops.html 

 

Loops — Ansible Documentation

Docs » User Guide » Working With Playbooks » Loops You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the la

docs.ansible.com

 

단순 반복문

loop 지시문과 변수를 받아 반복을 수행한다. 변수에 방식에 따라 3가지의 방식이 있다.

 

1. 기본 item 변수 사용

- name: test1
  hosts: web1.example.com
  tasks:
    - name: postfix and httpd are running
      service:
        - name: "{{ item }}"
          state: started
      loop:
        - postfix
        - httpd

- loop 지시문에 반복할 값들을 명시하면 순서대로 한번씩 item 변수에 넣는다. item 변수는 따로 정의한 게 아니고 반복문에서 자동으로 쓰는 전용 변수이다. 즉 loop가 돌 때마다 loop안에 있는 요소가 위에서부터 순차적으로 하나씩 넣고, 하나하나 다 넣으면 루프가 끝난다.

 

 

2. 사용자 정의 변수 사용 

- name: test1
  hosts: web1.example.com
  
  vars:
    check_services:
      - postfix
      - httpd
    
  tasks:
    - name: postfix and httpd are running
      service:
        - name: "{{ item }}"
          state: started
      loop: "{{ check_services }}"

- 사용자가 check_services 라는 변수 목록을 만들고, loop에 해당 변수를 명시하는 방식이다. 1번과 동일하게 순서대로 한번씩 item 변수에 넣는다.

 

3.  hash/dictionary 목록으로 된 변수 사용

- name: group loop
  hosts: web1.example.com

  tasks:
    - name: users eaist and are in the correct groups
      user:
        name: "{{ item.name }}"
        state: present
        groups: "{{ item.groups }}"
      loop:
        - name: jane
          groups: wheel
        - name: joe
          groups: root

- 여기서는 loop 밑에 - name group 이 하나이고 그 다음 또 - name group 가 하나로써 루프에 들어간다.

- 즉 맨 처음에는 name에 jane, groups에 wheel이 들어가서 반복 한번이 끝나고, 그 다음 반복으로 name에 joe, groups에 root가 들어가게 된다.

 

 

# 참고 : 이전 버전의 반복문 키워드

ansible 2.5 이전에는 다른 구문을 사용했음. with_ 가 앞에 오고, ansible 조회 플러그인의 이름이 뒤에 오는 여러개의 반복문 키워드가 제공되었다. (with_items, with_files 등) 이러한 구문은 이전 버전에선 매우 일반적이지만, 향후 없어질 것이다. 여기서는 따로 이야기하지 않으므로 필요하다면 따로 찾아볼 것.

 

# 참고 : loop 지시문 위치

- loop 지시문은 각각의 모듈 이하에 있으므로, 여러개의 모듈이 있는 경우 loop의 위치를 정확히 해야한다.

- 아래 예시에서는 에러가 난다. loop가 첫번째 debug 밑에 있어야 하기 때문이다.

- hosts: servera
  tasks:
    - debug:
        msg: "{{ item }} started"
    - debug:
        msg: hello world
      loop:
        - postfix
        - dovecot

 

 

 

반복문에서 레지스터 변수 사용하기

- 아래와 같이 loop 지시문 다음에 register를 쓰면, 각 loop 당 register에 값이 들어간다.

- 즉, loop의 첫번째 값 one으로 루프를 돌고 echo_results에 결과를 저장하고, 그다음 loop의 두번째 값 two로 루프를 돌고 echo_results에 저장해서 총 2개의 결과값이 echo_results에 저장되게 된다.

- name: loop register test
  hosts: web.example.com
  gather_facts: no

  tasks:
    - name: looping echo task
      shell: "echo this is my item: {{ item }}"
      loop:
        - one
        - two
      register: echo_results

    - name: show result
      debug:
        var: echo_results

- 결과가 너무 길어 show result 부분만 캡쳐했다. one과 two가 결과로 나온 것을 확인할 수 있다.

- echo 명령의 출력 결과는 "stdout" 부분에 나오게 된다.

 

ansible-playbook에서 조건문 사용

ansible에서는 조건문을 사용하여 특정 조건을 충족하면 작동하는 playbook을 실행할 수 있다.  예를 들어 다음과 같은 예시 시나리오를 생각해볼 수 있다.

 

- 하드웨어 제한을 변수에 정의하고 (예 : min_memory) 관리 호스트에서 사용가능한 메모리와 비교할 수 있다.

- ansible에서 이후 작업을 수행하기 전에 작업 완료 여부를 확인하기 위해 명령 출력을 캡쳐하고 평가할 수 있다. 예를 들어 프로그램이 실패하는 경우, 배치를 건너뛴다.

- ansible_facts를 사용하여 관리 호스트 네트워크 구성을 확인하고, 보내려는 템플릿 파일을 결정할 수 있다.

- cpu 수를 평가하여 웹 서버를 적절히 조정할 수 있다.

- 등록된 변수를 사전 정의된 변수와 비교화여 서비스가 변경되었는지 확인한다. 예를 들어 서비스 구성파일의 md5 체크섬을 테스트해 서비스가 변경되었는지 확인할 수 있다.

 

* 조건식 연산자

- ansible에서의 조건문은 기본적으로 아래와 같이 조건식 연산자를 사용해 조건을 평가하여 task를 실행할지 말지 여부를 결정하게 된다. 

연산

예시

같음(숫자)
같음(문자열)

max_memory == 512
ansible_machine == "x86_64"

미만

min_memory < 128

보다 큼

min_memory > 256

작거나 같음

min_memory <= 256

크거나 같음

min_memory >= 256

같지 않음

min_memory != 512

변수 있음

min_memory is defined
min_memory라는 변수가 존재하면 true 

변수 없음

min_memory is not defined

부울 변수가 false이다.

not memory_available

부울 변수가 true이다.

memory_available

첫 번째 변수의 값이 두번째 변수 목록의 값으로 표시됨

ansible_distribution in supported_distros

이 예시는 ansible_distribution 이라는 팩트변수이며, supported_distros 안에 ansible_distribution이라는 항목이 있으면 true 가 되는 것이다.

 

기본 조건문

when 지시문을 사용하여 조건문을 사용하며, when은 테스트할 조건이 값으로 들어간다. 위에서 명시한 조건식 연산자를 사용하여 특정 조건이 충족되면 해당 task가 실행된다. 조건을 충족하지 않으면 작업을 건너뛰게 된다. when은 보통 task 아래 name과 같은 수준의 최상위이며(즉, 모듈 안에 포함되는 것이 아님) task, name, module명 보다 맨 마지막에 두는 것이 일반적이다. 아래는 몇가지 조건문의 예시이다.

 

* 조건문이 true인 경우

- 단순히 when 부분에 true가 들어가면 조건대로 작동한다. 만약 run_my_task: false 였으면 작동하지 않았을 것.

- name: loop register test
  hosts: all
  vars:
    run_my_task: true

  tasks:
    - name: install http package
      yum:
        name: httpd
        state: latest
      when: run_my_task

- 참고로, when 구문에서는 변수를 써도 "{{ }}" 를 써지 않아도 되는 듯하다.

 

* 변수에 값이 있는 경우 true

is defined는 변수가 존재하는지를 확인하며, 존재하므로 true이다. 그러므로 해당 task가 실행된다.

- name: test virable is defined demo
  hosts: web.example.com
  vars:
    my_service: httpd

  tasks:
    - name: "{{ my_service }} package will be removed"
      yum:
        name: httpd
        state: absent
      when: my_service is defined

 

* 특정 리스트 안에 특정 값이 있다면 true

- ansible_distribution은 해당 서버의 OS  종류를 알려준다. 확인한 OS 종류를 supported_distros에 있는 변수들과 비교해서 일치하는 것이 있으면 ture가 된다.

- 다음의 형태를 따른다.  (when: 일치할내용 in 검색할값들모음변수)

- name : list when test
  hosts: web.example.com
  vars:
    supported_distros:
      - RedHat
      - CentOS
      - Fedora
      - ubuntu

  tasks:
    - name : debug
      debug:
        msg: "{{ ansible_distribution }}"

    - name: install httpd using yum, where supported
      yum:
        name: httpd
        state: present
      when: ansible_distribution in supported_distros

 

여러개의 조건이 합쳐진 조건문

하나의 when 지시자에 여러개의 조건문을 평가할 수 있다. 이를 위해 and, or, 괄호( ) 를 사용할 수 있다.

 

* or

- 두 조건 중 하나만 true 여도 되는 경우 사용

- 예시 : 시스템에서 RHEL 또는 Fedora 둘 중 아무거나 하나면 되는 경우

- 구문 :  when: ansible_distribution == "RedHat" or ansible_distribution == "Fedora"

 

* and

- 두 조건 모두 true 여야만 하는 경우 사용

- 예시 : RHEL 버전이 7.5여야 하고 또한 커널버전이 3.10.0-327 이어야 하는 경우

- 구문 : when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"

 

# 참고 : when 지시문에서 목록으로 표시를 하면 자동으로 and 연산자가 사용된다.

when:
  - ansible_distribution_version == "7.5"
  - ansible_kernel == "3.10.0-327.el7.x86_64"

 

* ( ) 괄호

- 복잡한 조건문은 괄호를 사용해서 알아보기 쉽게 만들 수 있다.

- 참고로, > 는 긴 한줄을 여러 줄로 나누어 읽기 쉽게 한다. (실제로는 한줄이다)

when: >
  ( ansible_distribution == "RedHat" and
    ansible_distribution_major_version == "7" )
  or
  ( ansible_distribution == "Fedora" and
    ansible_distribution_major_version == "28" )

 

 

register 값을 조건문에 사용하기

- register는 앞에도 말했듯이 task의 결과를 변수로 가진다. 따라서 task의 결과값의 내용 중 특정 값을 가지고 조건문을 사용할수도 있다.

 

- 아래 예시는 chronyd가 현재 실행중인지지 확인하고, 실행중이라면 httpd를 재시작하는 구문이다.

---
- name: Restart httpd if chronyd is running
  hosts: web.example.com
  tasks:
    - name: get chronyd server status
      command: systemctl is-active chronyd
      ignore_errors: yes
      register: result

    - name: restart httpd based on chronyd status
      service:
        name: httpd
        state: restarted
      when: result.rc == 0

- ignore_errors: yes를 하는 이유는, 만약 chronyd가 active가 아니라면 systemctl is-active chronyd의 결과 리턴코드가 0이 아니게 된다. ansible에서는 모든 작업의 리턴코드가 0이어야만 정상이라고 인식한다. 따라서 리턴코드가 0이 아니면 playbook 진행상에 에러가 발생하며 에러가 발생하면 ansible 작업이 즉시 종료된다. 따라서 이 에러가 발생해도 그대로 진행하도록 하기 위해서 사용한다. (즉, 에러가 발생하는 것 자체가 이 playbook에 예상되어 있다는 것이다)

- result.rc == 0 이 구문은 register 변수에 저장된 task의 결과가 result에 저장되어 있고 그 저장된 값 중 rc라는 값이 0인지 검사하는 구문이다. 여기서 rc값은 리턴코드를 의미한다.

 

# 참고 : 리턴코드(rc) 란?

리눅스에서 어떤 명령이든 실행한 후 프롬프트에서 echo $? 를 입력하면, 바로 전 명령의 리턴코드를 보여준다. 정상적으로 명령이 실행되었다면 0이 나오고, 정상이 아니라면 0이 아닌 다른 값이 나온다. ansible을 비롯한 많은 프로그램들이 특정 명령이 제대로 잘 실행되었다는 것을 판단하기 위해 리턴코드를 사용한다.

 

 

 

 

 

반복문과 조건문을  함께 사용하기

- task 안에서 반복문 loop와 조건문 when을 함께 사용하면, 각 loop의 항목에 대해 when이 검사되는 형태가 된다. when은 맨 마지막에 쓴다.

- 아래 예시는 파일시스템의 특정 마운트 포인트의 용량이 300000000이상인 경우 패키지를 설치하는 구문이다.

- name : filesystem test
  hosts: web2.example.com
  tasks:
    - name: install mariadb-server if enough space on root
      yum:
        name: mariadb-server
        state: latest

      loop: "{{ ansible_mounts }}"
      when: item.mount == "/" and item.size_available > 300000000

 

- 여기서, ansible_mounts 라는 변수는 facts 변수에 있는 값이며, 이 값을 확인하면 아래와 같다. 

- 중괄호 3개가 있고, loop에서는 이 3개의 중괄호를 하나씩 loop로 검사한다. 이 3번 돌리는 값이 item 변수에 들어간다.

- loop를 돌리면 item변수에 해당 중괄호 값이 하나가 들어갈 것이고, 그 안에 조건문인 when이 작동하여, item.mount 값과 item.size_available의 조건을 확인해서 해당 조건과 맞으면 위의 task를 실행하게 된다.

 

- 다시 정리하면, loop와 when을 함께 사용하면 loop안에 when이 있는 것처럼 작동한다. when 안에 loop가 있는 방식이 존재하는지는 확실히 모르겠고, 이 강의에서는 이정도 선까지만 교육한다.

 

 

 

 

 

 

연습문제

- 지정한 ansible client에 데이터베이스 설치, 사용자 계정을 설정한다.

- 3가지의 yaml 파일을 사용한다.

     - database_setup.yml : 데이터베이스를 설치하는데, 최소조건에 맞는지 확인

     - CentOS_database_tasks.yml : 데이터베이스 패키지를 설치하고, 서비스를 시작하고, enable시킨다.  

      - database_user_tasks.yml : 특정 유저를 조건에 맞춰서 생성한다.

- 이렇게 나눈 이유는, 다른 패키지나 다른 유저설정을 할 때 재사용하기 쉽게 최소작업단위로 분할을 한 것이다. 

 

* database_setup.yml

---
- name: database setup play
  hosts: db.example.com
  vars:
    min_ram_size_bytes: 500000000
    supported_distros:
      - Redhat
      - CentOS
    host_permission_groups:
      - dbadmin
      - dbuser
    user_list:
      - name: john davis
        username: jdavis
        role: dbadmin
      - name: jennifer smith
        username: jsmith
        role: dbuser
      - name: alen page
        username: alpage
        role: dbuser
# 총 4개 종류의 변수를 지정한다.

  tasks:
    - name: Setup database tasks on supported hosts w/ Min. RAM
      include_tasks: "{{ ansible_distribution }}_database_tasks.yml"
      when:
        - ansible_distribution in supported_distros
        - ansible_memtotal_mb*1024*1024 >= min_ram_size_bytes
# 서버 OS와 램 용량이 조건에 맞으면 -> os명_database_tasks.yml 이 파일로 진행이 된다.

    - name: print a messages for unsupported Distros
      debug:
        msg: >
          {{ inventory_hostname }} is a
          {{ ansible_distribution }}-based host, which is not one
          of the supported distributions ({{ supported_distros }})
      when: ansible_distribution not in supported_distros
#  서버 OS에 문제가 있는경우 해당 내용이 작동한다. 만약 문제가 없으면 SKIP된다.

    - name: Print a message for systems with insufficient RAM
      debug:
        msg: >
          {{ inventory_hostname }} does not meet the minimum RAM
          requirements of {{ min_ram_size_bytes }} bytes.
      when: ansible_memtotal_mb*1024*1024 < min_ram_size_bytes
# 서버 메모리에 문제가 있는경우 해당 내용이 작동한다. 만약 문제가 없으면 SKIP 된다.
# 즉, 정리하면 아무 문제가 없는경우, 3개의 TASK 중 맨 위 한개만 작동하게 된다.

- 여기서 사용하는 변수는 2가지인데, vars에 정의한 사용자 정의 변수, 그리고 팩트변수이다.

- 팩트변수는 다음과 같다.

     - ansible_distribution

     - inventory_hostname

     - ansible_memtotal_mb

 

* CentOS_database_tasks.yml

#For CentOS, using mariadb as the database service
- name: Set the 'db_service' fact
  set_fact:
    db_service: mariadb
# set_fact 모듈은 mariadb로 설정하는 db_service 변수를 ansible_facts안에 저장한다.
# 이를 통해 각 배포시 다른 데이터베이스 서비스를 활용할 수 있다.

#CentOS packages for mariadb service
- name: Ensure database packages are installed
  yum:
    name:
      - mariadb-server
      - mariadb-bench
      - mariadb-libs
      - mariadb-test
    state: latest
# 패키지를 설치한다.

- name: Ensure the database service is started
  service:
    name: "{{ db_service }}"   # set_fact 모듈로 정의한 사용자 정의 팩트변수이다.
    state: started
    enabled: true
# 위에서 정의한 서비스명으로 서비스를 시작하고 enable한다.

#below tasks are also reused by other distros
- name: create database users
  include_tasks: database_user_tasks.yml
# 계정설정 작업을 수행하기 위해  -> database_user_tasks.yml 파일로 넘어간다.

* database_user_tasks.yml

- name: Ensure database permission groups exist
  group:
    name: "{{ item }}"
    state: present
  loop: "{{ host_permission_groups }}"
# 그룹명 2개가 있는데, 각각을 item으로 하여 present한다. 즉 그룹 2개를 추가한다는 것.

- name: Ensure database user exists
  user:
    name: "{{ item.username }}"
    groups: "{{ item.role }}"
    append: yes
    state: present
  loop: "{{ user_list }}"
  when: item.role in host_permission_groups
# 그룹 리스트(dbadmin, dbuser)를 item 에서 찾아서 일치하면 루프를 작동한다.
# 루프는 유저 리스트대로 진행한다. username으로 계정을 만들고 그 계정은 명시한 그룹에 들어간다.
# append는 yes로 하면 groups로 명시한 그룹을 "추가"한다. no로 하면 groups로 명시한 그룹"만" 포함한다.

 

* 첫 시도 - 서버의 메모리 용량이 적어서 실패

 

* 2차 시도 - 잘 적용됨

 

* 확인

- db.example.com 에 접속해서 아래 명령어들로 확인한다.

cat /etc/passwd
cat /etc/group
rpm -qa |grep mariadb
systemctl status mariadb

 

 

 

참고링크

 

조건문 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_conditionals.html 

 

Conditionals — Ansible Documentation

Docs » User Guide » Working With Playbooks » Conditionals You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See

docs.ansible.com

올바른 변수 이름을 생성하는 법 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html#what-makes-a-valid-variable-name 

 

Using Variables — Ansible Documentation

Docs » User Guide » Working With Playbooks » Using Variables You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version.

docs.ansible.com

테스트 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_tests.html 

 

Tests — Ansible Documentation

You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the latest Ansible documentation. Tests in Jinja are a way o

docs.ansible.com

 

 

'Ansible' 카테고리의 다른 글

13장. 작업 제어 구현 - 오류처리  (0) 2021.02.25
12장. 작업 제어 구현 - 핸들러  (0) 2021.02.24
10장. ansible vault  (0) 2021.02.23
9장. fact 변수 관리  (0) 2021.02.20
8장. 변수 사용하기  (0) 2021.02.20

ansible vault란?

ansible host에서 사용하는 특정 파일이나 ansible-playbook 내용에는 비밀번호나 api 키 값 같은 중요한 데이터가 포함될 수 있다. 이런 것들을 텍스트로 저장하면 보안에 문제가 생길 수 있으므로, 암호화가 필요하다. 이런 암호화를 수행하는 것이 ansible vault 이다. 이것은 모든 구조화된 데이터파일을 암호화/해독 할 수 있다.

 

이러한 기능은 ansible 자체의 암호화 기능은 아니며, 외부 python 도구를 사용한다. 암호화할 대상 파일은 AES256을 사용하여 대칭형 암호화로 보호된다. AES256은 최신버전에서 사용되며, 이전 버전에서는 128BIT AES를 쓸 수도 있다.

 

 

ansible vault의 기능

- 민감한 변수를 암호화

- 암호화한 파일을 해독

- 암호화된 파일을 참조하는 playbook을 사용할 수 있음

- 인벤토리 변수, playbook, 변수파일, ansible role에서 정의된 변수 등 여러가지를 암호화할 수 있다.

 

ansible vault 사용하기

암호화된 파일 만들기 ansible-vault create secret_test.yml
안호화된 파일 확인하기 ansible-vault view secret_test.yml
암호화된 파일 편집하기 ansible-vault edit secret_test.yml
기존 파일 암호화하기 ansible-vault encrypt test_encrypt_yml
암호화된 파일 암호 해제하기 ansible-vault decrypt test_encrypt.yml
암호화된 파일의 접근 암호 변경하기 ansible-vault rekey test_encrypt.yml

 

1. ansible vault로 파일 생성하기

 

구문 : ansible-vault create 파일명

예시 : ansible-vault create secret_test.yml

 

- 이렇게 구문을 실행하면, 패스워드를 물어보며 준비해둔 패스워드를 두번 입력한다.

- 그 후 vim 에디터가 나오며, 여기서 내용을 작성하고 저장을 하면 cecret_test.yml이 암호화되어 저장된다.

 

* ansible-vault create시 압호 입력하지 않고 파일로 만들어서 지정하는 옵션

- 옵션 : --vault-password-file=파일명과경로

- 예시 : ansible-cault create --vault-password-file=secret.txt /home/jason/ansible/anspw secret_test.yml

- 이 파일은 파일 권한과 여러가지 방식으로 아주 조심히 다뤄야 한다.

 

* vi 에디터가 아닌 다른 에디터를 사용하기

- 구문 : export EDITOR=에디터명 

- 예시 : export EDITOR=nano (nano 에디터를 쓰는 경우)

- 이 방법은 임시 방법이며, 영구적인 방법은 리눅스 환경변수 관련 내용을 참조한다.

 

 

2. ansible vault로 암호화된 파일을 해독하여 내용 보기

 

구문 : ansible-vault view 파일명

예시 : ansible-vault view secret_test.yml

 

- 만약, 암호화된 파일을 그냥 에디터로 열어보면 아래와 같이 암호화된 모습을 확인할 수 있다.

 

3. 암호화된 파일 편집하기

 

구문 : ansible-vault edit 파일명

예시 : ansible-vault edit secret_test.yml

 

- edit 명령은 파일을 항상 다시 작성한다. 따라서 변경할때만 사용해야 한다.

- 이게 왜 문제냐면, 버전제어 프로그램 (git 등)을 쓸 때 파일이 새로 생성되므로 관련해서 특이사항이 있을 수도 있다. 따라서 내용을 볼 때는 view를 사용해야 한다.

 

 

4. 기존 파일 암호화하기

 

구문 : ansible-vault encrypt 파일명

예시 : ansible-vault encrypt test_encrypt_yml

 

- 파일명 부분에 여러개의 파일을 나열할 수도 있다.

 

* 암호화된 파일을 새로 생성하기

- 옵션 : --output=output파일명

- 예시 : ansible-vault encrypt --output=internet_encrypted.yml internet.yml

- 원본은 그대로 두고 동일한 내용의 새로운 암호화된 파일 만들 수 있다.

 

 

5. 암호 해독하기

구문 : ansible-vault decrypt 파일명

예시 : ansible-vault decrypt test_encrypt.yml

 

- 암호화된 파일을 영구적으로 해독해서 일반 파일로 만든다.

 

* 해독된 파일을 새로 생성하기

- 옵션 : --output=output파일명

- 예시 : ansible-vault decrypt secret1.yml --output=secret1-decrypted.yml

- 원본은 그대로 두고 동일한 내용의 암호해독된 새로운 파일 만들 수 있다.

 

 

6. 암호화된 파일의 암호를 변경하기

 

구문 : ansible-vault rekey 파일명

예시 : ansible-vault rekey test_encrypt.yml

 

* vault 암호파일로 암호 변경하기

- 옵션 : --new-vault-password-file=vault패스워드파일

- 예시 : ansible-vault rekey --new-vault-password-file=pwfile test_encrypt.yml

 

 

 

암호화된 yml 파일을 playbook으로 사용하기

* 직접 암호를 입력받아서 사용하기

ansible-playbook [--syntax-check] --vault-id @prompt internet_encrypted.yml
이후 패스워드를 입력함

- 이 구문은 2.5부터 사용하는 최신 구문이며, 2.4 이하 버전에서는 (ansible-playbook --ask-vault-pass 파일명) 구문을 사용한다.

 

* 패스워드 파일을 지정해서 사용하기

ansible-playbook --vault-password-file=패스워드파일 internet_encrypted.yml

- 암호가 들어있는 패스워드 파일은 일반 텍스트 파일이므로 파일권한과 여러 다른 보안수단으로 보호해야 한다.

- ANSIBLE_VAULT_PASSWORD_FILE 환경변수를 사용하여 암호 파일의 기본 위치를 지정할 수 있다.

 

 

 

 

변수 파일 관리 권장 사례

이전 9장에서, 변수를 넣는 여러가지 방법을 배웠는데, 그 중 변수들을 별도의 파일로 보관하는 방법이 여러모로 관리의 편의성이 좋다. 또한 ansible-vault를 사용하여 중요한 변수를 포함하는 파일을 보호할수도 있기 때문에 더 권장된다.

 

일반적으로 그룹변수, 호스트변수를 관리하는데 선호되는 방식은 playbook 레벨에서 디렉토리를 생성하는 것이며, 일반적으로 group_vars 디렉토리는 호스트 그룹의 변수, host_vars는 호스트 각각의 이름과 일치하는 호스트의 변수 파일들을 포함한다. 아래와 같은 형태가 될 수 있다.

 

 

여기서 vars는 각각의 일반 변수들을 저장하는 파일이고, vault는 암호화된 변수를 저장하는 파일이 된다. 즉 관리자가 ansible-vault를 사용하여 vault 파일을 암호화할 수 있다. 

 

위에 내용까지는 인벤토리 변수로써 변수 사용에 대해 이야기했는데, 또한 플레이북 변수도 ansible-vault로 보호할수 있다. 플레이북 안에서 vars_files 지시어로 플레이북에 포함된 별도의 암호화된 파일을 배치할 수 있다. 플레이북 변수는 인벤토리 변수보다 우선시되므로 이를 유의할 것.

 

 

vault 속도 올리기

기본적으로 ansible은 python-crypto 패키지의 기능을 사용하여 암호/복호화를 수행한다. 암호화된 파일이 많을 경우 지연 시간이 발생할 수 있으며 이를 가속화하려면 아래처럼 패키지를 설치한다. 이 패키지는 암호화 레시피 및 기본 항목을 가지는 python 라이브러리를 제공한다.

yum install python-cryptography

 

 

연습문제

1. ansible vault로 변수 및 패스워드 파일 암호화

# vi pwdfile
username: ansibleuser3
password: passw0rd

# ansible-vault encrypt pwdfile

- 파일 확장자는 상관없으며, 해당 파일을 암호화한다.

 

2. 암호화된 파일을 참조하여 ansible-playbook 생성

---
- name: create user accounts using vault
  hosts: web.example.com
  become: true
  remote_user: jason
  vars_files:
    - pwdfile

  tasks:
    - name: createing user from pwdfile
      user:
        name: "{{ username }}"
        password: "{{ password | password_hash('sha512') }}"

- 여기서 password 부분을 password라는 변수로 받았는데, passord_hash('sha512') 부분을 포함하지 않으면 아래와 같이 warning이 발생한다. 이렇게 되면 작업은 완료했으나 실제로는 제대로 적용되지 않아 로그인이 되지 않는다.

 

3. 실행 및 확인

ansible-playbook --vault-id @prompt create_user_vault.yml

- 이 플레이북에서 참조하는 pwdfile이 암호화되어있기 때문에 --vault-id @prompt 구문이 포함되어야 한다.

- web.example.com 에서 아래와 같이 명령 실행하여 잘 로그인되는지 확인

 

 

 

 

 

참조도움말

ansible-playbook(1)

ansible-vault(1)

 

참조링크

 

vault ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_vault.html 

 

Using Vault in playbooks — Ansible Documentation

You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the latest Ansible documentation. The “Vault” is a featu

docs.ansible.com

변수 및 vaults ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_best_practices.html#best-practices-for-variables-and-vaults

 

Best Practices — Ansible Documentation

Here are some tips for making the most of Ansible and Ansible playbooks. You can find some example playbooks illustrating these best practices in our ansible-examples repository. (NOTE: These may not use all of the features in the latest release, but are s

docs.ansible.com

 

'Ansible' 카테고리의 다른 글

12장. 작업 제어 구현 - 핸들러  (0) 2021.02.24
11장. 작업 제어 구현 - 반복문과 조건문  (0) 2021.02.23
9장. fact 변수 관리  (0) 2021.02.20
8장. 변수 사용하기  (0) 2021.02.20
7장. ansible playbook 기본 구현  (0) 2021.02.20

ansible_facts 변수란?

아래 그림에서 PLAY 바로 아래의 TASK를 보면 Gathering Facts 라고 나와있는데, Gathering Fact부분은 playbook 실행 시 가장 먼저 실행되는 play이다. playbook에 명시되어 있지 않으며, 시스템에서 기본적으로 실행하는 play이다. 이러한 play는 setup 모듈을 사용하여 ansible_facts 값을 수집한다. 

# 참고 : ansible 2.3 버전 이상에서는 gathering facts 라고 나오나, 이전 버전에서는 setup라는 명칭으로 나온다고 한다.

 

이 ansible_facts 변수에는 해당 ansible client의 여러가지 정보들을 수집한 데이터가 저장된다. 예를들어 다음과 같은 내용들을 수집한다.

 

- 호스트명

- 커널버전

- 네트워크 인터페이스

- 아이피주소

- 운영체제버전

- 여러 환경변수

- 씨피유개수

- 사용가능한 메모리

- 사용가능한 디스크공간

등등..

 

ansible_facts는 ansible client의 상태를 확인하고 상태에 따라 수행할 조치를 결정하는 편리한 방법이다. 다음과 같은 예시가 있다.

- facts에 저장되는 커널버전 값을 참조하여 패키지 업데이트 시 조건부 작업을 실행

- facts에 저장되는 메모리 정보 값을 참조하여 메모리 크기 MYSQL 구성파일을 유동적으로 설정

- facts에 저장되는 ipv4 주소를 가지고 특정 네트워크 설정

 

 

facts 값을 직접 확인하기

수집된 fact 값은 ansible_facts 라는 변수에 저장되며, debug 모듈을 사용해 ansible_facts 변수 값을 출력할 수 있다.

- name: fact dump
  hosts: web1.example.com
  tasks:
    - name: print all facts
      debug:
        var: ansible_facts

 

이런식으로 엄청 길게 나온다. 상당히 많은 값이 나오는 것이다. 이 값의 형태는 json 형태이며 hash/dictionary 형식으로 표시한다. 파이썬에서 사용하는 변수 참조방식으로 팩트의 특정 값을 찾을 수 있다. 아래는 데이터를 찾는 몇가지 예시이다.

 

* ansible_facts 변수에서 특정 값을 추출하기

짧은 호스트이름

변수명
ansible_facts['hostname']

결과

   "ansible_facts": {

        "hostname": "ansible-client1",

정규화된 도메인 이름

변수명
ansible_facts['fqdn']

결과

   "ansible_facts": {

        "fqdn": "web1.example.com",

기본 ipv4 주소

변수명
ansible_facts['default_ipv4']['address']

결과

   "ansible_facts": {

        "default_ipv4": {

            "address": "192.168.1.101",

            "alias": "enp0s3",

            "broadcast": "192.168.1.255",

            "gateway": "192.168.1.1",

            "interface": "enp0s3",

            "macaddress": "08:00:27:71:c4:78",

            "mtu": 1500,

            "netmask": "255.255.255.0",

            "network": "192.168.1.0",

            "type": "ether"

        },

모든 네트워크 인터페이스의 이름 목록

변수명
ansible_facts['interfaces']

결과

  "ansible_facts": {

        "interfaces": [

            "lo",

            "enp0s3",

            "enp0s8"

        ],

/dev/sda1 디스크 파티션의 크기

변수명
ansible_facts['devices']['sda']['partitions']['sda1']['size']

결과

  "ansible_facts": {

        "devices": {

            "sda": {

                "holders": [],

                "host": "",

                "links": {

                    "ids": [

                        "ata-VBOX_HARDDISK_VBc94d3991-95399480"

                    ],

                    "labels": [],

                    "masters": [],

                    "uuids": []

                },

                "model": "VBOX HARDDISK",

                "partitions": {

                    "sda1": {

                        "holders": [],

                        "links": {

                            "ids": [

                                "ata-VBOX_HARDDISK_VBc94d3991-95399480-part1"

                            ],

                            "labels": [],

                            "masters": [],

                            "uuids": [

                                "61BC-330E"

                            ]

                        },

                        "sectors": "409600",

                        "sectorsize": 512,

                        "size": "200.00 MB",

                        "start": "2048",

                        "uuid": "61BC-330E"

                    },

dns 서버목록

변수명
ansible_facts['dns']['nameservers']

결과

  "ansible_facts": {

        "dns": {

            "nameservers": [

                "192.168.1.1"

            ]

        },

현재 실행되고 있는 커널의 버전

변수명
ansible_facts['kernel']

결과

  "ansible_facts": {

        "kernel": "3.10.0-957.el7.x86_64",

변수명을 보면 대괄호 형식인데, 점 방식으로도 사용할 수 있다. 아래는 서로 동일한 방식이다. 하지만 대괄호 방식이 권장된다.

ansible_facts['dns']['nameservers']  =  ansible_facts.dns.nameservers

 

 

* 실제로 사용하는 예시

- name: fact dump
  hosts: web1.example.com
  tasks:
    - name: print all facts
      debug:
        msg: "{{ ansible_facts['devices']['sda']['partitions']['sda1']['size'] }}"

 

ansible 2.5 이전 버전에서 ansible_fact 변수 표기방식 차이

- ansible 2.5 이전에는 팩트가 "ansible_첫번째항목[두번째항목][세번째...] " 이런식의 구조였다.

- 아래와 같이 이전방식과 최신방식에 차이가 있는 것을 확인할 수 있다.  

내용

ansible_fact 방식 (최신)

이전팩트변수 방식

짧은 호스트이름

ansible_facts['hostname']

ansible_hostname

정규화된 도메인 이름

ansible_facts['fqdn']

ansibles_fqdn

기본 ipv4 주소

ansible_facts['default_ipv4']['address']

ansible_default_ipv4['address']

모든 네트워크 인터페이스의 이름 목록

ansible_facts['interfaces']

ansible_interfaces

/dev/sda1 디스크 파티션의 크기

ansible_facts['devices']['sda']['partitions']['sda1']['size']

ansible_devices['sda']['partitions']['sda1']['size']

dns 서버목록

ansible_facts['dns']['nameservers']

ansible_dns['nameservers']

현재 실행되고 있는 커널의 버전

ansible_facts['kernel']

ansible_kernel

- 현재 최신 ansible은 이전 팩트변수 명명 방식도 인지한다. 

- ansible.cfg 의 [default] 부분에 inject_facts_as_vars 매개변수를 false로 하면, 이전 명명시스템을 비활성화할 수 있다. default 값은 true 이다.

- 향후 ansible 버전이 점점 올라가면, 아마 inject_facts_as_vars 매개변수가 변수가 default로 false가 되어 이전 팩트변수방식을 쓰지 않게 될 것이다.

- 이전 방식을 보려면, 다음 명령으로 볼 수 있다. 이 방식은 보통 단순히 ad-hoc으로 팩트정보를 보고싶을 때 쓴다.

# ansible 호스트명 -m setup

- 이 명령은 playbook에서 수집하는 ansible_facts 의 변수 내용과 동일하다.

 

# 참고 : 간단하게 ansible client의 정보들을 보기 예시

Display only facts about certain interfaces.

- ansible all -m setup -a 'filter=ansible_eth[0-2]'

Restrict additional gathered facts to network and virtual (includes default minimum facts)

- ansible all -m setup -a 'gather_subset=network,virtual'

Collect only network and virtual (excludes default minimum facts)

- ansible all -m setup -a 'gather_subset=!all,!any,network,virtual'

Do not call puppet facter or ohai even if present.

- ansible all -m setup -a 'gather_subset=!facter,!ohai'

Only collect the default minimum amount of facts:

- ansible all -m setup -a 'gather_subset=!all'

Collect no facts, even the default minimum subset of facts:

- ansible all -m setup -a 'gather_subset=!all,!min'

Display facts from Windows hosts with custom facts stored in C(C:\custom_facts).

- ansible windows -m setup -a "fact_path='c:\custom_facts'"

 

한마디로, ansible 서버명 -m setup 의 결과를 원하는대로 필터해서 볼 줄 알면 된다. 그리고 각 키워드를 정확히 맞추기 어려우므로 대충 와일드카드를 사용해서 어떻게든 확인해 볼 수도 있다. 대충 아래와 같은 방식이다.

[student@workstation test]$ ansible servera -m setup -a 'filter=*version*'
servera | SUCCESS => {
    "ansible_facts": {
        "ansible_bios_version": "0.5.1", 
        "ansible_distribution_major_version": "7", 
        "ansible_distribution_version": "7.6", 
        "ansible_product_version": "RHEL 7.0.0 PC (i440FX + PIIX, 1996)", 
        "ansible_python_version": "2.7.5"
    }, 
    "changed": false
}



[student@workstation test]$ ansible servera -m setup -a 'filter=*eth0*'
servera | SUCCESS => {
    "ansible_facts": {
        "ansible_eth0": {
            "active": true, 
            "device": "eth0", 
            "features": {
                "busy_poll": "off [fixed]", 
                "fcoe_mtu": "off [fixed]", 
                "generic_receive_offload": "on", 
                "generic_segmentation_offload": "on", 
                "highdma": "on [fixed]", 
                "hw_tc_offload": "off [fixed]", 
                "l2_fwd_offload": "off [fixed]", 
                "large_receive_offload": "off [fixed]", 
                "loopback": "off [fixed]", 
                "netns_local": "off [fixed]", 
                "ntuple_filters": "off [fixed]", 
                "receive_hashing": "off [fixed]", 
                "rx_all": "off [fixed]", 
                "rx_checksumming": "on [fixed]", 
....
...
..

 

 

 

facts 수집을 하지 않도록 하기

때때로 플레이에 팩트를 수집하지 않길 바랄 수 있다. 관리 호스트에서 플레이 속도를 높이거나, 플레이로 인한 로드를 줄이기 위해서이다. 팩트수집을 비활성화하려면, 플레이북에 gather_facts: no 로 하면 된다.

---
- name: this play gethers no facts automatically
  hosts: all
  gather_facts: no

이렇게 no로 해놓고 플레이북에 setup 모듈을 넣으면 또 팩트수집을 할 수 있다. 이 때는 일반 모듈처럼, tasks 밑에 setup 모듈을 놓으면 된다. 자세한 사항은 doc문서를 참고하자. 

 

 

ansible_facts의 값을 사용자 정의하기

유저가 필요에 따라 ansible_facts의 결과에 원하는 값을 넣을 수 있다. 이 작업은 각 ansible client에 정의해야 하며, 결과는 관리 호스트에서 setup 모듈이 실행될 때 수집되는 표준 ansible_facts 값으로 통합된다. 이렇게 하면 ansible client에서 play의 동작을 조정하는데 사용할 수 있는 임의의 변수를 ansible에 제공할 수 있다. 

 

* 사용자 지정 팩트 설정 방식

- ansible client의 /etc/ansible/facts.d 라는 디렉토리에 사용자 정의 facts 값이 저장된 파일을 배치한다.

- 이 디렉토리는 기본적으로 없을 것이므로 직접 만들어야 한다.

- facts값이 저장된 파일은 확장자가 .fact 이다. 이렇게 맞춰야만 사용할 수 있다.

- 2가지 포맷, ini / json 방식으로 특정 파일에 정의할 수 있다. yaml은 사용할 수 없다.

 

* 사용 예시

 

1. web.example.com 서버에 아래와 같이 두가지 방식으로 파일을 작성한다. (ini, json 사용을 보여주기 위함임)

2. 각 파일의 내용은 다음과 같다. (둘다 동일한 내용이며, 형식만 다를 뿐이다)

 

3. ansible host에서 아래와 같이 playbook을 작성하고 실행한다.

---
- name: fact dump custom
  hosts: web.example.com
  tasks:
    - name: print all facts
      debug:
        var: ansible_facts

ansible_local 밑에 위에 명시한 2가지 방식의 사용자 정의 변수가 적용된 것을 확인할 수 있다.

 

 

* 사용자 정의 ansible_facts 변수 참조하기

사용자 정의 ansible_facts 변수는, setup 모듈에 의해 ansible_facts 이하의 ansible_local이라는 변수에 저장된다. 그 아래는 팩트를 정의한 파일명에 따라 구성된다. 다음과 같은 방식으로 변수를 참조하게 될 것이다. 이렇게 facts에 사용자 정의 값을 넣었으면, 일반 facts 변수 사용하듯이 사용할 수 있다.

 

ansible_facts['ansible_local']['custom_web_ini']['users']['user1']

 

playbook 구문

---
- name: fact dump custom
  hosts: web.example.com
  tasks:
    - name: print all facts
      debug:
        msg: "{{ansible_facts['ansible_local']['custom_web_ini']['users']['user1']}}"

결과

 

 

매직변수

일부 변수는 팩트가 아니거나 setup 모듈을 통해 구성되지 않지만, ansible에 의해 자동으로 설정된다. 정의하거나 선언하는 변수가 아니다. 이것을 매직변수라고 한다. 이러한 매직 변수는 특정 관리 호스트에 고유한 정보를 얻는 데 유용할 수 있다.

 

* 유용한 4가지 매직변수

hostvars

인벤토리에 정의된 ansible client의 변수가 포함되며, 다른 ansible client 변수에 대한 값을 가져오는데 사용한다. 해당 ansible client에 대해 facts 변수가 아직 수집되지 않은 경우 해당 ansible client의 facts 값은 포함되지 않는다. (hostvars안에 아래 group_names, groups, inventory_hostname 모두 포함되어있다.)

group_names

현재 ansible client가 속한 모든 그룹을 나열한다.

groups

인벤토리의 모든 그룹 및 호스트를 나열한다.

inventory_hostname

인벤토리에 구성된 현재 ansible client의 호스트 이름이 포함된다. 다양한 이유로 팩트에서 보고하는 호스트명과 다를 수 있다.

이밖에도 많은 매직변수가 있다. 자세한 내용은 아래를 참고한다.

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

 

Using Variables — Ansible Documentation

Docs » User Guide » Working With Playbooks » Using Variables You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version.

docs.ansible.com

 

* 매직변수 직접 확인하기

ansible web.example.com -m debug -a "var=hostvars['localhost']"

- ['localhost'] 부분을 빼면, 인벤토리 안에 있는 모든 호스트들의 데이터도 싹 긁어온다.

 

 

 

연습문제

- ansible 호스트에서 .fact 파일을 만들고 그 파일을 ansible client에게 배포한다.

- 배포된 그 파일의 내용을 기반으로 변수를 참조하여 playbook을 만든다.

 

1. ansible 호스트에서 fact 파일 만들기

vi /tmp/custom_ini.fact

[packages]
web_package = httpd
db_package = mariadb-server

[users]
user1 = joe
user2 = jane

 

2. 만든 fact 파일을 원하는 클라이언트에 배포하기

vi create_fact.yml
---
- name: install remote facts
  hosts: web.example.com
  vars:
    remote_dir: /etc/ansible/facts.d
    facts_file: /tmp/custom_ini.fact

  tasks:
    - name: create the remote directory
      file:
        state: directory
        recurse: yes
        path: "{{ remote_dir }}"
    - name: install the new facts
      copy:
        src: "{{ facts_file }}"
        dest: "{{ remote_dir }}"

3. web.example.com 의 /etc/ansible/facts.d 에 들어가서 내용 확인

- custom_ini.fact가 있는것을 확인할 수 있다.

4. 생성한 사용자 정의 팩트변수를 가지고 설치 작업을 해보자.

---
- name: install the packages
  hosts: web.example.com

  tasks:
    - name: install packages
      yum:
        name: "{{ ansible_facts.ansible_local.custom_ini.packages.web_package }}"
        state: present

    - name: start packages
      service:
        name: httpd
        state: started

5. web.example.com 에서 확인

- 처음엔 없었는데 playbook 실행 후에는 이렇게 변경된 것을 알 수 있다.

 

 

 

참고링크

 

설정 - 원격 호스트에 대한 팩트 수집 ansible 설명서

https://docs.ansible.com/ansible/2.7/modules/setup_module.html 

 

setup – Gathers facts about remote hosts — Ansible Documentation

Docs » setup – Gathers facts about remote hosts You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the lates

docs.ansible.com

로컬팩트(fact.d) 변수 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html#local-facts-facts-d 

 

Using Variables — Ansible Documentation

Docs » User Guide » Working With Playbooks » Using Variables You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version.

docs.ansible.com

 

'Ansible' 카테고리의 다른 글

11장. 작업 제어 구현 - 반복문과 조건문  (0) 2021.02.23
10장. ansible vault  (0) 2021.02.23
8장. 변수 사용하기  (0) 2021.02.20
7장. ansible playbook 기본 구현  (0) 2021.02.20
부록1 - 자주 사용되는 모듈들  (0) 2021.02.19

변수의 기본 개념

ansible에서는 ansible project 전체에서 재사용할 수 있는 값을 저장하기 위해 변수를 사용할 수 있다. playbook에서는 프로그래밍 언어처럼 변수의 타입을 지정하지는 않는다. 

 

* 변수의 범위

- 전역 범위 : 명령줄(-e 옵션) 또는 ansible 구성에서 설정한 변수

- 플레이 범위 : 플레이 및 관련 구조에서 설정한 변수

- 호스트 범위 : 인벤토리, 팩트수집 또는 등록된 작업별로 호스트 그룹 및 개별 호스트에서 설정한 변수

우선순위는, 명령줄변수(전역) > 플레이북변수(플레이) > 인벤토리변수(호스트) 이다. 명령줄변수가 최우선.

 

* 변수로 사용 가능한 값 (예시)

- 사용자

- 패키지명

- 서비스

- 제거할 파일

- 인터넷에서 검색할 아카이브 등

 

* 변수 규칙

- 여러가지가 있지만 가장 필수적인 규칙만 설명한다.

- 문자로 시작해야 한다.

- 문자, 숫자, 밑줄(언더바) 만 사용 가능하다. 당연히 공백 안됨.

 

 

 

 

각 범위의 따른 변수 정의하기

변수 정의 방법은 총 4가지 방식이다.

- 명령줄에서 변수 정의하기

- 플레이북에서 변수 정의하기

- 인벤토리에서 변수 정의하기

- 디렉토리에서 변수 정의하기

 

* 명령줄에서 변수 정의하기

- ansible 명령 (애드혹), 그리고 ansible-playbook 명령 모두 -e 옵션을 사용하여 변수를 정의할 수 있다.

ansible-playbook main.yml -e "package=apache"

 

* 플레이북에서 변수 정의하기

- 방식1 : 플레이북 내부에 정의 : vars 라는 구문 아래에 변수를 (key:value) 형식으로 배치한다.

- name: variable
  hosts: all
  vars:
    user: joe
    home: /home/joe

- 방식2 : 외부파일에 정의하고 플레이북에 해당 외부파일을 참조

- name: variable
  hosts: all
  vars_files:
    - vars/users.yml

이 users.yml 에는 아래와 같이 되어있다.

user: joe
home: /home/joe

 

# 참고 : 변수를 파일로 참조하는것과 직접 입력하는 것 비교

vars_files로 변수 파일을 삽입하면 거기에 있는 변수 리스트들이 적용된것처럼 나오기 때문에, 다음과 같이 이해될 수 있다.

 

변수 파일을 삽입한 경우 (변수를 직접 입력한 경우와 결과는 동일하다)

locker.yml
pw_developer: Imadev
pw_manager: Imamgr
user_list.yml
users:
 - name: node1
   job: developers
 - name: node2
   job: developers
 - name: node3
   job: manager
- hosts: all
  vars_files:
   - locker.yml
   - user_list.yml

 

변수를 직접 입력한 경우 (변수 파일을 삽입한 경우와 결과는 동일하다)

vars:
  pw_developer: Imadev
  pw_manager: Imamgr
  users:
    - name: node1
       job: developers
    - name: node2
       job: developers
    - name: node3
       job: manager

 

따라서 변수를 참조할 때는, "{{ pw_developer }}" 이렇게 하면 결과는 Imadev일 것이고, "{{ users }}" 이렇게 하면 아래 모두가 결과가 된다.

    - name: node1

       job: developers

    - name: node2

       job: developers

    - name: node3

       job: manager

 

 

* 인벤토리에서 변수 정의하기

인벤토리 파일 안에는 각 호스트 또는 호스트를 모은 그룹이 명시되는데, 여기 나온 호스트나 그룹에 대해 변수를 지정할 수 있다. 또한 참고로 인벤토리 변수끼리 우선순위를 정할 때 호스트 변수가 그룹 변수보다 우선된다. 

 

이 방법은 인벤토리 파일을 작업하기 어렵게 만들고, 같은 파일에서 호스트와 변수에 대한 정보가 합쳐지고 사용되지 않는 구문을 사용하는 몇 가지 단점이 있습니다. 권장하는 방법은 host_vars, group_vars 디렉토리를 만들어서 그룹변수와 호스트변수를 정의한 파일들을 넣는 것이다.

 

1. 특정 호스트 하나에 정의하기

[servers]
demo.example.com     ansible_user=joe

이런식으로 하면, demo.example.com 에서는 ansible_user가 joe가 된다.

 

 

2. 특정 호스트그룹에 정의하기 (:vars 를 사용)

[servers]
demo1.example.com
demo2.example.com

[servers:vars]
user=joe

 

3. 호스트 그룹을 모은 그룹에 정의하기

[servers1]
demo1.example.com
demo2.example.com

[servers2]
test1.example.com
test2.example.com

[allservers:children]
servers1
servers2

[allservers:vars]
user=joe

 

* 인벤토리에 맞춰 host_vars, group_vars 디렉토리를 만들어 변수 정의하기

이 방법은 인벤토리에 정의한 값을 바탕으로 같은 프로젝트 디렉토리 안에 추가 디렉토리를 만들어 변수파일을 지정하는 방식이다. 아래 예시를 참고한다. host_vars, group_vars는 정의된 이름이므로 정확히 이 이름을 가진 디렉토리를 생성해야 한다.

 

인벤토리 파일

[datacenter1]

demo1.example.com

demo2.example.com

[datacenter2]

demo3.example.com

demo4.example.com

[datacenters:children]

datacenter1

datacenter2

 

해당 인벤토리를 가진 프로젝트의 디렉토리 구조

(datacenters1, datacenters2 각각 s가 빠져야 한다 오타인듯)

 

이렇게 인벤토리의 그룹과 호스트명을 바탕으로 위와 같이 각각의 그룹/호스트 이름으로 파일을 만든다.  만약 datacenters에 대한 변수를 넣고 싶으면, datacenters 파일에 변수를 명시한다. 예를들어 다음과 같다.

package: httpd
user: uktae

이렇게 하면, datacenters에 포함된 datacenter1, datacenter2 각각에도 위의 변수가 적용된다. 이 말은, 각각 demo1~4.example.com 에도 적용된다는 뜻이다. 만약 단일 호스트 demo1.example.com 에다 변수를 넣고 싶으면 demo1.example.com 파일에 위와 동일하게 변수를 지정하면 된다.

 

 

플레이북에서 변수 사용하기

- 정의된 변수는 사용할 때, {{  }} 대괄호 두개 사이에 놓는다.

- 참고로, 키/밸류형태에서 밸류값에 변수를 첫번째로  때는, " "  감싸줘야한다고 한다. 첫번째만 그렇다.  변수가 뒤에 있으면 안써도 된다. (대체 왜지?)

- name: variable
  hosts: all
  vars:
    user: joe
    home: /home/joe
  tasks:
    - name: creates the user {{ user }}
      user:
        name: "{{ user }}"

 

* 변수가 적용된 추가예제

- 아래와 같이 vars에 정의된 변수들은 tasks에서 같은 파란색 음영 부분으로 참조된다.

 

 

여러 변수 할당 시 배열 사용하기

같은 요소 (패키지, 서비스, 사용자 등)와 관련된 구성 데이터를 여러 변수에 할당하는 대신, 배열을 사용할 수 있다. 이렇게 하면 배열을 검색하여 변수를 지정할 수 있고 좀 더 명확하고 간편하게 변수 참조할 수 있다.

 

* 배열 변수 만들기

일반적으로 변수는 아래와 같이 지정할 수 있을 것이다. 하지만 이 경우 변수들이 좀 난잡하다.

user1_first_name: bob
user1_last_name: jones
user1_home_dir: /users/bjones
user2_first_name: anne
user2_last_name: cook
user2_home_dir: /users/acook

이 경우 users 라는 배열로 아래와 같이 다시 변수를 작성할 수 있다.

users:
  bjones:
    first_name: bob
    last_name: jones
    home_dir: /users/bjones
  acook:
    first_name: anne
    last_name: cook
    home_dir: /users/acook

 

* 배열 변수 참조하기

- bob은 다음 변수로 표현된다 : users.bjones.first_name   또는   users['bjones']['first_name']

- /users/acook은 다음 변수로 표현된다 : users.acook.home_dir   또는   users['acook']['home_dir']

- 점 방식, 대괄호 방식 모두 파이썬에서 볼 수 있는 변수 참조 방식이다.

 

* 유의사항

- key 이름을 넣을 때, discard, copy, add 같은 "키워드"를 쓰지 말 것. 이러한 키워드를 점 방식으로 사용하면 오류가 날 수 있다.

- 점 방식과 대괄호 방식을 섞어 쓰지 말 것. 일관되게 쓰는 것이 레드햇 권고사항이다.

- 일반적으로 대괄호 표기법이 충돌과 오류가 발생할 가능성이 낮다.

 

 

register 키워드

register 키워드는 특정 변수를 만들고 그 변수에 해당 task의 결과를 저장한다. 이 결과는, 그냥 내가 그 명령어를 쳤을때 볼 수 있는 결과 "자체"를 보여준다. 이러한 값은 debugging 또는 명령 출력을 기반으로한 특정 구성과 같은 다른 작업을 수행할 때 사용할 수 있다.

 

아래 구문은 이미 설치된 httpd를 uninstall 하는 것이다. (참고 : debug 모듈에 대한 상세 정보는 이후에 자세히 전달한다.)

---
- name: play to uninstall web server
  hosts: web.example.com
  tasks:
    - name: latest httpd version uninstalled
      yum:
        name: httpd
        state: absent
      register: uninstall_result
    - name: debug install_result
      debug:
        var: uninstall_result

 

아래 결과를 보면, yum 명령으로 지웠을때의 결과 자체가 그대로 텍스트로 나오는 것을 확인할 수 있다. rester 키워드는 이러한 결과 자체를 보여준다.

 

 

 

 

주요 링크

 

인벤토리 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/intro_inventory.html 

 

Working with Inventory — Ansible Documentation

Docs » User Guide » Working with Inventory You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the latest Ansi

docs.ansible.com

변수 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html

 

Working with Inventory — Ansible Documentation

Docs » User Guide » Working with Inventory You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the latest Ansi

docs.ansible.com

변수 우선 순위: 변수를 어디에 두어야 합니까?

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

 

Working with Inventory — Ansible Documentation

Docs » User Guide » Working with Inventory You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the latest Ansi

docs.ansible.com

 

'Ansible' 카테고리의 다른 글

10장. ansible vault  (0) 2021.02.23
9장. fact 변수 관리  (0) 2021.02.20
7장. ansible playbook 기본 구현  (0) 2021.02.20
부록1 - 자주 사용되는 모듈들  (0) 2021.02.19
6장. ansible에서 모듈 사용하기  (0) 2021.02.19

+ Recent posts