[번역] Ansible(2) inventory, Playbooks, Roles

rin·2020년 4월 21일
1

Document 번역

목록 보기
7/22
post-thumbnail

2020.4.20 추가

How to build your inventory

Ansible은 인벤토리라고 하는 목록 or 목록 그룹을 사용해 인프라의 여러 managed node(or host)에 대해 동시에 작동한다. 인벤토리가 정의되면 패턴을 사용해 Ansible을 실행할 호스트 또는 그룹을 선택한다.

인벤토리의 기본 위치는 /etc/ansible/hosts이다. -i <path>옵션을 사용하여 command line에서 다른 인벤토리 파일을 지정할 수 있다. 동적 인벤토리 작업에 설명된 대로 여러 인벤토리 파일을 동시에 사용하거나 동적 or 클라우드 소스 or 다른 형식(YAML, ini 등)에서 인벤토리를 가져올 수도 있다. 버전 2.4에 도입된 Ansible에는 유연하고 사용자 정의가 가능한 인벤토리 플러그인이 있다.

Inventory basics: formats, hosts, and groups

인벤토리 파일은 보유한 인벤토리 플러그인에 따라 여러 포맷 중 하나 일 수 있다. 가장 일반적인 형식은 INI 및 YAML이다. 기본 INI etc/ansible/hosts는 다음과 같다.

mail.example.com

