가변 개수의 Hostvar를 통한 Ansible 루프

가변 개수의 Hostvar를 통한 Ansible 루프

사용자가 입력한 호스트 목록에서 호스트 이름과 IP 주소를 가져와 해당 정보를 중앙 서버로 보내려고 합니다. 제가 겪고 있는 주요 문제는 호스트 수가 상당히 다양할 수 있다는 것입니다. 예를 들어 첫 번째 실행에서 사용자는 호스트 이름 1개를 입력하고 두 번째 실행에서는 30을 입력하고 다음 실행에서는 5를 입력할 수 있습니다. 사용자가 호스트를 1개 또는 100개 입력하는지 여부에 관계없이 단일 플레이북을 사용할 수 있기를 원합니다.

Ansible Tower 템플릿이 실행될 때 "추가 변수" 프롬프트를 통해 호스트 이름이 수집됩니다.

client_hosts: 'host1,host2'

그런 다음 플레이북에서 참조됩니다.

- name: Gather client information
  hosts: 
  - "{{ client_hosts | default(omit) }}"  
  tasks:    
    - name: Grab client hostname
      shell: cat /etc/hostname
      register: client_hostname

    - name: Grab client IP address
      shell: hostname -i | sed -n '1 p'
      register: client_ip

플레이북을 더 자세히 살펴보면 해당 IP + 호스트 이름을 특정 중앙 서버의 파일에 추가하고 싶습니다(서버 호스트 이름은 변경되지 않음).

- name: Update server
  hosts: central.server  
  tasks:  
    - name: Update client host list
      lineinfile:
        path: /path/to/file
        line: "{{ hostvars['client_hosts']['client_ip'] }} - {{ hostvars['client_hosts']['client_hostname'] }}"

위의 내용은 단일 호스트에 대해 잘 작동하지만 둘 이상의 호스트가 지정되면(예: client_hostname[1,2,*]?) 변수 등록을 통해 어떻게 반복하고 어떻게 해야 할지 모를 때 해당 값으로 서버를 업데이트합니다. 많은 호스트가 미리 입력될 예정인가요?

답변1

이 사용 사례는 세 부분으로 구성됩니다. 1) 재고 관리, 2) 수집클라이언트_호스트 이름그리고클라이언트_IP, 3) 중앙서버에 보고합니다.

1. 재고 관리

재고를 관리하고 수집하는 방법에는 다양한 옵션이 있습니다.클라이언트_호스트 이름그리고클라이언트_IP. 예를 들어호스트 범위 추가. host001, hosts002, ..., host999​예를 들어 아래 인벤토리에 다음을 추가하세요.중앙 서버, 단순화를 위한 localhost 및 그룹의 100개 호스트시험

shell> cat inventory/01-hosts 
central_server ansible_host=localhost

[test]
host[001:100]

[test:vars]
ansible_connection=ssh
ansible_user=admin
ansible_become=yes
ansible_become_user=root
ansible_become_method=sudo
ansible_python_interpreter=/usr/local/bin/python3.8

인벤토리를 간단히 테스트해 보세요.

- hosts: all
  gather_facts: false
  tasks:
    - debug:
        var: ansible_play_hosts|length
      run_once: true

요약하다

  ansible_play_hosts|length: '101'

전체 인벤토리를 표시하려면 아래 명령을 실행하십시오.

shell> ansible-inventory -i inventory --list --yaml

그런 다음 호스트를 선택하는 방법에 대한 다양한 옵션이 있습니다. 보다패턴: 호스트 및 그룹 타겟팅. 예를 들어,한계특정 호스트 또는 그룹에 대한 인벤토리. 아래의 간단한 플레이북으로 테스트해 보세요.

shell> cat pb1.yml
- hosts: all
  gather_facts: false
  tasks:
    - debug:
        var: inventory_hostname

주다

shell> ansible-playbook -i inventory pb1.yml -l host001,host002

PLAY [all] ***********************************************************************************

TASK [debug] *********************************************************************************
ok: [host001] => 
  inventory_hostname: host001
ok: [host002] => 
  inventory_hostname: host002

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

인벤토리 플러그인 사용구성된인벤토리를 더 큰 호스트 그룹으로 제한하려는 경우. 보다

shell> ansible-doc -t inventory constructed

예를 들어, 추가 변수개수_호스트아래 예에서는 그룹을 생성하는 데 사용됩니다.나의 그룹이 변수의 값으로 제한되는 호스트로 구성됩니다.

shell> cat inventory/02-constructed.yml
plugin: constructed
strict: true
use_extra_vars: true
compose:
  my_group_count: count_hosts|default(0)
groups:
  my_group: inventory_hostname[-2:]|int < my_group_count|int

테스트해 보세요

shell> ansible-playbook -i inventory pb.yml -e count_hosts=10 -l my_group

PLAY [all] ***********************************************************************************

