나의 삽질 저장소!

Ansible inventory 작성하기

by softPine

Inventory

Ansible을 사용하기 앞서 Ansible로 관리하려는 노드들 즉 Managed node들에 대해서 관리하려면 Inventory 파일을 먼저 작성을 해야한다. 이 Inventory 파일을 hostfile 이라고도 불리며, ansible 실행 시 기본적으로 /etc/ansible/hosts 파일을 불러온다. 이 파일의 양식은 INI 또는  yaml 파일 형식이다. 이 기본 hosts 파일 말고 다른 hosts 파일을 불러오려면 -i 옵션을 사용하여 다른 파일을 불러오면 된다. 다음은 기본적인 inventory 파일의 형식이다.

all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        foo.example.com:
        bar.example.com:
    dbservers:
      hosts:
        one.example.com:
        two.example.com:
        three.example.com:

 

기본 그룹

Inventory 에는 all, ungrouped 라는 2가지 기본 그룹이 있다. all은 모든 호스트를 지칭한다. ungrouped는 all 그룹에 포함되지 않는 다른 모든 호스트를 말한다. 모든 호스트들은 항상 2개 이상의 그룹에 속하게 된다(all, ungrouped 또는 all과 또 다른 그룹). all, ungrouped는 항상 있지만, 암시적일 수 있어서 group_names와 같은 그룹 목록에 안보일수 있다.

 

여러 그룹에 호스트 포함하기

각 호스트를 둘 이상의 그룹에 넣을 수 있다.

all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        foo.example.com:
        bar.example.com:
    dbservers:
      hosts:
        one.example.com:
        two.example.com:
        three.example.com:
    east:
      hosts:
        foo.example.com:
        one.example.com:
        two.example.com:
    west:
      hosts:
        bar.example.com:
        three.example.com:
    prod:
      children:
        east:
    test:
      children:
        west:

또한 위 inventory 파일 처럼 그룹을 중첩하여 같은 결과값이 나오더라도 테스트 환경으로 나누는 등 그룹화를 할 수 있다.

 

호스트에 범위 추가하기

비슷한 패턴의 호스트가 많을 경우 범위를 사용해서 쉽게 Inventory 파일에 나열할 수 있다.

#--- INI File
[webservers]
www[01:50].example.com

#--- Yaml File
  webservers:
    hosts:
      www[01:50].example.com:

또한 이 범위에서 증가하는 번호의 범위를 지정할 수 있다.

#--- INI File
[webservers]
www[01:50:2].example.com

#--- Yaml File
  webservers:
    hosts:
      www[01:50:2].example.com:

숫자 말고 알파벳으로도 범위를 정의할 수 있다.

db-[a:f].example.com

 

Inventory에 변수 추가하기

Inventory의 특정 호스트 또는 그룹과 관련된 변수 값을 저장할 수 있다.

 

하나의 시스템에 변수 할당 : 호스트 변수

#--- INI File
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909

#--- Yaml File
atlanta:
  hosts:
    host1:
      http_port: 80
      maxRequestsPerChild: 808
    host2:
      http_port: 303
      maxRequestsPerChild: 909

기존 ssh의 22번 포트말고 다른 포트를 사용해도 호스트 변수로 잘 작동한다. 호스트 이름 콜론의 뒤에 포트 번호를 추가하면 된다.

badwolf.example.com:5309

또한 Connection 관련 변수는 호스트 변수로도 잘 작동한다.

[targets]

localhost              ansible_connection=local
other1.example.com     ansible_connection=ssh        ansible_user=myuser
other2.example.com     ansible_connection=ssh        ansible_user=myotheruser
ssh 구성파일에 비표준 ssh 포트(22번이 아닌)를 설정하면 oppenssh 자동으로 찾아서 연결하지만 paramiko 연결은 그렇지 않다.

 

Inventory aliases

Inventory에서 별칭을 정의할 수도 있다.

#---  INI File
jumper ansible_port=5555 ansible_host=192.0.2.50

#--- Yaml File
  hosts:
    jumper:
      ansible_port: 5555
      ansible_host: 192.0.2.50