[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

괄호 안 제목은 그룹 이름으로, 호스트를 분류하고 어느 시간에 어떤 목적으로 어떤 호스트를 제어하는지 결정하는데 사용된다.
YAML 형식의 동일한 기본 인텐토리 파일을 다음과 같다.

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:

Default groups

디폴트 그룹에는 두가지가 있다 : all, ungrouped.
all 그룹은 모든 호스트가 포함돼있다. ungrouped 그룹은 다른 그룹을 제외한 모든 호스트가 포함된다. (The ungrouped group contains all hosts that don’t have another group aside from all) 모든 호스트는 항상 2개 이상의 그룹(allungrouped or all과 또 다른 그룹)에 속한다. allungrouped이 항상 존재할지라도, 이는 암시적일 수 있으며 group_names와 같은 그룹 목록에 나타나지 않는다.

Hosts in multiple groups

각 호스트를 둘 이상의 그룹에 넣을 수 있다. 예를 들어 Atlanta의 데이터 센터에 있는 프로덕션 웹 서버는 [prod], [atlanta], [webservers]라는 그룹에 동시에 포함될 수 있다.
다음을 추적하는 그룹을 만들 수 있다.

  • what : 응용 프로그램, 스택 또는 마이크로서비스 (e.g. DB server, web server)
  • where : 로컬 DNS, 스토리지 등과 통신할 데이터 센터나 지역 (e.g. east, west)
  • when : 개발 단계에서 프로덕션 레벨의 자원(production resources)에 대한 테스트 제외시키기 (e.g. prod, test)

이전 YAML 인벤토리를 확장하여 다음과 같은 what, when, where을 포함시킨다 :

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

one.example.com에 존재하는 dbservers, east, prod 그룹을 확인할 수 있다.
또한 동일한 결과를 위해 중첩된 그룹을 사용하여 이 인벤토리에서 prodtest를 단순화 할 수도 있다.

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: //중첩

어떻게 인벤토리를 구성하고 호스트를 그룹화하는 가에 대한 다양한 예시를 여기에서 확인할 수 있다.

Adding ranges of hosts

유사한 패턴을 가진 호스트가 많은 경우 각 호스트 이름을 별도로 나열하지 않고 범위로 추가 할 수 있다.
INI:

[webservers]
www[01:50].example.com

YAML:

...
  webservers:
    hosts:
      www[01:50].example.com:

숫자 패턴의 경우 원하는대로 선행 0을 포함하거나 제거 할 수 있다.
알파벳 범위를 정의 할 수도 있다. :

[databases]
db-[a:f].example.com

Adding variables to inventory

인벤토리의 특정 호스트나 그룹과 관련된 변수 값을 저장할 수 있다. 이를 시작하기 위해 메인 인벤토리 파일의 호스트나 그룹에 변수를 직접 추가할 수 있다. 하지만 Ansible 인벤토리에 더 많은 managed node를 추가함에 따라 변수를 별도의 호스트 및 그룹 변수 파일에 저장할 수 있다.

Assigning a variable to one machine: host variables

✔️하나의 머신에 변수할당하기
단일 호스트에 변수를 할당한 뒤 플레이북에서 사용가능하다.
INI:

[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909

YAML:

atlanta:
  host1:
    http_port: 80
    maxRequestsPerChild: 808
  host2:
    http_port: 303
    maxRequestsPerChild: 909

비표준 SSH 포트와 같은 고유한 값은 호스트 변수로 잘 작동한다. 호스트 이름 뒤에 포트 번호를 콜론으로 추가해 Ansible인벤토리에 추가할 수 있다.

badwolf.example.com:5309 //port 번호 바로 붙임

연결 변수는 호스트 변수로도 잘 작동한다.

[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 포트를 나열하면 openssh 커넥션은 이를 찾고 사용할 수 있는 반면에 paramiko 커넥션은 그렇게 하지 못한다.

Inventory aliases

인벤토리에서 별칭을 정의 할 수 있다.
YAML:

...
  hosts:
    jumper: //<- aliase
      ansible_port: 5555
      ansible_host: 192.0.2.50

📌위의 예에서 호스트의 별칭 'jumper'에 대해 Ansible을 실행 → 5555 port에서 192.0.2.50에 연결된다.
이는 고정 IP가 있거나 터널을 통해 연결될 때만 작동한다.

일반적으로 이것이 시스템 정책을 설명하는 변수를 정의하기에 가장 좋은 방법은 아니다. 메인 인벤토리 파일에서 변수를 설정하는 것은 간단하다. host_vars 디렉토리의 개별 파일에 변수 값을 저장하는 것에 대한 지침은 호스트 및 그룹 변수 구성을 참조하라.

Assigning a variable to many machines: group variables

✔️여러 머신에 변수할당하기 : 그룹 변수
📌그룹의 모든 호스트가 변수 값을 공유하면 해당 변수를 전체 그룹에 한 번에 적용 할 수 있다.
INI:

[atlanta]
host1
host2

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

YAML:

atlanta:
  hosts: //그룹화된 호스트 = group이름 atlanta
    host1:
    host2:
  vars: //그룹화된 변수 = atlanta.vars
    ntp_server: ntp.atlanta.example.com
    proxy: proxy.atlanta.example.com

그룹 변수는 변수를 한 번에 여러 호스트에 적용할 수 있는 편리한 방법이다.

  • 그러나 Ansible을 실행하기 전에 항상 인벤토리 변수를 포함한 변수를 호스트 수준으로 평준화한다.
  • 호스트가 여러 그룹에 포함돼있다면 Ansible은 해당하는 모든 그룹에서 변수 값을 읽는다.
  • 다른 그룹의 동일한 변수에 다른 값을 할당하면 Ansible은 병합을 위한 내부 규칙에 따라 사용할 값을 선택한다.

Inheriting variable values: group variables for groups of groups

✔️변수 값 상속 : 그룹의 하위 그룹을 위한 그룹 변수*

INI의 접미사 :children 또는 YAML의 children: 항목을 사용해 그룹의 하위 그룹을 만들 수 있다.
:vars 또는 vars:를 사용해 그룹의 하위 그룹에 변수를 적용할 수 있다.

INI:

[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children] //southesat의 child가 atlanta, raleigh
atlanta
raleigh

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

[usa:children] //usa의 child가 southeast, northeast, southwest, northwest
southeast
northeast
southwest
northwest

YAML:

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:

목록 또는 해시 데이터를 저장해야하거나 호스트 및 그룹의 특정 변수를 인벤토리 파일과 별도로 유지하려면 호스트 및 그룹 변수 구성을 참조하라.

하위 그룹에는 다음과 같은 몇 가지 속성이 있다.

  • 하위 그룹에 포함된 모든 호스트는 자동의 상위 그룹에도 포함된다.
  • 하위 그룹의 변수는 상위 그룹의 변수보다 우선 순위가 높다. (오버라이드)
  • 그룹에는 여러 부모와 자식이 있을 수 있지만 순환 관계는 없다.
  • 호스트는 여러 그룹에 속할 수도 있지만, 여러 그룹의 데이터를 병합하는 호스트 인스턴스는 하나 뿐이다.

Organizing host and group variables

기본 인벤토리 파일에 변수를 저장할 수도 있지만 별도의 호스트 및 그룹 변수 파일을 저장하면 ✔️변수값을 쉽게 구성할 수 있다. 호스트 및 그릅 변수 파일은 YAML 구문을 사용해야한다. 유효한 파일 확장자는 '.yml', '.yaml', '.json'이며 파일 확장자가 없는 경우도 가능하다. YAML을 처음 사용하는 경우 YAML 구문을 참조하라.

Ansible은 인벤토리 파일 또는 플레이북 파일과 관련된 경로를 검색하여 호스트 및 그룹 변수 파일을 로드한다. /etc/ansible/hosts에 위치한 인벤토리 파일이 raleighwebservers라는 두 그룹에 속하는 foosball이라는 호스트를 포함한 경우, 해당 호스트는 다음 위치에서 YAML 파일의 변수를 사용한다.

/etc/ansible/group_vars/raleigh #'.yml', '.yaml', '.json'를 붙이는 것은 옵션이다.
/etc/ansible/group_vars/webservers
/etc/ansible/host_vars/foosball

예를 들어, 인벤토리에서 호스트를 데이터 센터별로 그룹화하고 각 데이터 센터가 자체 NTP 서버 및 데이터베이스 서버를 사용한다면 raleigh 그룹의 변수를 저장하기 위해 /etc/ansible/group_vars/raleigh 파일을 생성하면 된다

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

그룹이나 호스트의 이름을 딴 디렉토리를 만들 수도 있다. Ansible은 이 디렉토리의 모든 파일을 사전 순서대로 읽는다. 'raleigh' 그룹의 경우 :

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

raleigh 그룹의 모든 호스트는 이 파일에 정의된 변수를 사용할 수 있다. 단일 파일이 너무 커지거나 일부 그룹변수에서 Ansible Vault를 사용하려는 경우, 변수를 체계적으로 유지하는데 매우 유용할 수 있다.

또한 플레이북 디렉토리를 위한 group_vars/, host_vars/를 추가할 수도 있다.

  • ansible-playbook 커멘드는 기본적으로 현재 작업 디렉토리에서 이러한 형태의 디렉토리를 찾는다.
  • 다른 Ansible 명령 (e.g. ansible, ansible-console 등)은 인벤토리 디렉토리 내의 group_vars/, host_vars/ 디렉토리를 찾는다.
  • 플레이북 디렉토리로부터 그룹 및 호스트 변수를 로드하기 위한 다른 커맨드를 원한다면 커맨드 라인에 --playbook-dir 옵션을 반드시 제공해야한다.
  • 플레이북 디렉토리와 인벤토리 디렉토리 모두에서 인벤토리 파일을 로드하면 플레이북 디렉토리의 변수가 인벤토리 디렉토리에 설정된 변수보다 우선순위가 높다.

인벤토리 파일과 변수를 gir repo(또는 다른 버전 관리)에 유지하면 인벤토리 및 호스트 변수의 변경 사항을 추적 할 수 있다.

How variables are merged

기본적으로 변수는 play가 실행되기 전에 특정 호스트로 병합/평준화 된다. 이렇게 하면 Ansible이 Host 및 Task에 집중하게 되므로 그룹은 실제로 인벤토리와 호스트 매칭 밖에서는 존재할 수 없다.(This keeps Ansible focused on the Host and Task, so groups don’t really survive outside of inventory and host matching.)
기본적으로 Ansible은 그룹 and/or 호스트(DEFAULT_HASH_BEHAVIOUR 참조)에 정의된 변수를 포함해 변수를 덮어쓴다. 순서와 우선 순위는 다음과 같다 (낮은 순위부터 높은 순위) :

  • all group (왜냐면 다른 모든 그룹의 '부모'이므로-최상위 그룹임)
  • 부모 그룹
  • 자식 그룹
  • host

기본적으로 Ansible은

  • 동일한 부모/자식 수준에서 그룹을 알파벳순으로 병합
  • 마지막으로 로드된 그룹은 이전 그룹을 덮어쓴다.
  • e.g. a_group이 b_group과 병합될 때 동일한 변수는 b_group이 a_group을 덮어쓴다. (알파벳 순으로 호출)

같은 레벨의 그룹을 병합하는 순서를 바꾸는 그룹 변수인 ansible_group_priority를 셋팅함으로써 이 행동을 바꿀 수 있다. (부모/자식 순서가 해결된 후)
숫자가 클수록 나중에 병합된다. 즉, 우선순위가 높아진다. 이를 설정하지 않는 경우 이 변수의 기본값은 1이다.

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

이 예에서 두 그룹의 우선 순위가 같으면 결과는 보통 testvar == b이지만, a_group이 우선 순위가 높으므로 결과는 testvar == a.이다.

ansible_group_priority 변수는 group_var의 로딩시에 사용되므로 group_vars/가 아닌 인벤토리 소스에서만 설정할 수 있다.

Using multiple inventory sources

커멘드 라인에서 멀티 인벤토리 매개 변수를 제공하거나 ANSIBLE_INVENTORY를 구성하여 여러 인벤토리 소스(디렉토리, 동적 인벤토리 스크립트, 인벤토리 플러그인에서 지원하는 파일)를 동시에 타겟팅 할 수 있다. 이는 특정 작업에 대해 staging 또는 프로덕션과 같이 일반적으로 별도의 환경을 동시에 대상으로 하려는 경우 유용 할 수 있다.

다음과 같이 커멘드 라인에서 두 가지 소스를 대상으로 지정한다. :

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

인벤토리에 변수 충돌이 있는 경우 How variables are mergedVariable precedence: Where should I put a variable?에 설명된 규칙에 따라 해결된다.
병합 순서는 인벤토리 소스 파라미터의 순서에 따라 제어된다. 만약 staging 인벤토리의 [all:vars]가 myvar = 1을 정의하고 프로덕션 인벤토리는 myvar = 2로 정의 돼있다면 플레이북은 myvar = 2로 실행된다. -i production -i staging.로 선언했다면 결과는 반대이다.
📌커멘드를 쓰는 순서에 따라서 결과가 달라진다. → 앞부터 읽고 뒤에 나오는 파일이 동일한 값을 가지고 있으면 덮어쓴다.

Aggregating inventory sources with a directory

✔️디렉토리를 사용한 인벤토리 소스 집계

디렉토리 아래에 여러 인벤토리 소스와 소스 유형을 결합하여 인벤토리를 생성 할 수도 있다. 이는 정적 및 동적 호스트를 결합하고 이를 하나의 인벤토리로 관리하는데 유용할 수 있다. 다음 인벤토리는 인벤토리 플러그인 소스, 동적 인벤토리 스크립트, 정적 호스트가 있는 파일을 결합한다.

inventory/
  openstack.yml          # OpenStack 클라우드에서 호스트를 가져 오도록 인벤토리 플러그인 구성
  dynamic-inventory.py   # 동적 인벤토리 스크립트로 추가 호스트 추가
  static-inventory       # 정적 호스트 및 그룹 추가
  group_vars/
    all.yml              # 모든 호스트에 변수를 할당

이 인벤토리 디렉토리를 다음과 같이 간단하게 타겟팅 할 수 있다.

ansible-playbook example.yml -i inventory

다른 인벤토리 소스에 대한 다양한 충돌이나 하위 그룹으로써 종속성이 있는 경우 인벤토리 소스의 병합 순서를 제어하는 것이 유용할 수 있다.
📌파일 이름에 따라 인벤토리가 알파벳 순서로 병합되므로 파일에 접두사를 추가하여 결과를 제어 할 수 있다.

inventory/
  01-openstack.yml          # OpenStack 클라우드에서 호스트를 가져 오도록 인벤토리 플러그인 구성
  02-dynamic-inventory.py   # 동적 인벤토리 스크립트로 추가 호스트 추가
  03-static-inventory       # 정적 호스트 및 그룹 추가
  group_vars/
    all.yml                 # 모든 호스트에 변수를 할당

만약 01-openstack.ymlall 그룹에 대해 myvar = 1을 정의하고, 02-dynamic-inventory.pymyvar = 2, 03-static-inventorymyvar = 3을 정의하고 있다면 플레이북은 myvar = 3를 가지고 실행된다.

인벤토리 플러그인 및 동적 인벤토리 스크립트에 대한 자세한 내용은 Inventory Plugins and Working with dynamic inventory.를 참조하라

Connecting to hosts: behavioral inventory parameters

✔️호스트 연결 : 인벤토리 파라미터의 행동에 관하여

위에서 설명한대로 다음 변수를 설정하면 Ansible이 원격 호스트와 상호 작용하는 방식을 제어할 수 있다.

Ansible은 ssh 연결 플러그인(default)을 사용할 때 ssh 키를 해독하기 위해 사용자와 ssh 프로세스 간의 통신이 수동으로 비밀번호를 승인하도록 채널을 노출시키지 않는다. ssh-agent의 사용을 적극 권장한다.

✔️호스트 연결 :
ansible_connection

  • 호스트에 대한 연결 유형
  • Ansible의 커넥션 플러그인의 이름일 수 있다.
  • SSH protocol types
    • smart(default)
    • ssh
    • paramiko
  • 비 SSH 기반 유형은 다음 섹션에서 설명한다.

✔️모든 연결에 대한 일반 사항:
ansible_host : 연결하려는 호스트 이름과 다른 경우 연결할 호스트 이름
ansible_port : 기본값(ssh인 경우 22)이 아닌 경우 연결 포트 번호
ansible_user : 호스트에 연결할 때 사용할 사용자 이름
ansible_password : 호스트 인증에 사용하는 비밀번호 (이 변수는 일반 텍스트로 저장하지 말고 항상 볼트를 사용하도록 한다.📌)

✔️SSH 연결에만 해당하는 것:
ansible_ssh_private_key_file : ssh가 사용하는 개인 키파일, 여러 키를 사용하고 SSH 에이전트를 사용하지 않은려는 경우에 유용하다.
ansible_ssh_common_args : 이 설정은 항상 sftp, scp, ssh의 디폴트 커맨드 라인에 추가된다. 특정 호스트나 그룹을 위해 ProxyCommand를 구성하는데 유용한다.
ansible_sftp_extra_args : 이 설정은 항상 sftp 커맨드 라인에 추가된다.
ansible_scp_extra_args : 이 설정은 항상 scp 커맨드 라인에 추가된다.
ansible_ssh_extra_args : 이 설정은 항상 ssh 커맨드 라인에 추가된다.
ansible_ssh_pipelining : SSH 파이프라이닝을 사용할지 여부를 결정한다. ansible.cfg. 내의 pipelining 설정을 덮어 쓸 수 있다.
ansible_ssh_executable (added in version 2.2) : 시스템 ssh를 사용하기 위한 기본 동작을 덮어쓴다. ansible.cfg. 내의 ssh_executable 설정을 덮어 쓸 수 있다.

2020.04.21 추가
✔️권한 확대 (자세한 내용은 Ansible Privilege Escalation 참조):
ansible_become
ansible_sudo 또는 ansible_su와 동일하다. 권한 확대를 강제한다.
ansible_become_method
권한 확대 방법을 설정할 수 있다.
ansible_become_user
ansible_sudo_user 또는 ansible_su_user와 동일하다. 권한을 확대시킬 사용자를 설정할 수 있다.
ansible_become_password
ansible_sudo_password 또는 ansible_su_password와 동일하다. 권한 확대에 필요한 패스워드를 설정할 수 있다. (절대로 일반 텍스트 문서에 이 변수를 저장하면 안된다. 항상 Vault를 사용하도록 한다.)
ansible_become_exe
ansible_sudo_exe 또는 ansible_su_exe와 동일하다. 사용자가 선택한 권한 확대 메소드에 대한 실행 파일을 설정할 수 있다.
ansible_become_flags
ansible_sudo_flags 또는 ansible_su_flags와 동일하다. 선택한 권한 확대 메소드에 전달 될 플래그를 설정할 수 있다. sudo_flags 옵션의 ansible.cfg에서 전역으로 설정 할 수도 있다.

✔️리모트 호스트 환경 파라미터:
ansible_shell_type

  • 타겟 시스템의 쉘 타입
  • ansible_shell_executable을 non-Bourne (sh)와 호환되는 셸로 설정하지 않은 경우 이 설정을 사용하면 안된다.
  • 디폴트 커맨드는 sh-style 구문으로 형식이 지정된다.
  • 이를 csh또는 fish로 설정하면 대상 시스템에서 실행된 커맨드가 sh-style 대신 해당 쉘의 구문을 따른다.

ansible_python_interpreter

  • The target host python path.
  • 하나 이상의 Python이 있거나, *BSD와 같은 /usr /bin /python에 있지 않거나, /usr /bin /python이 2.X 시리즈의 Python이 아닌 경우에 유용하다.
  • /usr/bin/env 메커니즘을 사용하지 않으므로 리모트 유저의 경로를 올바르게 설정해야하고 python 실행 파일의 이름이 python이라고 가정한다. 여기서 실행 파일의 이름은 python2.6과 같다.

ansible_*_interpreter

  • ruby나 perl과 같은 작업에 적합
  • ansible_python_interpreter와 동일하게 작동한다.
  • 해당 호스트에서 실행될 모듈을 대체한다.

버전 2.1의 새로운 기능 :
ansible_shell_executable

  • 대상 시스템에서 Ansible 컨트롤러가 사용할 쉘을 설정
  • 기본값이 /bin /shansible.cfg의 실행 파일을 대체한다.
  • /bin /sh를 사용할 수 없는 경우에만 변경해야한다. (/bin /sh가 대상 시스템에 설치되어 있지 않거나 sudo에서 실행할 수 없는 경우)

Ansible-INI host file의 예시:

some_host         ansible_port=2222     ansible_user=manager
aws_host          ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host      ansible_python_interpreter=/usr/local/bin/python
ruby_module_host  ansible_ruby_interpreter=/usr/bin/ruby.1.9.3

Non-SSH connection types

이전 섹션에서 언급했듯이 Ansible은 SSH를 통해 플레이북을 실행하지만 이 커넥션 유형으로 제한되지는 않는다. 호스트 특성 파라미터인 ansible_connection=<connector>를 사용하면 커넥션 유형을 변경할 수 있다. non-SSH 기반 커넥터는 다음과 같다.

local
이 커넥터를 사용해 플레이북을 제어 시스템 자체에 배포 할 수 있다.

docker
이 커넥터는 로컬 Docker 클라이언트를 사용해 플레이북을 도커 컨테이너에 직접 배포한다. 다음의 매개 변수를 처리한다.

  • ansible_host : 연결할 Docker 컨테이너의 이름
  • ansible_user : 컨테이너 내에서 작동할 유저 이름, 컨테이너 안에 유자가 있어야한다.
  • ansible_become : true, become_user로 설정하면 컨테이너 내에서 작동하는데 사용된다.
  • ansible_docker_extra_args : Docker가 이해하는 추가 argument가 있는 문자열 일 수 있으며 커맨드 별로 다르다. 이 파라미터는 주로 사용할 원격 Docker 데몬을 구성하는데 사용된다.

생성된 컨테이너에 즉시 배포하는 방법의 예는 다음과 같다. :

- name: create jenkins container
  docker_container:
    docker_host: myserver.net:4243
    name: my_jenkins
    image: jenkins

- name: add container to inventory
  add_host:
    name: my_jenkins
    ansible_connection: docker
    ansible_docker_extra_args: "--tlsverify --tlscacert=/path/to/ca.pem --tlscert=/path/to/client-cert.pem --tlskey=/path/to/client-key.pem -H=tcp://myserver.net:4243"
    ansible_user: jenkins
  changed_when: false

- name: create directory for ssh keys
  delegate_to: my_jenkins
  file:
    path: "/var/jenkins_home/.ssh/jupiter"
    state: directory

사용 가능한 플러그인과 예제가 포함된 전체 목록은 플러그인 리스트를 참조하라.

처음부터 문서를 읽는 경우, 이는 Ansible 플레이북의 첫 번째 예제일 수 있다. 이것은 인벤토리 파일이 아니다. 플레이북은 나중에 자세히 다룰 것이다.

Inventory setup examples

Example: One inventory per environment : 환경 당 하나의 인벤토리

여러 환경을 관리해야하는 경우 인벤토리 별로 단일 환경의 호스트만 정의하는 것이 나은 경우가 있다. 예를 들어, 실제로 일부 "staging" 서버를 업데이트 하려고 할 때 "test" 환경 내의 노드 상태를 우연히 변경하기는 어렵다.

위의 예에서 inventory_test 파일 :

[dbservers]
db01.test.example.com
db02.test.example.com

[appservers]
app01.test.example.com
app02.test.example.com
app03.test.example.com

이 파일에는 "test" 환경의 일부인 호스트만 포함된다. 그리고 다음과 같은 다른 파일 inventory_staging에 "staging" 시스템을 정리한다. :

[dbservers]
db01.staging.example.com
db02.staging.example.com

[appservers]
app01.staging.example.com
app02.staging.example.com
app03.staging.example.com

테스트 환경의 모든 앱 서버에 호출된 site.yml 플레이북을 적용하려면 다음 명령을 사용한다.

ansible-playbook -i inventory_test site.yml -l appservers

Example: Group by function : 기능별 그룹화

이전 섹션에서는 이미 동일한 기능을 가진 호스트를 클러스터링하기 위해 그룹을 사용하는 예를 보았다.
아래는 데이터베이스 서버에 영향을 주지 않고 플레이북 또는 role 내에서 방화벽 규칙을 정의하는 예이다 :

- hosts: dbservers
  tasks:
  - name: allow access from 10.0.0.1
    iptables:
      chain: INPUT
      jump: ACCEPT
      source: 10.0.0.1

Example: Group by location : 위치별로 그룹화

다른 task를 특정 호스트의 위치에 중점을 둘 수 있다.
db01.test.example.comapp01.test.example.coDC1에 있고, db02.test.example.comDC2에 있는 경우 :

[dc1]
db01.test.example.com
app01.test.example.com

[dc2]
db02.test.example.com

실제로는 어떤 날에는 특정 데이터 센터의 모든 노드를 업데이트하고, 다른 날에는 위치에 관계없이 모든 애플리케이션 서버를 업데이트해야 한다면 이런 설정을 모두 혼합해 사용할 수도 있다.

Intro to Playbooks

About Playbooks

📌플레이북 : ad-hoc task 실행 모드와 Ansible을 사용하는 방법이 완전히 다르며 강력하다.
간단히 말해, 플레이북은 기존의 것과는 달리 복잡한 구성 관리 및 다중 시스템 배포 시스템을 위한 기초이며 복잡한 응용 프로그램을 배포하는데 매우 적합하다.
플레이북은 configuration을 선언 할 수 있는 것은 당연하고 또한 머신 셋 사이에 서로 다른 단계를 반복하면서 특정 순서를 지켜야하는 경우에도 수동 오더 프로세스의 단계를 조정할 수 있다. task를 동기식 또는 비동기식으로 시작할 수 있다.

✏️ad-hoc task를 위한 메인 /usr/bin/ansible 프로그램을 실행할 수 있지만, 플레이북은 소스 제어 상태로 유지되어 configuration을 푸시하거나 원격 시스템의 구성이 사양에 맞는지 확인하는데 사용된다.

ansible-examples repository에 이러한 기술을 설명하는 전체 플레이북 세트로 있다. 계속 진행하면서 다른 탭에서 해당 항목을 살펴 보도록 하여라

Playbook Language Example

플레이북은 YAML 형식으로 표현되며 최소한의 구문을 가진다. 의도적으로 프로그래밍 언어나 스크립트가 아닌 configuration 또는 프로세스의 모델이 된다.

일부 에디터에는 플레이북의 깔끔한 TAML구문을 작성하는데 도움이 되는 add-ons이 있다. 자세한 내용은 기타 도구 및 프로그램을 참조하라.

각 플레이북은 목록에서 하나 이상의 '플레이'로 구성된다.
'플레이'의 목표는 호스트 그룹을 잘 정의된 role에 매핑하는 것이다. 기본적으로 task는 단순히 Ansible 모듈을 호출하는 것이다.

여러 '플레이'의 플레이북을 구성하면
1. 웹 서버 그룹의 모든 컴퓨터에서 특정 단계를 실행한 다음
2. 데이터베이스 서버 그룹에서 특정 단계를 실행한 다음
3. 웹 서버 그룹에서 더 많은 명령을 실행
하는 등, 멀티 머신 배포를 조정할 수 있다.

'플레이'는 스포츠에 비유될 수 있다. 당신은 시스템에 영향을 끼침으로써 다른 일을 하는 많은 플레이가 가능하다. 하나의 특정 상태 또는 모델을 정의하는 것만이 아니라 다른 시간에 다른 플레이를 실행할 수 있다.

우선, 여기 verify-apache.yml에는 한 번의 플레이만 포함된 플레이북이 있다. :

---
- 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
      service:
        name: httpd
        state: restarted

플레이북에는 여러 플레이가 포함될 수 있다. 먼저 웹 서버를 대상으로 한다음 데이터베이스 서버를 대상으로하는 플레이북이 있을 수 있다. :

---
- hosts: webservers #첫 번째 플레이
  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

- hosts: databases #두 번째 플레이
  remote_user: root

  tasks:
  - name: ensure postgresql is at the latest version
    yum:
      name: postgresql
      state: latest
  - name: ensure that postgresql is started
    service:
      name: postgresql
      state: started

이 방법을 사용해 대상 호스트 그룹, 원격 서버에 로그인하는 사용자 이름, sudo 여부 등을 전환 할 수 있다. 플레이는 task 처럼 플레이북에 지정된 순서대로 실행된다.: 위에서 아래로

아래에는 플레이북 언어의 다양한 기능을 설명한다.

Basics -- 플레이북 언어의 기능

Hosts and Users

플레이북의 각 플레이에 대해 인프라에서 대상으로 지정할 머신과 단계(tasks)를 완료할 리모드 유저를 선택할 수 있다.

hosts라인은 콜론으로 구분되는 하나 이상의 그룹 또는 호스트 패턴의 목록이다. (참조 : Patterns: targeting hosts and groups ) remote_user는 단순히 사용자 계정의 이름이다.

---
- hosts: webservers
  remote_user: root

remote_user 매개변수는 user로 불렸다. Ansible 1.4에서 유저 모듈(리모트 시스템에서 사용자를 만드는데 사용됨)과 구별되도록 이름이 변경되었다.

task 별로 리모트 유저를 정의할 수도 있다.

---
- hosts: webservers
  remote_user: root
  tasks:
    - name: test connection
      ping:
      remote_user: yourname

become -추가학습

✏️아래 예제들에 become이 많이 사용되므로 잠깐 보고 넘어가도록 하겠다. 자세한 내용은 여기를 클릭하면 된다. 현재는 최소한의 이해를 돕기위한 정도만 해석하도록 하겠다.

play나 task 지시문, 커넥션 변수, 커멘드 라인에서 become 을 사용해 제어할 수 있다.
여러가지 방법으로 권한 확대 특성을 설정하는 경우 the general precedence rules를 검토하고 사용할 설정을 이해하라.

Ansible에 포함된 모든 플러그인의 전체 목록은 플러그인 목록에서 찾을 수 있다.

✏️Become 지시어
play나 task 수준에서 become을 제어하기 위한 지시문을 설정할 수 있다. 호스트마다 다른 연결 변수를 설정하여 이를 대체 할 수 있다. 이러한 변수와 지시문은 독립적이다. 예를 들어 become_user를 설정해도 become이 설정되지 않는다.

become : yes로 설정하면 권한 확대를 활성화한다.
become_user : 로그인할 때의 사용자가 아닌 원하는 권한을 가진 사용자로 설정한다.become:yes를 의미하지 않는다-호스트 수준에서 설정 할 수 있게한다. 기본값은 root이다.
become_method : (play 또는 task 수준에서) the Become Plugins을 사용하기로 설정된 ansible.cfg의 디폴트 메소드 설정을 덮어쓴다.
become_flags : (play 또는 task 수준에서) tasks나 role에 특정 플래그를 사용할 수 있다. 쉘이 로그인 없음으로 설정된 경우 일반적으로 사용자를 nobody로 변경하는 것으로 사용된다. Ansible2.2에 추가되었다.

예를 들어, non-root 유저로 연결됐을 때, root권한이 요구되는 시스템 서비스를 관리하기 위해 become_user(root)를 기본값으로 사용 할 수 있다.

- name: Ensure the httpd service is running
  service:
    name: httpd
    state: started
  become: yes

apache 유저로써 커맨드를 수행하는 경우 :

- name: Run a command as the apache user
  command: somecommand
  become: yes
  become_user: apache

셀이 로그인 없음(nologin) 일 때, nobody로 어떤 일을 하는 경우 :

- name: Run a command as nobody
  command: somecommand
  become: yes
  become_method: su
  become_user: nobody
  become_flags: '-s /bin/sh'
Become connection varia

다른 유저로 작업을 실행할 수 있는 기능도 지원된다. (see Understanding privilege escalation: become):

---
- hosts: webservers
  remote_user: yourname
  become: yes

전체 플레이 대신 특정 task에 become 키워드를 사용할 수도 있다.

---
- hosts: webservers
  remote_user: yourname
  tasks:
    - service:
        name: nginx
        state: started
      become: yes
      become_method: sudo

또한 로그인 한 다음 root가 아닌 다른 유저가 될 수도 있다.

---
- hosts: webservers
  remote_user: yourname
  become: yes
  become_user: postgres

su와 같은 다른 권한 확대 방법을 사용 할 수도 있다.

---
- hosts: webservers
  remote_user: yourname
  become: yes
  become_method: su

sudo를 위한 암호를 지정해야하는 경우 ansible-playbook--ask-become-pass 또는 -K와 함께 실행하도록 하여라.
만약 become을 활용해 플레이북을 실행하고 플레이북이 정지(hang) 된 것처럼 보이면, 이는 권한 확대 프롬프트에서 멈췄을 수도 있다. 이는 Control-C 를 사용하여 중지 할 수 있으며, 적절한 비밀번호를 추가하여 플레이북을 다시 실행할 수 있다.

✏️권한 확대
권한 확대 (privilege escalation)는 보통 애플리케이션이나 사용자에 대해 보호되는 자원들에 대한 상승된 접근을 얻기 위해서 운영체제나 소프트웨어 애플리케이션에서 버그나 설계결함, 또는 설정을 익스플로잇하는 행동을 말한다. 이것에 의한 결과는 애플리케이션이 개발자나 시스템 관리자가 의도한 것보다 높은 수준의 권한을 얻어서 비허가 행동을 할 수 있게 된다.

❗️중요❗️
become_user를 root 이외의 사용자에게 사용하는 경우, 모듈 argument는 /tmp의 임시 파일에 간단히 기록된다. 이는 'bob'에서 'root'로 이동하거나 'bob' 또는 'root'로 직접 로그인 할 때가 아니라 'bob'과 같은 사용자의 권한을 'timmy'로 변경하는 경우에만 발생한다. 이 데이터가 간단하게 읽힐 수 있는(쓰기는 불가능하다) 것이 우려된다면 암호화되지 않은 비밀번호(with become_user set)를 전송하면 안된다. 다른 경우에서 /tmp는 사용되지 않으며 play에 들어가지 않는다. 또한 Ansible은 비밀번호 파라미터를 로그하지 않도록 주의하고 있다.

new in version 2.4.
호스트가 실행되는 순서를 제어 할 수도 있다. 디폴트 값은 인벤토리에서 제공한 오더를 따르는 것이다.

- hosts: all
  order: sorted
  gather_facts: False
  tasks:
    - debug:
        var: inventory_hostname

order에 설정 가능한 값은 다음과 같다:

valuedescription
inventroy(default) 인벤토리에 의해 '제공된대로' 정렬
reverse_inventory인벤토리에서 '제공한' 순서의 반대로 정렬
sorted이름-알파벳 순으로 정렬
reverse_sorted이름-알파벳 역순으로 정렬
shuffle매번 무작위로 정렬

Tasks list

각 플레이에는 task 목록이 포함되어 있다. 📌다음 작업으로 넘어가기 전에 호스트 패턴과 일치하는 모든 시스템에 대해 task가 한 번에 하나씩 순서대로 실행된다. 플레이에서 모든 호스트는 동일한 task 지시문을 가져야함을 이해하는 것이 중요하다. 선택된 호스트를 task에 매핑하는 것이 플레이의 목적이다.❗️

위에서 아래로 실행되는 플레이북을 실행할 시 실패한 task가 있는 호스트는 전체 플레이북의 로테이션에서 제외된다. 즉, task에 실패하면 플레이북 파일을 수정하고 재실행해야한다.

각 task의 목표는 매우 구체적인 파라미터로 모듈을 실행하는 것이다.
변수는 모듈에 대한 파라미터로 사용될 수 있다.

모듈은 멱등성이 있어야한다. 즉, 순서대로 모듈을 여러번 실행하면 한 번만 실행하는 것과 같은 효과가 있다.

멱등성 (idempotent)
멱등법칙(冪等法則) 또는 멱등성(冪等性, 영어: idempotent)은 수학이나 전산학에서 연산의 한 성질을 나타내는 것으로, 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다.

멱등원을 달성하는 한 가지 방법은 모듈이 원하는 최종 상태가 이미 달성되었는지 확인하고 해당 상태가 달성된 경우 어떤 액션도 취하지 않고 종료하는 것이다. 플레이북을 사용하는 모든 모듈이 멱등원인 경우, 플레이북 자체는 멱등원인 가능성이 있으므로 플레이북을 재실행하는 것이 안전해야할 것이다.

command가 chmod 또는 setsebool 등과 같은 경우에 이는 정상이며, commandshell 모듈은 같은 command로 재실행된다. 비록 모듈들을 멱등원으로 만드는데 사용하기 위한 create 플래그가 있음에도 말이다.

모든 task는 플레이북 실행 결과를 포함하는 name을 가진다. 이것은 사람이 읽을 수 있는 출력인데, 각 task 단계에 대한 설명이므로 적절히 선정하는 것이 좋다. name이 제공되지 않으면 action의 값이 출력에 사용된다.

레거시 action: module options 형식을 사용하여 작업을 선언 할 수 있지만 보다 일반적인 형식인 module: options을 사용하는 것이 좋다. 이러한 권장 형식은 도큐먼트 전체에서 사용되지만 일부 플레이북에는 이전 형식이 나타날 수 있다.

기본 task는 다음과 같다. 대부분의 모듈과 마찬가지로 서비스 모듈은 다음과 같은 key=value argument를 사용한다.

tasks:
  - name: make sure apache is running
    service:
      name: httpd
      state: started

commandshell 모듈은 key=value 형식을 사용하는 대신 argument 목록을 가져오는 유일한 모듈이다.

tasks:
  - name: enable selinux
    command: /sbin/setenforce 1

commandshell 모듈은 리턴코드에 관해 관리하므로 성공적인 종료 코드가 0이 아닌 command를 가진다면 다음과 같이 수행할 수 있다.

tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand || /bin/true

혹은

tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand
    ignore_errors: True

액션 라인이 너무 길어 가독성에 좋지않다면, 이를 끊고 연속 라인으로 들어쓰기가 가능하다.

tasks:
  - name: Copy ansible inventory file to client
    copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
            owner=root group=root mode=0644

액션 라인에서 변수를 사용할 수 있다. vars 섹션에서 vhost라 불리는 변수를 정의했다고 가정한다면 다음처럼 수행할 수 있다.

tasks:
  - name: create a virtual host file for {{ vhost }}
    template:
      src: somefile.j2
      dest: /etc/httpd/conf.d/{{ vhost }}

동일한 변수를 템플릿에서 사용 가능한데, 이는 나중에 자세히 살펴보도록한다.

이제 매우 기본적인 플레이북에서 모든 task가 해당 플레이에 직접 나열될 것이다. 하지만 재사용 가능한 플레이북 만들기에 설명 된대로 작업을 분리하는 것이 더 합리적이다.

Action Shorthand

New in version 0.8.

Ansible은 다음과 같은 모듈 나열을 선호한다.

template:
    src: templates/foo.j2
    dest: /etc/foo.conf

Ansible 초기 버전은 다음 형식을 사용했으며, 여전히 작동한다.

action: template src=templates/foo.j2 dest=/etc/foo.conf

Handlers: Running Operations On Change

앞에서 언급했듯이 모듈은 멱등원이어야하며 리모트 시스템에서 변경했을 때 relay 할 수 있다. 플레이북은 이를 인식하고 변화에 대응하는데 사용 가능한 기본 이벤트 시스템을 가지고 있다.
이러한 'notify' 액션은 플레이의 각 task 블록의 끝에서 트리거되며 여러 다른 작업에서 알림을 받았더라도 한 번만 트리거된다.

예를 들어, 여러 resource가 configuration 파일을 변경했기 때문에 아파치를 다시 시작해야 함을 나타낼 수 있지만, 불필요한 재시작을 피하기 위해 아파치는 한 번만 바운스된다.

파일 내용이 변경 될 때 두 서비스를 재시작하는 예는 다음과 같다.(오로지 파일 변경시에만):

- name: template configuration file
  template:
    src: template.j2
    dest: /etc/foo.conf
  notify: #변화 감지해서 아래 핸들러 실행
     - restart memcached
     - restart apache

task의 notify에 나열된 것을 핸들러라고 부른다.

핸들러는 일반적으로 인반 task와 다르지 않은 task 목록으로, 전역으로 고유한 이름으로 참조되고 nofitier에 의해 알려진다. 핸들러에 아무것도 알리지 않으면 이는 실행되지 않는다. 핸들러에 알려진 작업 수에 관계없이 특정 작업에서 모든 작업이 완료된 후 한 번만 실행된다.

핸들러 섹션의 예는 다음과 같다.

handlers:
    - name: restart memcached #nofity에서 변화를 감지해 알려줄 핸들러의 이름
      service:
        name: memcached
        state: restarted
    - name: restart apache
      service:
        name: apache
        state: restarted

Ansible 핸들러가 변수를 사용하도록 할 수 있다. 예를 들어, 서비스 이름이 배포에 따라 약간 다른 경우 출력에 각 대상 시스템에 대해 재시작된 서비스의 정확한 이름이 표시되게하려고 한다. 핸들러 이름에 변수를 배치해선 안된다. 핸들러 이름은 초기에 템플릿화되므로 Ansible은 다음과 같이 핸들러 이름에 사용할 수 있는 값을 가지고 있지 않을 수도 있다.

handlers:
# this handler name may cause your play to fail!
- name: restart "{{ web_service_name }}"

핸들러 이름에 사용된 변수를 사용할 수 없으면 전체 플레이가 실패한다. 플레이가 수행되던 중에 변수가 변경된다해도 새로 생성된 핸들러는 생성되지 않는다.

📌대신 핸들러의 task 파라미터에 변수를 배치하도록 한다. 다음 예제에서의 include_vars와 같이 사용해 값을 로드 할 수 있다.

tasks:
  - name: Set host variables based on distribution
    include_vars: "{{ ansible_facts.distribution }}.yml"

handlers:
  - name: restart web service
    service:
      name: "{{ web_service_name | default('httpd') }}"
      state: restarted

Ansible 2.2부터 핸들러는 generic topics를 수신(listen)할 수 있으며 task는 다음과 같이 해당 topic에 알릴 수 있다.

handlers:
    - name: restart memcached
      service:
        name: memcached
        state: restarted
      listen: "restart web services" # 아래 notify와 동일 → 수신
    - name: restart apache
      service:
        name: apache
        state: restarted
      listen: "restart web services" # 아래 notify와 동일 → 수신

tasks:
    - name: restart everything
      command: echo "this task will restart the web services"
      notify: "restart web services" # 변경 시 알릴 것

이렇게하면 여러 핸들러를 보다 쉽게 트리거 할 수 있다. 또한 핸들러를 자신의 이름에서 분리함으로써 플레이북과 역할(특히 Galaxy와 같은 공유 소스에서 3rd party roles를 사용하는 경우)간에 핸들러를 쉽게 공유 할 수 있다.

  • notify 핸들러는 notify-statament에 나열된 순서가 아닌 정의된 순서대로 실행된다. listen이 사용되는 경우에도 마찬가지이다.
  • 핸들러의 이름과 listen topic은 전역 네임스페이스에 존재한다.
  • 핸들러의 이름은 템플릿화(templatable) 가능하나 listen topics은 그렇지 않다.
  • 고유한 핸들러 이름을 사용하라. 이름이 같은 핸들러를 두 개 이상 트리거하면 첫 번째 핸들러를 (뒤의 것이) 덮어 쓴다. 즉, 마지막으로 정의 된 것만 실행된다.
  • include 내부에 정의된 핸들러에 통지(notify)하는 것은 불가능하다. Ansible 2.1부터는 작동하지만 include는 정적이여야한다.

role은 나중에 설명하지만 다음을 짚어보는 것이 좋다.

  • pre_tasks, tasks, post_tasks 섹션에 notify된 핸들러는 notify된 섹션의 끝에서 자동으로 플러시된다.
  • roles 섹션 내에서 notify된 핸들러는 tasks 종료 섹션에서 자동으로 플러시되지만 tasks 핸들러보다 우선된다.
  • 핸들러는 범위가 정해져 있으므로 정의된 role 밖에서 사용할 수 있다.

모든 핸들러 명령을 즉시 플러시하려면 다음을 수행하라:

tasks:
   - shell: some tasks go here
   - meta: flush_handlers
   - shell: some other tasks

위의 예에서 대기중인 모든 핸들러는 meta 명령문에 도달하기 전에 처리된다. 이것은 별로 없는 사례이지만 때때로 유용할 수 있다.

Executing A Playbook : 플레이북 실행하기

플레이북 구문을 배웠으므로 플레이북을 실행해본다. 간단하게 병렬 레벨 10을 사용해 플레이북을 실행하도록 하겠다.

ansible-playbook playbook.yml -f 10

Ansible-Pull

Ansible 아키텍처를 뒤집기 원한다면 노드가 구성을 푸시하지 않고 중앙에서 체크인하도록 할 수 있다.
ansible-pull은 git에서 configuration 명령의 저장소를 확인한 다음 해당 내용에 대해 ansible-playbook을 실행하는 스크립트이다.
체크아웃 위치를 로드 밸런싱한다고 가정하면, ansible-pull 스케일은 기본적으로 무한대로 확장된다.
자세한 내용은 ansible-pull --help를 실행해라.
push 모드의 crontab을 통해 ansible-pull을 구성 할 수 있는 영리한 플레이북도 존재한다.

Linting playbooks

ansible-lint를 사용하여 플레이북을 실행하기 전에 세부 사항을 확인 시킬 수 있다.

예를 들어, 이 섹션의 앞부분에서 소개한 verify-apache.yml playbook에서 ansible-lint를 실행하면 다음과 같은 결과가 나타난다.

$ ansible-lint verify-apache.yml
[403] Package installs should not use latest
verify-apache.yml:8
Task/Handler: ensure apache is at the latest version

The ansible-lint default rules page는 각 오류에 대해 설명한다. [403]에 대한 권장 수정 사항을 플레이북안에서 state: lateststate: present로 변경하는 것이다.

Other playbook verification options : 또다른 플레이북 확인 옵션

플레이북을 확인하는데 사용할 수 있는 자세한 도구 목록은 플레이북 유효성 검사 도구를 참조하라. 고려해야할 다른 것들은 아래와 같다.

  • 플레이북의 구문(syntax)을 확인하려면 --syntax-check 플래그를 ansible-playbook와 함께 사용해라. 포함된 파일, role 등에 구문 오류가 없는지 확인하기 위해 parser를 통해 플레이북 파일을 실행한다.
  • 플레이북 실행의 맨 아래에서 대상이 된 노드와 어떻게 그들이 수행될 것인지에 대한 요약을 확인하라. 일반적인 실패와 치명적인 'unreachable' 의사 소통 요청은 개별적으로 유지된다.
  • 성공한 모듈과 실패한 모듈의 자세한 출력을 보려면 --verbose플래그를 사용해라. Ansible 0.5 이상에서 사용할 수 있다.
  • 플레이북을 실행하기 전에 어떤 호스트가 영향을 받는지 확인하려면 다음과 같이 작성해라. : ansible-playbook playbook.yml --list-hosts

Roles

New in version 1.2.

Role은 알려진 파일 구조에 따라 특정 vars_files, tasks, 핸들러를 자동으로 로드하는 방법이다. Role에 따라 컨텐츠를 그룹화하면 다른 사용자와 role을 쉽게 공유 할 수 있다.

Role Directory Structure

프로젝트 구조 예 :

site.yml
webservers.yml
fooservers.yml
roles/
    common/
        tasks/
        handlers/
        files/
        templates/
        vars/
        defaults/
        meta/
    webservers/
        tasks/
        defaults/
        meta/

Role은 파일이 특정 디렉토리 이름에 들어있을 것이라고 예상한다. Role은 이러한 디렉토리 중 하나 이상이 포함되어야하지만 사용되지 않는 디렉토리는 제외해도 된다. 사용중인 각 디렉토리는 관련 컨텐츠를 가지고 있는 main.yml 파일을 반드시 포함해야한다.:

  • tasks : role에 의해 실행될 주요 task 목록을 포함한다.
  • handlers : 해당 role 또는 이외의 다른 곳에서 사용할 수 있는 핸들러를 포함한다.
  • defaults : role의 디폴트 변수 (자세한 내용은 변수 사용 참조)
  • vars : role에 대한 다른 변수 (자세한 내용은 변수 사용 참조)
  • files : 해당 role을 통해 배포 할 수 있는 파일이 포함되어 있다.
  • templates : 해당 role을 통해 배포 할 수 있는 템플릿이 포함되어 있다.
  • meta : 해당 role에 대한 일부 메타 데이터를 정의한다. 자세한 내용을 아래를 참조하라.

다른 YAML 파일이 특정 디렉토리에 포함될 수 있다. 예를 들어, tasks/main.yml 파일에 플랫폼 별 작업을 포함시키는 것이 일반적이다.

# roles/example/tasks/main.yml
- name: added in 2.4, previously you used 'include'
  import_tasks: redhat.yml
  when: ansible_facts['os_family']|lower == 'redhat'
- import_tasks: debian.yml
  when: ansible_facts['os_family']|lower == 'debian'

# roles/example/tasks/redhat.yml
- yum:
    name: "httpd"
    state: present

# roles/example/tasks/debian.yml
- apt:
    name: "apache2"
    state: present

role에는 모듈 및 기타 플러그인이 포함될 수도 있다. 자세한 내용은 아래의 Embedding Modules and Plugins In Roles 섹션을 참조하라.

Using Roles

role을 사용하는 고정적인 (오리지날) 방법은 주어진 플레이에 roles: 옵션을 사용하는 것이다.

---
- hosts: webservers
  roles:
    - common
    - webservers

각 role 'x'에 대해 다음 동작을 지정한다.

  • roles/x/tasks/main.yml 이 있으면 여기에 나열된 task가 play에 추가된다.
  • roles/x/handlers/main.yml 이 있으면 여기에 나열된 핸들러가 play에 추가된다.
  • roles/x/vars/main.yml 이 있으면 여기에 나열된 변수가 play에 추가된다.
  • roles/x/defaults/main.yml 이 있으면 여기에 나열된 변수가 play에 추가된다.
  • roles/x/meta/main.yml 이 있으면 여기에 나열된 모든 role 종속성이 role 목록 (1.3 버전 이상)에 추가된다.
  • 모든 사본, 스크립트, 템플릿, role 내의 포함 task는 role/x/{files,templates,tasks}/(task에 따라 다른 디렉토리)의 파일을 상대적으로 또는 절대적으로 경로를 지정하지 않고도 사용가능하다.

이런 방식이 사용되는 경우 플레이북의 실행 순서는 다음과 같다.
1. play에 정의된 pre_task
2. 지금까지 트리거된 모든 핸들러가 실행된다.
3. roles에 나열된 각각의 role이 차례로 실행된다. roles의 meta/main.yml에 정의된 모든 role 종속성이 태크 필터링 및 조건에 따라 먼저 실행된다.
4. play에 정의된 tasks
5. 지금까지 트리거된 모든 핸들러가 실행된다.
6. play에 정의된 post_tasks
7. 지금까지 트리거된 모든 핸들러가 실행된다.

role 종속성에 대한 자세한 내용은 아래를 참조하라

task가 포함된 태그를 사용하는 경우 (나중에 플레이북의 일부만 실행하는 수단으로 설명한다.) pre_tasks, post_tasks, role 종속성이 중단창(outage window) 제어나 로드 밸런싱을 모니터링하는데 사용되는 경우 pre_tasks, post_tasks, role 종속성에 태그를 지정하고 이를 전달하라.

Ansible 2.4부터 import_role 이나 include_role을 사용해 다른 task와 함께 인라인 role로 사용할 수 있다. (As of Ansible 2.4, you can now use roles inline with any other tasks using import_role or include_role:)

---
- hosts: webservers
  tasks:
    - debug:
        msg: "before we run our role"
    - import_role:
        name: example
    - include_role:
        name: example
    - debug:
        msg: "after we ran our role"

role이 이전 방식으로 정의되면 정적 import로 처리되고 플레이북 구문 분석 중에 처리된다.

include_role 옵션은 Ansible 2.3.에서 도입되었다. include (동적) vs. import (정적) 사용방식에 따라 사용법이 Ansible 2.4에서 약간 변경되었다. 자세한 내용은 Dynamic vs. Static을 참조해라

role에 사용되는 이름은 간단한 이름이거나 (아래의 Role Search Path 참조) 정규화 된 경로 일 수 있다.

---
- hosts: webservers
  roles:
    - role: '/path/to/my/roles/common'

role은 다른 키워드를 허용할 수 있다.

---
- hosts: webservers
  roles:
    - common
    - role: foo_app_instance
      vars:
        dir: '/opt/a'
        app_port: 5000
    - role: foo_app_instance
      vars:
        dir: '/opt/b'
        app_port: 5001

최신 구문을 사용할 경우 :

---
- hosts: webservers
  tasks:
    - include_role:
        name: foo_app_instance
      vars:
        dir: '/opt/a'
        app_port: 5000
  ...

조건부로 role을 가져와 해당 작업을 실행할 수 있다.

---
- hosts: webservers
  tasks:
    - include_role:
        name: some_role
      when: "ansible_facts['os_family'] == 'RedHat'"

마지막으로, 지정한 role 내의 task에 태그를 할당 할 수 있다.

---
- hosts: webservers
  roles:
    - role: foo
      tags:
        - bar
        - baz
    # YAML 구문을 이용해 다음과 같이 표현도 가능하다.
    - { role: foo, tags: ["bar", "baz"] }

최신 구문으로 작성할 경우:

---
- hosts: webservers
  tasks:
    - import_role:
        name: foo
      tags:
        - bar
        - baz

해당 태그는 지정된 태그로 해당 role의 모든 task에 태그를 지정하여, role 내부에 지정된 tag에 추가한다.

반면에 role 자체의 import에 태그를 지정하고 싶은 경우에는 다음처럼 작성한다. :

---
- hosts: webservers
  tasks:
    - include_role:
        name: bar
      tags:
        - foo

이 예제의 태그는 include_role 내부의 task에 추가되지 않는다. 둘 다 수행하기 위해서 block 지시문을 사용할 수 있다.

실행할 태그의 하위 셋을 지정하는 동안 role을 import하는 기능이 없다. 많은 태그가 있는 role을 만들고 다른 시간에 role의 하위 셋을 호출하려는 경우, 해당 role을 여러 role로 분할하는 것을 고려해야한다.

2020.04.22 추가

Role Duplication and Execution

Ansible은 role에 정의된 파라미터가 각 정의마다 다르지 않은 경우에는 여러번 정의 된 경우에도 role을 한 번만 실행할 수 있다. 예를 들면 다음과 같다.

---
- hosts: webservers
  roles:
    - foo
    - foo

위의 경우 role foo는 한 번만 실행된다.
role을 여러번 실행하려면 두 가지 옵션이 있다.
1. 각 role 정의에서 다른 매개 변수를 전달한다.
2. allow_duplicates: true를 role의 meta/main.yml 파일에 추가한다.

예1 - 다른 매개 변수 전달:

---
- hosts: webservers
  roles:
    - role: foo
      vars:
        message: "first" # 같은 role인 foo이지만, message 파라미터가 다르다
    - { role: foo, vars: { message: "second" } }

이 예에서 각 role 정의에 서로 다른 파라미터를 가지므로 foo는 두 번 실행된다.

예2 - allow_duplicates: true 사용:

# playbook.yml
---
- hosts: webservers
  roles:
    - foo
    - foo

# roles/foo/meta/main.yml
---
allow_duplicates: true

이 예에서는 명시적으로 중복을 허용했으므로 foo가 두 번 실행된다.

Role Default Variables

New in version 1.3.

role의 디폴트 변수를 사용하면 포함되거나 종속된 role에 대한 디폴트 변수를 설정할 수 있다.(아래 참조) 디폴트 값을 작성하려면 defaults/main.yml 파일을 role 디렉토리에 추가한다. 이 변수들은 사용 가능한 모든 변수 중 우선 순위가 가장 낮으며 인벤토리 변수를 포함한 다른 변수로 쉽게 재정의 가능하다.

Role Dependencies

New in version 1.3.

role 종속성을 사용하면 role을 사용할 때 다른 role을 자동으로 가져올 수 있다. role 종속성은 위에서 언급 한대로 role 디렉토리에 포함된 meta/main.yml 파일에 저장된다. 이 파일에는 지정된 role 앞에 삽입될 role과 파라미터 목록이 포함되어야한다.
roles/myapp/meta/main.yml의 예제이다 :

---
dependencies:
  - role: common
    vars:
      some_parameter: 3
  - role: apache
    vars:
      apache_port: 80
  - role: postgres
    vars:
      dbname: blarg
      other_parameter: 12

role 종속성은 이전의 role 정의 방식을 사용해야한다.

role 종속성은 이를 포함하는 role보다 항상 앞에서 실행되며 재귀적일 수 있다. 종속성의 위에 지정된 복제 규칙(동일한 role은 한 번만 수행)을 따른다. 다른 role도 종속적이게 나열한다면 이는 위에 제공된 것과 동일한 규칙을 기반으로 하므로 재실행되지 않는다. 자세한 내용은 Galaxy 역할 종속성을 참조하라.

allow_duplicates: true를 사용할 때, 이는 항상 부모가 아닌 종속된 role의 meta/main.yml에 있어야한다.

예를들어 car라는 role은 wheel이라는 role에 종속성을 다음과 같이 가지고 있을 때 이는 각각 다르다:

---
dependencies:
  - role: wheel
    vars:
      n: 1
  - role: wheel
    vars:
      n: 2
  - role: wheel
    vars:
      n: 3
  - role: wheel
    vars:
      n: 4

그리고 wheeltirebrake라는 두 가지 role에 종속된다. wheel을 위한 meta/main.yml 은 다음을 포함한다.

---
dependencies:
  - role: tire
  - role: brake

그리고 tirebrake를 위한 meta/main.yml는 다음을 포함한다.

---
allow_duplicates: true

📌결과적으로 실행 순서는 다음과 같다.

tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car

wheel은 각각 다른 파라미터 값을 가지고 있으므로 allow_duplicates: true를 사용할 필요는 없다.

변수 상속 및 범위는 변수 사용에 자세히 설명되어있다.

Embedding Modules and Plugins In Roles

이는 대부분의 사용자와 관련이 없는 고급 주제이다.
This is an advanced topic that should not be relevant for most users.

If you write a custom module (see Should you develop a module?) or a plugin (see Developing plugins), you may wish to distribute it as part of a role. Generally speaking, Ansible as a project is very interested in taking high-quality modules into ansible core for inclusion, so this shouldn’t be the norm, but it’s quite easy to do.

A good example for this is if you worked at a company called AcmeWidgets, and wrote an internal module that helped configure your internal software, and you wanted other people in your organization to easily use this module – but you didn’t want to tell everyone how to configure their Ansible library path.

Alongside the ‘tasks’ and ‘handlers’ structure of a role, add a directory named ‘library’. In this ‘library’ directory, then include the module directly inside of it.

Assuming you had this:

roles/
    my_custom_modules/
        library/
            module1
            module2

The module will be usable in the role itself, as well as any roles that are called after this role, as follows:

---
- hosts: webservers
  roles:
    - my_custom_modules
    - some_other_role_using_my_custom_modules
    - yet_another_role_using_my_custom_modules

This can also be used, with some limitations, to modify modules in Ansible’s core distribution, such as to use development versions of modules before they are released in production releases. This is not always advisable as API signatures may change in core components, however, and is not always guaranteed to work. It can be a handy way of carrying a patch against a core module, however, should you have good reason for this. Naturally the project prefers that contributions be directed back to github whenever possible via a pull request.

The same mechanism can be used to embed and distribute plugins in a role, using the same schema. For example, for a filter plugin:

roles/
    my_custom_filter/
        filter_plugins
            filter1
            filter2

They can then be used in a template or a jinja template in any role called after ‘my_custom_filter’

Role Search Path

Ansible은 다음과 같은 방식으로 role을 검색한다.
1. 플레이북 파일에 상대 경로인 roles/ 디렉토리
2. 디폴트는 /etc/ansible/roles

Ansible 1.4 이상에서는 role을 검색하기 위한 추가적인 roles_path를 구성 할 수 있다. 이를 사용해 모든 공통 role을 한 위치에서 확인하고 여러 플레이북 프로젝트 간에 쉽게 공유 할 수 있다. ansible.cfg에서 이를 설정하는 방법에 대한 자세한 내용은 Configuring Ansible를 참조하라.

Ansible Galaxy

Ansible Galaxy는 모든 종류의 커뮤니티가 개발한 Ansible role을 찾고, 다운로드하고, 평가하고, 검토할 수 있는 무료 사이트이다. 이는 자동화 프로젝트를 시작하는 좋은 방법이 될 수 있다.

클라이언트 ansible-galaxy는 Ansible에 포함되어 있다. galaxy 클라이언트는 'Ansible Galaxy'에서 role을 다운로드 받을 수 있게 해주며, 또한 자신만의 role을 만들기 위한 훌륭한 기본 프레임워크를 제공한다.

profile
🌱 😈💻 🌱

0개의 댓글