TASK [debug] *********************************************************************************
ok: [host001] => 
  ansible_play_hosts|length: '11'

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

전체 인벤토리를 표시하려면 아래 명령을 실행하십시오.

shell> ansible-inventory -i inventory -e count_hosts=10 --list --yaml

의 도움으로구성된플러그인을 사용하면 복잡한 조건을 만들 수 있습니다. 예를 들어 호스트를 특정 간격으로 제한하고 그룹을 만듭니다.내_그룹2

shell> cat inventory/02-constructed.yml
plugin: constructed
strict: true
use_extra_vars: true
compose:
  my_group_count: count_hosts|default(0)
  my_group_start: start_hosts|default(0)
  my_group_stop: stop_hosts|default(0)
groups:
  my_group1: inventory_hostname[-2:]|int < my_group_count|int
  my_group2: inventory_hostname[-2:]|int >= my_group_start|int and
             inventory_hostname[-2:]|int < my_group_stop|int

테스트해 보세요

shell> ansible-playbook -i inventory pb1.yml -e start_hosts=10 -e stop_hosts=15 -l my_group2

PLAY [all] ***********************************************************************************

TASK [debug] *********************************************************************************
ok: [host010] => 
  inventory_hostname: host010
ok: [host011] => 
  inventory_hostname: host011
ok: [host012] => 
  inventory_hostname: host012
ok: [host013] => 
  inventory_hostname: host013
ok: [host014] => 
  inventory_hostname: host014

...

2. 수집클라이언트_호스트 이름그리고클라이언트_IP

모듈 중 하나를 사용할 수 있습니다설정아니면 스스로 사실을 수집하세요. 휴대성 때문에설정선호되어야합니다.

모듈 보기설정원격 호스트에 대한 정보를 수집하는 방법에 대해 설명합니다. 예를 들어, 아래 플레이북은 다음에 대한 사실을 수집합니다.기계그리고회로망그리고 변수를 생성합니다클라이언트_호스트 이름그리고클라이언트_IP

shell> cat pb2.yml
- hosts: all
  gather_facts: false
    
  tasks:

    - setup:
        gather_subset:
          - machine
          - network

    - set_fact:
        client_hostname: "{{ ansible_hostname }}"
    - debug:
        var: client_hostname

    - debug:
        var: ansible_default_ipv4
    - debug:
        var: ansible_all_ipv4_addresses

    - set_fact:
        client_ip: "{{ ansible_all_ipv4_addresses|last }}"
    - debug:
        var: client_ip

주다

shell> ansible-playbook -i inventory -l host011 pb2.yml

PLAY [all] ***********************************************************************************

TASK [setup] *********************************************************************************
ok: [host011]

TASK [set_fact] ******************************************************************************
ok: [host011]

TASK [debug] *********************************************************************************
ok: [host011] => 
  client_hostname: test_11

TASK [debug] *********************************************************************************
ok: [host011] => 
  ansible_default_ipv4: {}

TASK [debug] *********************************************************************************
ok: [host011] => 
  ansible_all_ipv4_addresses:
  - 10.1.0.61

TASK [set_fact] ******************************************************************************
ok: [host011]

TASK [debug] *********************************************************************************
ok: [host011] => 
  client_ip: 10.1.0.61

PLAY RECAP ***********************************************************************************
host011: ok=7    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

사실의 구조와 형식은 운영 체제에 따라 다를 수 있습니다.


사실을 직접 수집할 수 있습니다. 예를 들어 아래 플레이북은

shell> cat pb3.yml
- hosts: all
  gather_facts: false
    
  tasks:

    - name: Grab client hostname
      command: cat /etc/hostname
      register: out
    - set_fact:
        client_hostname: "{{ out.stdout }}"
    - debug:
        var: client_hostname

    - name: Grab client IP address
      shell: hostname -i | sed -n '1 p'
      register: out
    - set_fact:
        client_ip: "{{ out.stdout|split|last }}"
    - debug:
        var: client_ip

Linux에서 실행 제공

shell> ansible-playbook -i inventory -l central_server pb3.yml

PLAY [all] ***********************************************************************************

TASK [Grab client hostname] ******************************************************************
changed: [central_server]

TASK [set_fact] ******************************************************************************
ok: [central_server]

TASK [debug] *********************************************************************************
ok: [central_server] => 
  client_hostname: central_server

TASK [Grab client IP address] ****************************************************************
changed: [central_server]

TASK [set_fact] ******************************************************************************
ok: [central_server]

TASK [debug] *********************************************************************************
ok: [central_server] => 
  client_ip: 10.1.0.22

PLAY RECAP ***********************************************************************************
central_server: ok=6    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

유틸리티의 출력은 운영 체제에 따라 다를 수 있습니다.


3) 중앙서버에 보고

Jinja를 사용하여 구조를 만듭니다. 작업을 한 번 실행하고 다른 사용자에게 위임합니다.중앙 서버

