Tag Archives: 플레이북

Ansible Playbook 정리

ansible_logo

플레이북은 Ansible의 설정, 배포, 통합 언어입니다. 이것들을 통해 당신이 원격 시스템에 적용하고자 하는 정책이나 IT 프로세스하에 단계별로 설정 작업을 할 수 있습니다.

Ansible 모듈이 당신의 작업상에서의 툴이라면 플레이북은 설계 계획에 해당합니다. 기본적으로 플레이북은 원격 서버들에 대한 설정과 배포를 관리하는데 사용됩니다. 좀 더 깊이 알아보면 그것들을 통해 순차적인 다양한 계층별 배포를 롤링 업데이트를 통해 실현할 수 있으며 다른 호스트들에게 작업을 위임하거나 모니터링 서버와 로드 밸런싱 서버들과 상호 작용을 할 수 있습니다.

이것들에 대한 많은 정보들에 대해서 다루겠지만 여기서 한번에 습득해야 할 필요는 없습니다. 우선 작게 시작한 뒤에 나중에 필요로 할때마다 필요한 기능을 추가하면 될 것입니다.

플레이북은 사람이 읽기 쉽게 만들어져 있으며 기본적인 텍스트 언어로 만들어져 있습니다. 플레이북과 포함된 파일들을 관리하는 방법은 다양하며 Ansible을 사용하는 많은 사람들이 선호하는 방식을 몇가지 제안할 것입니다.

우선 플레이북 예제[Example Playbooks]을 함께 확인해 보길 권장합니다. 이 예제에서는 다양한 개념을 넣는 방법에 대한 모범 사례를 보여줍니다.

플레이북에 대해

플레이북은 애드혹 테스트 실행 모드와는 완벽하게 다른 사용방법이며 특히 강력한 사용 방법입니다. 간단히 말해 플레이북은 정말 간단하게 설정을 관리하고 다수의 머신에 대한 배포 시스템에 대한 기본적인 단위입니다. 기존에 존재해왔던것과 달리 복잡한 어플리케이션 형태의 배포에 매우 적합합니다.

플레이북은 설정을 정의할 수 있으며 특정 머신의 집합을 오가며 다른 작업을 수행하도록 수동으로 작업 순서를 설정하는것도 가능합니다. 이때에 작업은 동기 또는 비동기로 수행할 수 있습니다.

/usr/bin/ansible 명령을 통한 애드혹 테스크를 실행하는것에 반해 플레이북은 소스 컨트롤을 통해 보관하거나 당신의 설정을 내보내거나 원격 시스템을 구성하는데 보장되는데 더욱 적합합니다.

플레이북을 통해 이러한 기술들을 구현하는 방법은 [Ansible-Example 저장소]에 정리가 되어있습니다. 이것들을 함께 확인해보길 추천합니다.

풀레이북 언어 예제

플레이북은 YAML 포맷으로 표현되며 프로그래밍 언어나 스크립트가 아닌 설정이나 프로세스에 대한 모델에 대한 정의를 표현한 최소한의 문법으로 구성되어있습니다. 각각의 플레이북은 리스트안의 한개 이상의 “플레이”로 구성됩니다.

이 플레이의 목표는 호스트의 그룹을 잘 정의된 Ansible내에서 테스크로 불리는 역할(Role)에 매핑해주는 것입니다. 기본적으로 각 테스크는 Ansible의 모듈을 호출하는것에 지나지 않습니다.

플레이북의 다수의 플레이들을 구성하는것을 통해, 다수의 머신들에 대한 통합 배포를 하고 웹서버 그룹의 모든 머신에 특정 작업을 수행하고 데이터베이스 서버 그룹에 특정 작업을 수행하고 다음에 추가로 웹서버 그룹에 또다른 작업을 수행하는식의 수행이 가능합니다.

“플레이”는 스포츠에 비유해 볼 수 있습니다. 당신은 당신의 시스템들에 대해 각기 다른 굉장히 많은 플레이를 가질 수 있으며 각기 다른 플레이를 각각 다른 시간에 수행할 수 있습니다.

시작하시는 분들을 위해 하나의 플레이를 보도록 하겠습니다.

---
- 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 (and enable it at boot)
    service: name=httpd state=started enabled=yes
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

우리는 물론 YAML의 딕셔너리 타입을 사용하여 각 모듈의 인자들을 여러 라인으로 분리해 정의하는것도 가능합니다. 이것은 정말 긴 파라미터를 가지고 있거나 많은 파라미터를 가지는 경우 구조적으로 보기 좋게 정리해주는 장점이 있습니다. 다음은 YAML 딕셔너리를 적용하여 기존의 key=value 형태를 분리해본 예제입니다.

---
- 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=running

당신은 각 호스트 그룹간에 전환을 할 때 어떤 유저로 로그인할 지 sudo 를 수행할지 말지 이런것들을 결정할 수 있습니다. 플레이는 플레이북에 정의되어있는데로 위에서 아래의 순서로 수행이 됩니다. 다음은 플레이북의 다양한 기능들에 대해 자세히 알아보도록 하겠습니다.

기본

호스트와 유저