위 예제에서 192.0.2.50의 호스트에 5555번을 사용하는 호스트에 대해서 jumper라는 별칭을 지었다. 이 호스트 연결에 대해서 여러 인벤토리 매개변수가 있는데 이 Link를 참조하면 된다.

key=value 구문을 사용하여 INI 파일 형식으로 전달하는 값들은 값이 선언되는 위치에 따라 다르게 해석된다.

- 호스트와 함께 바로 인라인으로 선언되면 INI 파일에서는 Python의 리터럴(string, number, tuple, list, dict, bool, none) 구조로 해석된다. 호스트 행은 한 행에 여러 개의 key, value 매개 변수를 허용한다. 따라서 공백이 구분 기호가 아니라 값의 일부임을 나타내는 방법이 필요하다.
- :vars 섹션에서 선언되면 INI 값은 문자열로 해석된다. var = FALSE도 'FALSE'와 같은 문자열로 만든다. 호스트 행과 달리 :vars 섹션은 행당 하나의 항목만 허용하므로 = 이후의 모든 항목은 해당 항목의 값이 되어야 한다.
- INI 인벤토리에 설정된 변수 값이 특정 유형(문자열 또는 bool)이어야 하는 경우 항상 task에서 필터를 사용하여 유형을 지정해야 한다. 변수를 사용할 때 INI Inventory에 설정된 유형에 의존하면 안된다.
- 변수의 실제 타입에 대한 혼선을 줄이기 위해 Inventory 소스에 Yaml 형식을 사용하는 것을 고려한다. Yaml Inventory 플러그인은 변수의 값 처리가 일관적이고 편하다.

기본 Inventory 파일에서 변수를 설정하는 것은 간단하다. 그러나 일반적으로 위와 같은 방법은 시스템 정책을 설명하는 변수를 정의하는 방법으로는 가장 좋은 방법은 아니다. 이에 대한 방식은 host_vars 디렉토리의 개별 파일에 변수 값을 구성하는 방법을 다음 장에서 진행한다.

 

여러 시스템에 변수 할당 : 그룹 변수

특정 그룹의 모든 호스트가 변수의 값을 공유하는 경우 해당 변수를 한번에 적용할 수 있다.

#--- INI File
[atlanta]
host1
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

#--- Yaml File
atlanta:
  hosts:
    host1:
    host2:
  vars:
    ntp_server: ntp.atlanta.example.com
    proxy: proxy.atlanta.example.com

그룹 변수는 여러 호스트에 변수를 적용하기에 편리한 방법이다. 그러나 ansible을 실행하기 전에 인벤토리 변수를 비롯한 변수를 항상 호스트 수준으로 평준화 시킨다. 호스트가 여러 그룹의 멤버인 경우 ansible은 속한 그룹에서 변수 값을 읽는다. 만약 다른 그룹의 동일한 변수에 다른 값을 할당하는 경우 ansible을 병합을 위한 내부 규칙에 따라서 사용할 값을 선택한다. 이러한 병합 과정에 대한 규칙은 다음 Link를 확인하면 된다.

 

변수 값 상속하기 : 그룹의 그룹에 대한 그룹 변수

INI의 경우 :children 접미사, Yaml의 children: 항목을 사용하여 그룹의 그룹을 만들 수 있다. 이 그룹의 그룹에 vars: 또는 :vars 를 사용하여 그룹의 그룹에 대한 그룹 변수를 적용할 수 있다.