shell> cat pb4.yml
- hosts: all
  gather_facts: false
    
  tasks:

    - setup:
        gather_subset:
          - machine
          - network
    - set_fact:
        client_hostname: "{{ ansible_hostname }}"
        client_ip: "{{ ansible_all_ipv4_addresses|last }}"

    - copy:
        dest: /tmp/test_host_ip.txt
        content: |
          {% for host in ansible_play_hosts %}
          {{ hostvars[host]['client_hostname'] }} - {{ hostvars[host]['client_ip'] }}
          {% endfor %}
      run_once: true
      delegate_to: central_server

주다

shell> ansible-playbook -i inventory -l host011,host013 pb4.yml

PLAY [all] ***********************************************************************************

TASK [setup] *********************************************************************************
ok: [host013]
ok: [host011]

TASK [set_fact] ******************************************************************************
ok: [host011]
ok: [host013]

TASK [copy] **********************************************************************************
changed: [host011 -> central_server(localhost)]

PLAY RECAP ***********************************************************************************
host011: ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host013: ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

플레이북이 다음 위치에 파일을 생성했습니다.중앙 서버

shell> cat /tmp/test_host_ip.txt 
test_11 - 10.1.0.61
test_13 - 10.1.0.63

모듈 사용라인 파일파일에 줄을 추가하려는 경우. 아래 플레이북은 멱등적입니다.

shell> cat pb5.yml
- hosts: all
  gather_facts: false
    
  tasks:

    - setup:
        gather_subset:
          - machine
          - network
    - set_fact:
        client_hostname: "{{ ansible_hostname }}"
        client_ip: "{{ ansible_all_ipv4_addresses|last }}"

    - lineinfile:
        path: /tmp/test_host_ip.txt
        line: |-
          {{ hostvars[item]['client_hostname'] }} - {{ hostvars[item]['client_ip'] }}
      loop: "{{ ansible_play_hosts }}"
      run_once: true
      delegate_to: central_server

동일한 호스트에서 반복적으로 실행하면 변경 사항이 없습니다.

shell> ansible-playbook -i inventory -l host011,host013 pb5.yml

PLAY [all] ***********************************************************************************

TASK [setup] *********************************************************************************
ok: [host011]
ok: [host013]

TASK [set_fact] ******************************************************************************
ok: [host011]
ok: [host013]

TASK [lineinfile] ****************************************************************************
ok: [host011 -> central_server(localhost)] => (item=host011)
ok: [host011 -> central_server(localhost)] => (item=host013)

PLAY RECAP ***********************************************************************************
host011: ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
host013: ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

플레이북이 새 호스트에서 실행되면 파일에 새 줄이 추가됩니다.


shell> ansible-playbook -i inventory -l central_server pb5.yml

PLAY [all] ***********************************************************************************

TASK [setup] *********************************************************************************
ok: [central_server]

TASK [set_fact] ******************************************************************************
ok: [central_server]

TASK [lineinfile] ****************************************************************************
changed: [central_server] => (item=central_server)

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

새 줄이 파일에 추가되었습니다.

shell> cat /tmp/test_host_ip.txt 
test_11 - 10.1.0.61
test_13 - 10.1.0.63
central_server - 10.1.0.184

답변2

플레이북에서 with_items 지시문을 사용하여 client_hosts 변수를 반복할 수 있습니다. 그런 다음 루프의 항목 변수를 사용하여 각 개별 호스트를 참조할 수 있습니다.

다음은 여러 호스트를 처리하기 위해 플레이북을 수정하는 방법의 예입니다.

- name: Gather client information
  hosts: "{{ client_hosts | default(omit) }}"  
  tasks:
    - name: Grab client hostname and IP address
      shell: |
        hostname -i | sed -n '1 p' > /tmp/client_ip
        cat /etc/hostname > /tmp/client_hostname
      register: gather_client_info
      become: true

    - name: Set client hostname and IP address as variables
      set_fact:
        client_hostname: "{{ hostvars[item]['gather_client_info'].stdout_lines[1] }}"
        client_ip: "{{ hostvars[item]['gather_client_info'].stdout_lines[0] }}"
      with_items: "{{ client_hosts | default(omit) }}"

- name: Update server
  hosts: central.server  
  tasks:
    - name: Update client host list
      lineinfile:
        path: /path/to/file
        line: "{{ client_ip }} - {{ client_hostname }}"
      with_items: "{{ client_hosts | default(omit) }}"

이 플레이북은 client_hosts 변수의 각 호스트를 반복하고 셸 모듈을 사용하여 호스트 이름과 IP 주소를 수집합니다. 그런 다음 set_fact 모듈을 사용하여 이러한 값을 변수로 설정합니다. 마지막으로 client_hosts 변수를 다시 반복하고 lineinfile 모듈을 사용하여 각 호스트의 호스트 이름과 IP 주소로 중앙 서버의 파일을 업데이트합니다.

도움이 되었기를 바랍니다.

관련 정보