플레이북의 각각의 플레이를 통해서 당신의 인프라스트럭쳐중에 원하는 타겟에 대한 머신을 선택할 수 있고 어떤 원격 유저로 해당 작업을 수행할지 선택할 수 있습니다.

이 hosts 라인은 [Patterns] 문서에 설명했듯이 하나 이상의 그룹이나 호스트 패턴을 콜론(:)으로 분리하여 정의한 리스트입니다. remote_user는 유저 계정의 이름입니다.

---
- hosts: webservers
  remote_user: root

각각의 테스크별로 작업을 수행할 유저를 따로 정의할 수 있습니다.

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

다른 유저의 권한으로 작업을 수행하는 것도 가능합니다. [Become/Privilege Escalation]을 참고해주세요.

---
- hosts: webservers
  remote_user: yourname
  sudo: yes

물론 모든 플레이 대신에 특정 테스크에 한해 sudo를 수행할 수도 있습니다.

---
- 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

또한 기존의 sudo 대신에 su와 같은 다른 권한 상승 명령을 지정할수도 있습니다.

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

만약 sudo를 수행하는데 다른 비밀번호가 필요하다면 ansible-playbook을 실행할 때 –ask-become-pass 옵션을 사용하거나 기존에 사용되던 –ask-sudo-pass를 사용할 수 있습니다. 만약 플레이북을 수행중에 행 걸린상태로 보여질 때 확인해 보면 대부분이 권한 상승을 위한 비밀번호 입력을 기다리는 상태일 경우가 많습니다. 이때엔 컨트롤 C를 눌러 일단 종료시킨 뒤에 다시 적절한 비밀번호와 함께 수행하시면 됩니다.

테스트 목록

각각의 플레이는 테스크의 목록을 가집니다. 테스크는 다음의 테크스로 이동하기 전에 호스트 패턴에 매칭되는 모든 머신들에 대해서 한번에 하나씩 수행됩니다. 플레이를 구동함과 동시에 여기서 반드시 이해해야 할 부분은 모든 호스트가 동일한 테스크를 명령받게 된다는 것입니다. 이것이 플레이가 특정 선택된 호스트를 테스크에 매핑하는 목적입니다.

위에서 아래로 플레이북이 실행될 때, 전체 플레이북의 작업을 호스트에 수행중에 실패가 발생한다면 간단히 플레이북의 문제가 되는 부분을 수정한 뒤 다시 실행하면 됩니다.

각 테스크의 목적은 특별히 지정한 인자들을 사용하여 모듈을 실행하는 것입니다. 위에서 언급했듯이 변수들은 인자를 통해 각 모듈에 전달 될 수 있습니다.

모듈들을 “멱등”으로 동작합니다. 이게 무슨 말이냐면 당신이 플레이북을 여러번 실행하게 될 때 시스템의 상태를 가져와서 변화된 부분만을 다시 수행하도록 합니다. 이것은 플레이북을 반복 실행해도 매우 안전하게 만들어줍니다. 이들은 당신이 원하지 않는 변화를 일으키지 않을 것입니다.

commandshell 모듈은 일반적으로 chmod, setsebool과 같은 문제가 되지 않을 명령을 재실행 하게 됩니다. 하지만 creates 플래그를 사용하여 이러한 모듈들이 멱등으로 동작하도록 할 수 있습니다.

모든 테스크는 플레이북이 실행될 때 외부에 노출될 name을 가집니다. 이러한 출력 메시지는 사람을 위해 출력되는것이므로 각각의 단계를 설명하는 좋은 문구여야 합니다. 이 name이 지정되지 않는다면 작업을 수행중에 출력되는 메시지가 사용됩니다.

테스크는 예전에 사용되던 action: module options 형태로 정의가 가능하지만 좀 더 사용하기 편리한 module: options 형태로 정의하시기를 추천합니다.

다음은 가장 많이 사용되는 key=value 인자를 사용한 서비스 모듈의 기본적인 테스크 형태입니다.

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

commandshell 모듈은 유일하게 key=value 형태로 사용하지 않고 명령어를 그대로 사용하는 모듈들입니다. 이 명령들은 당신이 예상하는데로 사용이 간단합니다.

tasks:
  - name: disable selinux
    command: /sbin/setenforce 0

command 와 shell 모듈은 명령의 실행결과 반환 코드를 통해 명령의 성공/실패 여부를 판단하게 됩니다. 만약 당신의 명령이 적절한 종료 코드를 구현하고 있지 않다면 다음과 같은 방법을 취할 수 있습니다.

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 }}

이러한 변수들을 뒤에서 설명할 템플릿 안에서도 사용 가능합니다. 지금까지 플레이를 통해 모든 테스크를 플레이북에 정의하는 기초적인 방법을 알아보았습니다만 include 문법을 사용해서 테스크별로 쪼개는것이 더 좋은 방법입니다. 해당 부분은 뒤에서 다시 설명드리겠습니다.

액션 단축 표기법

Ansible은 0.8 이후의 버전부터 다음과 같은 표기법을 선호합니다.

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

만약 이전 버전을 사용해야만 한다면 다음과 같은 표기법만이 사용 가능합니다.

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