#--- INI File
[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
atlanta
raleigh

[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2

[usa:children]
southeast
northeast
southwest
northwest

#--- Yaml File
all:
  children:
    usa:
      children:
        southeast:
          children:
            atlanta:
              hosts:
                host1:
                host2:
            raleigh:
              hosts:
                host2:
                host3:
          vars:
            some_server: foo.southeast.example.com
            halon_system_timeout: 30
            self_destruct_countdown: 60
            escape_pods: 2
        northeast:
        northwest:
        southwest:

list 또는 hash 데이터를 저장하거나 Inventory 파일과 별도로 호스트 및 그룹 관련 변수를 저장하려면 다음의 단원을 본다.

Child 그룹은 다음과 같은 몇 가지 속성이 있다.

  • 하위 그룹의 멤버인 모든 호스트는 자동으로 상위 그룹의 멤버가 된다.
  • 하위 그룹의 변수는 상위 그룹의 변수보다 우선 순위가 높다(덮어 쓴다).
  • 그룹에는 여러 부모와 자식이 있을 수 있지만 순환 관계는 없다.
  • 호스트는 여러 그룹에 속할 수 있지만 호스트의 인스턴스는 하나만 존재하며 여러 그룹의 데이터를 병합한다.

 

호스트 및 그룹 변수 구성

기본 Inventory 파일에 변수를 저장할 수 있지만 별도의 호스트 및 그룹 변수 파일을 저장하면 변수 값을 보다 쉽게 구성할 수 있다. 호스트 및 그룹 변수 파일은 Yaml 구문을 사용해야 한다. 

ansible은 Inventory 파일 또는 playbook 파일과 관련된 경로를 검색하여 호스트 및 그룹 변수 파일을 로드한다. /etc/ansible/hosts 의 inventory 파일에 'raleigh' 및 'webservers'라는 두 그룹에 속하는 'foosball'이라는 호스트가 있는 경우  해당 호스트는 다음 위치에 있는 yaml 파일의 변수를 사용한다.

/etc/ansible/group_vars/raleigh # .yml, .yaml, .json 으로 끝나는 파일 사용(아에 확장자가 없어도 된다)
/etc/ansible/group_vars/webservers
/etc/ansible/host_vars/foosball

예를 들어 IDC 별로 inventory의 호스트를 그룹화하고 각 IDC에서 자체적으로 NTP 및 DB 서버를 사용하는 경우 /etc/ansible/group_vars/raleigh 라는 파일을 생성하여 raleigh 그룹에 대한 변수를 저장할 수 있다.

---
ntp_server: acme.example.org
database_server: storage.example.org

그룹 또는 호스트의 이름을 딴 디렉토리를 만들어 사용할 수 있다. ansible은 사전 순서로 디렉토리의 모든 파일을 읽는다.

/etc/ansible/group_vars/raleigh/db_settings
/etc/ansible/group_vars/raleigh/cluster_settings

raleigh 그룹의 모든 호스트는 이러한 파일에 정의 된 변수를 사용할 수 있다. 단일 파일로 변수를 관리 시 파일의 크기가 너무 커지거나 일부 그룹 변수에서 ansible vault[각주:1]를 사용하려는 경우 유용하다.

playbook 디렉토리에 group_var/ 및 host_vars/ 디렉토리를 추가할 수 있다. ansible-playbook 명령은 기본적으로 현재 디렉토리에서 두 디렉토리를 찾는다. 다른 ansible 명령어(ansible, ansible-console 등)은 inventory 디렉토리에서 group_vars/ 및 host_vars/에서만 찾는다. 다른 명령이 playbook 디렉토리의 group_var/ 및 host_vars/ 디렉토리의 변수를 로드하려면 명령줄에 --playbook-dir 플래그 옵션을 사용해야 한다. 이때 우선순위는 playbook 디렉토리가 높기 때문에 같은 변수에 대해서는 playbook 디렉토리에 설정되어 있는 변수가 덮어쓴다.

Inventory 파일과 변수를 git에 보관하는 것은 변경사항을 추적하는 방법 중 하나이다.

 

변수가 병합되는 방법

기본적으로 변수는 실행되기 전에 특정 호스트에 대해 병합/평준화가 된다. 중복된 변수에 대한 우선순위는 다음과 같다.

  1. all group ( 다른 모든 group의 부모이기 때문)
  2. parent group
  3. child group
  4. host

기본적으로 ansible은 ASCII 순서로 동일한 상위/하위 수준의 그룹을 병합하고 마지막으로 로드 된 그룹이 이전 그룹을 덮어쓴다. 예를들면 a_group이 b_group과 병합되고 일치하는 b_group의 변수는 a_group의 변수를 덮어쓴다.

그룹 변수 ansible_group_priority 를 설정하여 동일한 수준의 그룹에 대한 병합 순서를 변경하여 동작을 변경할 수 있다(상위/하위의 순서가 해결 된 후). 숫자가 클 수록 나중에 병합되어 더 높은 우선 순위를 부여한다. 이 변수는 설정되지 않은 경우 기본값은 1이다.

a_group:
  vars:
    testvar: a
    ansible_group_priority: 10
b_group:
  vars:
    testvar: b

위 예제에서 두 그룹의 우선 순위가 같으면 결과는 testvar는 b가 되어야 하지만, ansible_group_priority 옵션으로 인해 더 높은 우선순위를 부여해 testvar는 a가 된다.

ansible_group_priority는 group_vars/ 를 로드할 때 변수가 사용되므로 group_vars/ 가 아닌 inventory 소스에서만 설정할 수 있다.

 

여러 Inventory 소스 사용

CLI에서 inventory 매개 변수를 여러개 제공하거나 ANSIBLE_INVENTORY를 구성하여 여러 inventory 소스(디렉토리, 동적 inventory 스크립트 또는 inventory 플러그인에서 지원되는 파일)를 동시에 대상으로 지정할 수 있다. 이 기능은 일반적으로 스테이징 및 프로덕션과 같은 별도의 환경에서 특정 작업을 동시에 대상으로 지정하려는 경우 유용하다.

다음과 같이 CLI 에서 두 소스를 지정한다.

ansible-playbook get_logs.yml -i staging -i production

스테이징 inventory의 [all:vars]가 myvar = 1을 정의하지만 프로덕션 inventory가 myvar = 2를 정의하는 경우 playbook은 myvar = 2로 실행된다. 만약 playbook이 -i production -i staging 으로 실행 된 경우 결과가 반전된다.

 

Inventory 소스를 디렉토리로 합치기

여러 inventory 소스와 소스 유형을 하나의 디렉토리로 만들 수 있다. 이 방법은 정적 및 동적 호스트를 하나의 인벤토리로 관리하는데 유용할 수 있다. 다음의 inventory는 inventory 플러그인 소스, 동적 inventory 스크립트 및 파일을 정적 호스트와 합친다.

inventory/
  openstack.yml          # Openstack 클라우드에서 호스트를 가져오도록 inventory 플러그인 구성
  dynamic-inventory.py   # 동적으로 추가된 호스트를 추가하는 inventory 스크립트
  static-inventory       # 정적 호스트 및 그룹
  group_vars/
    all.yml              # 모든 호스트에 대한 변수

간단하게 inventory 디렉토리를 지정할 수 있다.

ansible-playbook example.yml -i inventory

변수의 중복 또는 다른 inventory 소스에 대한 그룹 종속성이 있는 경우 inventory 소스의 병합 순서를 제어하는 것이 유용하다. inventory는 파일 이름에 따라 ASCII 순서로 병합되므로 파일에 접두사를 추가하여 결과를 제어할 수 있다.

inventory/
  01-openstack.yml          # Openstack 클라우드에서 호스트를 가져오도록 inventory 플러그인 구성
  02-dynamic-inventory.py   # 동적으로 추가된 호스트를 추가하는 inventory 스크립트
  03-static-inventory       # 정적 호스트 및 그룹
  group_vars/
    all.yml                 # 모든 호스트에 대한 변수

01-openstack.yml이 all 그룹에 대해 myvar = 1을 정의하고 02- dynamic-inventory.py가 myvar = 2를 정의하고 03-static-inventory가 myvar = 3을 정의하는 경우 playbook은 myvar = 3으로 실행된다.

inventory 플러그인 및 동적 inventory 스크립트에 대한 자세한 내용은 inventory pluginWorking with dynamic inventory를 참고한다.

  1. 암호 또는 키와 같은 중요 데이터를 playbook 또는 role의 일반 텍스트가 아닌 암호화된 파일에 보관할 수 있도록 해주는 기능 [본문으로]

블로그의 정보

나의 삽질저장소

softPine

활동하기