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

+ Recent posts