하지만 이 예전 표기법은 현재까지 Deprecated 되지 않고 지원되고 있습니다.

핸들러: 변경에 대한 작업을 수행

우리가 언급했다시피 모듈들은 멱등으로 쓰여지게 되며 원격 시스템에 변화가 일어났는지 여부에 따라 작업을 진행할지 말지 결정하게 됩니다. 플레이북은 이러한 것을 식별할 수 있으며 변화에 대한 결과를 사용할 수 있는 기본적인 이벤트 시스템을 갖추고 있습니다.

이 “통지” 액션은 플레이북의 테스크 블록중에 마지막에서 실행되며 많은 다른 테스크들이 실행될 때 한번만 실행됩니다. 예를 들어 다수의 리스소들이 적용하는 경우가 있다고 할 때 그중에 변경된 아파치 웹서버의 설정 파일이 존재하고 아파치가 재실행되어야 적용될 수 있습니다. 하지만 이 설정 파일이 변경되지 않았다면 아파치는 불필요한 재시작을 수행하지 않을것입니다.

다음은 컨텐츠 파일이 변경되었을 경우에만 두 서비스를 재시작 하는 예제입니다.

- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
     - restart memcached
     - restart apache

테스크의 notify 섹션은 작업 수행후에 실행할 핸들러를 호출합니다.

핸들러는 실제로는 글로벌하게 유니크한 이름을 갖는 일반적인 테스크와 다른게 없는 테스크의 목록입니다. 핸들러는 통지가 무엇을 통지해야 하는지를 정의합니다. 아무것도 핸들러를 통지하지 않는 경우 아무것도 실행되지 않습니다. 특정 플레이의 테스크가 완료된 후에 한번만 실행됩니다.

다음은 핸들러 섹션의 예제입니다.

handlers:
    - name: restart memcached
      service: name=memcached state=restarted
    - name: restart apache
      service: name=apache state=restarted

핸들러는 서비스를 재시작하거나 리부팅 하는 작업을 수행하는데 최적입니다. 아마 이러한 경우가 아닌 이상 사용할 일이 없을 것입니다.

역할은 나중에 다시 이야기 하겠지만 여기서 언급할 필요가 있는 부분이 있습니다.

  • pre_tasks, tasks, post_tasks 섹션을 통해 통지되는 핸들러는 그들이 통지된 섹션의 마지막에 자동으로 큐의 핸들러들은 플러시됩니다.
  • roles 섹션을 통해 통지되는 핸들러들은 다른 어떤 tasks 이전에 수행되지 않고 tasks 섹션의 마지막에 자동으로 플러시 됩니다.

만약 지금까지의 모든 핸들러들을 즉시 플러시 하고 싶다면 1.2 부터는 다음과 같은 방법을 사용할 수 있습니다.

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

위의 예제는 meta 구문에 도달하는 순간 지금까지 큐에 쌓인 핸들러들을 곧바로 수행합니다. 이것은 조금 특이한 경우지만 때때로 매우 유용하게 사용될 수 있습니다.

플레이북을 실행하기

지금까지 플레이북의 문법에 대해 알아보았습니다. 그럼 어떻게 이 플레이북을 실행할까요? 간단합니다. 다음의 병렬로 레벨 10의 설정으로 플레이북을 실행하는 방법입니다.

ansible-playbook playbook.yml -f 10

Ansible-Pull

Ansible의 아키텍쳐를 뒤집어서 설정을 밀어넣어주는 방식 말고 노드들이 중앙에 위치한 서버로부터 설정을 끌어가도록 할 수 있습니다.

ansible-pull은 git로부터 설정 명령들이 저장된 저장소를 체크아웃하고 해당 컨텐츠에 적절한 ansible-playbook을 실행하는 작업 스크립트입니다. 이 체크아웃을 할 저장소의 위치를 적절히 분산하여 ansible-pull의 스케일을 무한대로 키울 수 있습니다. ansible-pull –help 명령을 사용하여 자세한 사용방법을 확인하시길 바랍니다.

[Clever Playbook]을 보시면 푸시 모드를 사용하여 ansible-pull을 crontab에 등록하는 과정을 확인할 수 있습니다.

팁과 트릭

플레이북의 실행 결과를 보시면 마지막에 정리된 결과가 출력되고 몇개의 타겟에 실행이 되었고 일반적인 실패와 치명적인 “unreached” 통신 실패가 함께 표기가 됩니다. 만약 성공한 모듈뿐만 아니라 실패한 모듈의 상세한 출력을 보고 싶다면 –verbose 플래그를 사용하시면 됩니다. 이 플래그는 0.5 이후의 버전부터 지원되고 있습니다.

cowsay 패키지가 설치되어있다면 Ansible 플레이북의 실행결과가 크게 업그레이드 됩니다. 한번 시도해 보시기 바랍니다. 플레이북을 실행하기 전에 어떤 호스트들에 영향을 끼치게 될지 확인 하고 싶다면 다음의 명령을 사용하시면 됩니다.

ansible-playbook playbook.yml --list-hosts

참고 : http://docs.ansible.com/ansible/playbooks_intro.html