쿠버네티스 전문가 양성과정 8주차 1일(2/6)

최수환·2023년 2월 6일
0

Kubernetes

목록 보기
32/75
post-thumbnail

Ansible

플레이북

작업제어

이전 블로그에서는 작업제어의 조건문까지 다루었다.
이번에는 조건문 이후에 템플릿부터 다룰 예정이다.

템플릿

  • Asible에서 파일을 관리하는 가장 강력한 방법은 템플릿을 만드는 것

  • 템플릿을 사용하면 가능한 변수와 팩트를 사용하여 파일이 배포될 때 관리 호스트에 대해 자동으로 사용자 정의되는 템플릿 구성 파일을 작성할 수 있음

  • Jinja2

    • Python의 매우 강력하고 고급 템플릿 언어
    • 매우 빠르고 안정적이며 동적 데이터를 생성하는 데 널리 사용
    • 텍스트 기반 템플릿 언어이므로 모든 마크업과 소스 코드를 생성하는 데 사용할 수 있음
    • 파일의 확장자는 .j2이다
  • Jinja2 의 특징

    • 제어 구조(루프 및 조건문)
    • 템플릿 상속
    • 사용자 정의 필터 지원
    • 풍부한 내장 필터 세트
    • 구성 가능한 구문
  • Jinja2 기호

    • {{ . . . . }}
      -> 이중 중괄호는 템플릿 파일에서 널리 사용되는 태그이며 변수를 포함하고 궁극적으로 코드 실행 중에 값을 인쇄하는 데 사용
    • {% . . . . %}
      -> 루프 및 if-else 문과 같은 제어 문에 주로 사용
    • {# . . . . #}
      -> 작업을 설명하는 주석
  • Jinja2 템플릿

    • Jinja2 템플릿은 수시로 변경될 수 있는 변수를 저장하는 간단한 템플릿 파일
    • 플레이북이 실행되면 변수는 Ansible 플레이북에 정의된 실제 값으로 대체

1 . 템플릿 생성 예제

vi template1.yml # 템플릿 작성
- name: template test
  hosts: AA
  vars:
    site_name: groom_world
  tasks:
  - name: create template
    template: # 템플릿 모듈 
      src: test1.j2
      dest: /tmp/test

vi test1.j2 # j2(jinja2) 파일 작성 
Welcome {{ site_name }}
This node is {{ ansible_facts.hostname }}



-> 해당 노드 해당 디렉터리에 test파일이 만들어진 것을 확인
-> test파일에 입력한 정보가 작성된것을 확인

2 . 템플릿 생성 예제 (j2를 이용한 fact 접근)

vi template2.yml # 템플릿 작성
- name: template test
  hosts: AA
  tasks:
  - name: create directory
    file:
      state: directory
      dest: /etc/ansible/facts.d
      recurse: yes
  - name: create fact file
    template:
      src: factfile.j2
      dest: /etc/ansible/facts.d/test.fact
  - setup:
  - name: print lacal facts
    debug:
      msg: "{{ ansible_local }}"


vi factfile.j2 # j2파일 작성 
{# local_fact.config #}
[test1]
hostname= {{ ansible_facts.hostname }}
ipaddr={{ ansible_facts.enp0s8.ipv4.address }}


-> j2파일이 템플릿으로 대상 노드들에게 팩트파일로 전달되고 팩트파일의 정보가 출력되는 것을 볼 수 있다

3 . 템플릿 생성 예제 (j2를 이용한 반복문)

vi template3.yml # 템플릿 생성
- name: template test
  hosts: ABC
  tasks:
  - template:
      src: host_test.j2
      dest: /etc/hosts1

vi host_test.j2 # j2파일 생성
{% for i in [1,2,3] %}
  ansi-node{{ i }} 192.168.56.2{{ i }}
{% endfor %}


-> 대상 노드들에게 호스트와 ip가 적힌 새로운 호스트파일이 생성되어있는 것을 확인

핸들러

  • 특정 서비스가 실행 중일 경우에만 httpd 서비스 다시 시작
    • 핸들러(Handler)는 작업을 실행하고 시스템의 변경(Changed)이 있을 때에 별도의 작업을 호출하고 실행하는 작업
    • 주로 핸들러를 사용하게 시스템에서 특정 서비스의 구성 파일이 변경된 경우 서비스를 재시작할 때
    • Ansible 모듈은 멱등이 되도록 설계 되어 있음. 즉 제어 노드가 원하는 상태가 되도록 하기 위해 플레이북과 해당 작업을 변경하지 않아도 되는 경우, 적절하게 작성된 플레이북에서 제어노드를 변경하지 않고 플레이북과 해당 작업을 여러번 실행 가능
    • 핸들러는 작업에 변경이 있고, 반드시 알림(Notify)이 있을 때만 실행되는 작업
    • 작업(변경) ---> 알림 ---> 핸들러

1 . 핸들러 생성 예시

- name: handler test
  hosts: ansi-node1
  tasks:
  - copy:
      content: "{{ ansible_facts.hostname }} handler test"
      dest: /var/www/html/index.html
    notify:
    - Restart web service # 알림이름
  handlers:
  - name: Restart web service # handler가 인지할 알림이름 
    service:
      name: apache2
      state: restarted



-> 첫번째 실행에서 notify를 통해 핸들러가 작동된것을 볼 수 있다. 이때 다시 실행해보면 멱등성에 의해 결과에 변함이 없는 것을 확인할 수 있다. 즉, 아무 작업도 하지 않는다.
-> 최종적으로 curl해봤을 때 index.html의 문구가 나오는 것을 확인
-> 알림이름과 handler가 인지할 알림이름은 반드시 같아야 한다

2 . 다중알림 핸들러 생성 예시

vi html1.j2 # j2파일 생성
{{ ansible_facts.hostanme }} is handlers test1

vi handler2.yml # 플레이북 생성 
- name: handlers test
  hosts: ansi-node3
  tasks:
  - name: Install package
    apt:
      name:
      - apache2
      - firewalld
      state: present
      update_cahce: yes
  - name: Config index.html
    template:
      src: html1.j2
      dest: /var/www/html/index.html
    notify:
    - Restart web service
    - Restart firewalld service

  handlers:
  - name: Restart web service
    service:
      name: apache2
      state: restarted
  - name: Restart firewalld service
    service:
      name: firewalld
      state: restarted

-> 여러 알림을 만들고 알림이 울리면 핸들러가 알림에 해당하는 작업 실행
📗 만약 핸들러에 어떤 작업을 추가하고 다시 실행해도 위의 알림을 포함한 작업에서는 변화가 없기 때문에 알림은 핸들러에게 가지 않고 따라서 핸들러에 추가된 작업은 무시된다

2-1 . 다중알림 핸들러의 다른 형태

cp handler2.yml handler3.yml

- name: handlers test
  hosts: ansi-node3
  tasks:
  - name: Install package
    apt:
      name:
      - apache2
      - firewalld
      state: present
      update_cache: yes
  - name: Config index.html
    template:
      src: html1.j2
      dest: /var/www/html/index.html
    notify:
    - Restart service # 여러 알림이 아닌 하나의 알림 설정 

  handlers:
  - name: Restart web service
    service:
      name: apache2
      state: restarted
    listen: Restart service # listen모듈로 알림 선택
  - name: Restart firewalld service
    service:
      name: firewalld
      state: restarted
    listen: Restart service

-> 알림을 여러개 설정할 필요없이 listen모듈로 간편하게 알림을 선택할 수 있다
📗 firewalld를 설치한 상황에서 curl명령을 보냈을 때 응답이 오려면 firewalld가 http를 열어줘야한다

<핸들러 사용시 주의 사항>

  • 핸들러는 항상 플레이의 handlers 섹션에서 지정한 순서대로 실행
    • 작업의 notify 문에 따라 나열한 순서나 작업이 핸들러에 통지하는 순서대로 실행되지는 않음.
  • 핸들러는 일반적으로 플레이에서 다른 모든 작업이 완료된 후에 실행
    • 플레이북의 tasks 부분의 작업에서 호출한 핸들러는 tasks 아래에 있는 모든 작업이 처리될 때까지 실행되지 않음
  • 핸들러 이름은 글로벌 네임스페이스에 있음.
    • 두 핸들러에 같은 이름이 잘못 지정되면 한 핸들러만 실행
  • 둘 이상의 작업에서 한 핸들러에게 알리는 경우 해당 핸들러가 한번만 실행
    • 작업에서 핸들러에게 알리지 않는 경우 핸들러가 실행되지 않음.
  • notify문을 포함한 작업이 changed 결과를 보고하지 않으면 핸들러에 알리지 않음
    • 다른 작업에서 이 핸들러에게 알라지 않으면 이 핸들러를 건너띔
    • Ansible은 작업이 change 상태를 보고하는 경우에만 핸들러에게 알림.
  • 핸들러는 작업이 제어노드를 변경할 때 추가 조치를 수행하기 위한 것으로 정상적인 작업을 대체하기 위해서 사용해서는 안됨.
  • 핸들러는 작업의 알림과 핸들러의 이름이 일치해야지만 알림을 받을 수 있기 때문에 핸들러의 작업에는 반드시 이름을 선언해야 함

위임 (작업 실행 위치 제어)

  • 하나의 플레이를 실행 할 때 작업들은 별도로 설정하지 않는 한 호스트에 실행이 됨
  • 위임(delegation)은 호스트에 정의 되어있는 여러 작업들 중에 일부분의 작업을 다른 호스트에서 실행할 수 있음
  • 위임을 사용하면 상호 관련된 환경을 정확하고 효율적으로 관리할 수 있음
  • 다른 호스트를 참조하여 한 호스트에서 작업을 수행하려면 작업에서 delegate_to키워드를 사용
  • 이는 로드 밸런싱된 풀에서 노드를 관리하거나 중단 기간을 제어하는 데 이상적
  • 직렬 키워드 와 함께 위임을 사용 하여 한 번에 실행되는 호스트 수를 제어할 수 있음

1 . 위임 생성 예시

- name: delegate test
  hosts: ansi-node1
  tasks:
  - command: hostname
    register: hostname_result1
  - debug:
      msg: "{{ hostname_result1.stdout }}"
  - command: hostname
    register: hostname_result2
    delegate_to: ansi-node2 # 위임 
  - debug:
      msg: "{{ hostname_result2.stdout }}"


-> 명령어 실행 후 node2에게 위임했기 때문에 node1의 플레이에서 작업 도중에 node2의 hostname을 등록변수에 담아 출력할 수 있었다.

2 . 팩트 수집 위임 생성 예시

  • Ansible 작업을 위임하는 것은 현실 세계에서 작업을 위임하는 것과 동일하다고 할 수 있음.
  • 위임된 작업에 의해 수집된 모든 fact는 기본적으로 fact를 생성한 호스트(위임된 호스트)가 아닌 인벤토리 _호스트 이름(현재 호스트)에 할당
  • 수집된 fact을 현재 호스트 대신 위임된 호스트에 할당하려면 delegate_facts: true로 설정
- name: delegate facts test
  hosts: ansi-node1
  gather_facts: 0 # 수집x 
  tasks:
  - setup: 
    delegate_to: ansi-node2 # 위임
    delegate_facts: true # 수집 o

- name: delegate ansi-node2
  hosts: ansi-node2
  gather_facts: no # 수집 x 
  tasks:
  - debug:
      msg: "{{ ansible_facts.hostname }}"


-> node2에게 위임 후 팩트 수집 한다. 이후 node2를 대상으로 팩트 수집을 하지않아도 팩트 정보가 출력되는 것을 알 수 있다.

블록

  • 블록은 플레이에 하나 이상의 작업을 논리적으로 그룹화 할 수 있음
    • 그룹화의 장점은 대부분 단일 작업에서 적용했던 플레이북 키워드를 블록 수준에서 적용할 수 있음
    • 조건문(when), 권한상승(become) 등 블록에 구성할 수 가능
    • 블록에 구성된 키워드는 블록에 속한 모든 작업에 공통으로 적용
    • 단 반복문은 블록에 적용 X
  • 대부분의 프로그래밍 언어에 있듯이 예외 처리 기능을 제공
    • 블록의 하나 이상의 작업이 실패한 경우, 실패한 작업에 대응(롤 백, 오류 수정 등)하는 작업을 지정 가능

<작업의 그룹화>

  • 블록의 모든 작업은 블록 수준에서 적용된 지시문을 상속
  • 단일 작업에 적용할 수 있는 대부분(반복문(loop) 제외)은 블록 수준에서 적용할 수 있으므로 블록을 사용하면 작업에 공통적인 데이터나 지시문을 훨씬 쉽게 설정 가능
  • 지시문은 블록 자체에 영향을 미치지 않으며 블록으로 묶인 작업에 의해서만 상속
    • when 문은 블록 자체가 아니라 블록 내의 작업에 적용

1 . 블록 사용 예시 (작업의 그룹화)

- name: block test
  hosts: AA
  tasks:
  - name: block test1
    block:
    - name: command hostname
      command: hostname
      register: result1
    - name: print hostname
      debug:
        msg: "{{ result1.stdout }}"
    when: ansible_hostname == 'ansi-node1'

  - name: block test2
    block:
    - name: command grep
      command: grep 'ansi-node2' /etc/hosts
      register: result2
    - name: print result2
      debug:
        msg: "{{ result2.stdout }}"
    when: ansible_hostname == 'ansi-node2'


-> 작업을 그룹화 시켜서 조건문에 의해 node1에 대해서 hostname, node2에 대해서 grep의 결과가 나온 것을 확인

2 . 블록 사용 예시 (오류 처리)

  • rescue및 always섹션이 있는 블록을 사용하여 Ansible이 작업 오류에 응답하는 방식을 제어할 수 있음
  • 복구 블록은 블록의 이전 작업이 실패할 때 실행할 작업을 지정
    • 접근 방식은 많은 프로그래밍 언어의 예외 처리와 유사
  • Ansible은 작업이 '실패' 상태를 반환한 후에만 복구 블록을 실행
    • 잘못된 작업 정의와 연결할 수 없는 호스트는 복구 블록을 트리거하지 않음
  • 블록의 작업 중 하나라도 실패가 있으면, Rescue 섹션의 작업이 실행
    • 블록의 작업 중 실패가 없으면, Rescue 섹션은 실행 X
- name: block test
  hosts: ansi-node1
  tasks:
  - name: block session
    block:
    - name: print1
      debug:
        msg: "block message 1"
    - name: command
      command: failed
    - name: print2
      debug:
        msg: "block messages 2"

    rescue:
    - name: print3
      debug:
        msg: "rescue block messages 1"
    always:
    - name: print4
      debug:
        msg: "always block messages 1"


-> print1 출력 후 command 실패에 의해 print2는 출력되지않는다. 하지만 중지되는것이 아니라 rescue문에 의해 print3가 출력된다. always는 성공여부와 관계없이 항상 출력

📕 rescue & always

  • 블록의 작업이 반환 failed되면 rescue섹션은 오류를 복구하기 위해 작업을 실행
  • 블록 구문의 실패가 있을 때만 Rescue 섹션이 실행되며, always 섹션은 항상 실행
  • 블록에서 오류가 발생하고 rescue 작업이 성공하면 Ansible은 실행에 대한 원래 작업의 실패 상태를 되돌리고 원래 작업이 성공한 것처럼 재생을 계속 실행

태그(tags)

  • 많은 작업이 있는 플레이북의 경우 플레이북 전체를 실행하는 대신 특정 일부분 만 실행하는 것이 유용할 수 있음
  • Ansible 태그로 특정 작업만 실행하거나, 특정 작업을 실행하지 않을 수 있음
  • 태그는 플레이, 블록, 역할, 작업에 설정하고, 플레이북 실행 시 태그를 선택

1 . 작업에 태그 추가

- name: tag test
  hosts: ansi-node1
  tags: play1
  tasks:
  - block:
    - name: task 1-1
      debug:
        msg: task 1-1
      tags: task1
    - name: task 1-2
      debug:
        msg: task 1-2
      tags: task1

    - name: task 2-1
      debug:
        msg: task 2-1
      tags: task2
    - name: task 2-2
      debug:
        msg: task 2-1
      tags: task2
    tags: block1
  - name: task 3
    debug:
      msg: task 3
    tags: task3

- name: tag test2
  hosts: ansi-node2
  tags: play2
  tasks:
  - name: task 4
    debug:
      msg: task4

-> 플레이 단위, 블록 단위, 작업 단위 등에 tag를 붙일 수 있다
-> 태그를 통해 원하는 작업만 실행시킬 수 있다

<태그의 실행>

  • ansible-playbook tag1.yml --tags all : 모든 태그 실행
  • ansible-playbook tag1.yml --tags 'untagged' : 태그가 없는 것 실행
  • ansible-playbook tag1.yml --tags 'block1' : 블록에 붙여진 태그 실행
  • ansible-playbook tag1.yml --tags 'play1' : 플레이에 붙여진 태그 실행
  • ansible-playbook tag1.yml --tags 'task1' : 작업에 붙여진 태그 실행
  • ansible-playbook tag1.yml --skip-tags tag1 : tag1만 빼고 실행

아티팩트 재사용

  • Ansible 플레이북 작성 시 하나의 매우 큰 파일에 플레이 및 작업을 작성할 수 있음
  • 단일 플레이북의 복잡한 작업을 다른 파일로 나누어 작업 집합으로 구성할 수 있음
  • 더 작고 분산된 아티팩트를 통해 변수, 작업 및 플레이를 여러 플레이북에서 재사용 가능

재사용 가능한 아티팩트

  • 변수 파일
  • 작업 파일
  • 플레이북 파일
  • 역할

변수 재사용

플레이북에서 변수 재사용

  • 플레이북에서 vars_files 키워드 및 include_vars 모듈을 사용하여 외부 변수 파일을 가져올 수 있음
  • vars_files 키워드
    • 플레이 안에서 변수 파일을 불러와서 참조함
  • include_vars 모듈
    • tasks 영역에서 변수 파일을 불러와서 참조함

작업 재사용



1 . include를 이용한 핸들러

2 . import를 이용한 핸들러

3 . import를 이용한 핸들러

profile
성실하게 열심히!

0개의 댓글