ansible에서 템플릿 사용과 jinja2 소개

ansible에서 기존 파일의 내용을 수정하는데에는 여러 모듈을 쓸 수 있다. (lineinfile, blockinfile 등) 이것들은 단순 수정하는데는 좋지만, 어떤 규칙에 의해 체계적으로 관리하는 파일에서 쓰기에는 부족하다. 

 

파일을 관리하는데 더 훨씬 강력한 방법은 템플릿을 지정하는 것이다. 템플릿은 파일이 배포될 때 ansible client에 대해 ansible 변수 및 팩트변수를 사용해 자동으로 지정되는 템플릿 파일을 작성할 수 있다. 이것은 제어하기 더 쉽고 오류 발생률이 낮다.

 

ansible에서는 템플릿파일용으로 jinja2라는 템플릿 시스템을 사용한다.  jinja2는 위에서 말한 템플릿을 사용하는데 쓰기도 하지만, playbook에서 변수를 참조하고 여러가지 확장된 사용을 가능하게 한다.

 

jinja2 템플릿 구문 사용하기

- jinja2 템플릿은 데이터, 변수, 식 등 여러 요소로 구성되는데, 이러한 변수와 식은 jinja2 템플릿이 랜더링되면(jinja2문법이 번역되어 실행되면) 해당 값으로 변경된다. 

- 템플릿에 사용하는 변수는 playbook의 vars 섹션에서 지정할 수 있다.

- 템플릿에 해당 ansible client의 팩트변수를 사용할 수 있다.

- jinja2의 기본적인 사용은 {{ }} , {% %} , {# #} 3가지 방법이 있다.

     - {{ }} : 식/변수 결과를 최종 사용자에게 출력

     - {% %} : 식 또는 논리(반복문 등)에 사용

     - {# #} : 주석

- jinja2 템플릿이 들어있는 파일에는 따로 확장명이 필요 없다. 하지만 .j2 이런식으로 확장명을 제공하면 템플릿인지 쉽게 알 수 있다.

 

 

* template 모듈

- 기본적인 핵심 기능은 ansible host에 있는 파일을 ansible client에 배포하는 것이다. 하지만 같은 기능을 하는 모듈은 많으므로 일반적으로 jinja2 템플릿 파일을 배포하는데 사용된다.

- template 지시문을 사용하며, src는 ansible host에 있는 배포"할" 템플릿 소스파일의 경로, dest는 ansible client에서 해당 파일을 받을 경로이다.

- template 모듈은 file 모듈과 같이 배포된 파일의 소유자, 그룹, 권한, selinux 컨텍스트 등을 지정할 수 있다.

- template 모듈과 copy 모듈은 비슷하지만 다른점은, template는 파일 안에 변수 등이 있으면 그걸 랜더링해서 보여준다.

- 또한 validate 옵션으로 임의의 명령(visudo -c 같은)을 실행해 파일을 올바른 위치에 복사하기 전에 구문검사를 수행할 수 있다. 자세한 내용은 ansible-doc template 명령의 validate 부분 참고할 것

 

 

* 예시 : ansible client의 팩트변수로 템플릿 생성하기

 

템플릿 파일

vi test.j2
Welcome to {{ ansible_facts.hostname }}.
Today's date is : {{ ansible_facts.date_time.date }}.

플레이북 파일

- name: jinja2 test
  hosts: web.example.com
  tasks:
    - name: jinja2 template
      template:
        src: /home/devops/ansible_test/test.j2
        dest: /tmp/jinja-test-result
        owner: root
        group: root
        mode: 0644

결과

이렇게 하면, ansible host에는 템플릿파일플레이북파일을 사용하여 특정 ansible client에 결과파일을 만들어 내는 작업을 할 수 있는 것이다. 이렇게 간단하게 배포가 가능하다.

 

 

* 템플릿 파일에 관리자용 주석 달기

- 관리자가 template으로 만든 결과파일에 대해 수정하지 않도록 요구하거나 특별한 주석을 달고 싶을때, 아래와 같이 주석을 달 수 있다.

- 여러 방법이 있지만 가장 간단한 방법은, ansible.cfg의 [defaults] 섹션에 ansible_managed = 라는 부분을 추가하는 것이다.

- 아래 예시를 참고한다.

- 이렇게 구성해둔 후, 템플릿 파일에는 아래와 같이 {{ ansible_managed }} 라는 값을 맨 위에 추가해준다.

- 결과는 다음과 같다.

 

 

jinja2 제어구조 - 반복문

템플릿 파일에서도 제어구조인 반복문, 조건문 등을 사용할 수 있다.

 

* 반복문 사용하기

- for 문을 사용하여 반복문을 쓸 수 있다. 

- 기본 구문은 다음과 같다.

{% for user in users %}
	{{ user }}
{% endfor %}

- 이 구문에서 user 변수는 users 변수에 포함된 모든 값으로 대체되게 된다. 즉 리스트만 제공하면 알아서 그 리스트에서 변수를 하나씩 넣는다는 것이다.

 

 

* 반복문 예시1 - 직접 jinja2 템플릿에 변수를 정의하여 사용

vi template1.js

{% set numbers = [1,2,3,4,5,6,7,8,9,10] %}
{% for number in numbers %}
The number is {{ number }}
{% endfor %}


vi jinja2-template1.yml 

---
- hosts: all
  remote_user: devops
  become: true
  tasks:
    - template:
        src: jinja2.j2
        dest: /tmp/jinja2
        owner: root
        group: root
        mode: 0644

 

* 반복문 예시2  - 플레이북에서 직접 정의한 변수 사용

vi template2.js

{% for number in numbers %}
The number is {{ number }}
{% endfor %}

vi jinja2-template2.yml 

---
- hosts: all
  vars:
    numbers: 
      [1,2,3,4,5,6,7,8,9,10]
  remote_user: devops
  become: true
  tasks:
    - template:
        src: jinja2.j2
        dest: /tmp/jinja2
        owner: root
        group: root
        mode: 0644
로그인할 때 출력하는 motd파일 수정

vi motd.j2

this is the system {{ ansible_hostname }}.
today date is : {{ ansible_date_time.date }}.
only use this system with permission.
you can ask {{ system_owner }} for access.


vi motd.yml

---
- hosts: all
  vars:
    system_owner: clyde@example.com
  tasks:
    - template:
        src: motd.j2
        dest: /etc/motd
        owner: root
        group: root
        mode: 0644
로그인시 시스템 메모리 상태를 보여주기

vi motd2.j2

this system total memory is: {{ ansible_memtotal_mb }} MBs.
this current free memory is: {{ ansible_memfree_mb }} MBs.


vi motd2.yaml

---
- hosts: all
  remote_user: devops
  become: true
  tasks:
    - template:
        src: motd2.j2
        dest: /etc/motd
        owner: root
        group: root
        mode: 0644

- 참고로, 변수를 날짜로 하면 랜더링 할때만 날짜가 갱신되므로 이미 템플릿의 결과로 생성된 날짜는 고정되며 변동되지 않는다. 따라서 날짜를 표현하는데는 효과적이지 않다.

 

* 반복문 예시 - 매직변수 & 팩트 변수 사용

- 인벤토리의 모든 클라이언트를 대상으로 ip주소 확인하기

- groups 매직변수와 hostvars 매직변수를 사용한다. hostvars 매직변수에는 ansible_facts 변수가 포함된다. (gathring을 해야만 포함된다. gathering을 하지 않으면 포함되지 않는다)

gethring_ip.j2

{% for host in groups['all'] %}
HOST {{ hostvars[host]['ansible_facts']['hostname'] }} IPADDR : {{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }}
{% endfor %}

gathering_ip.yml

- name: jinja2 test
  hosts: all
  tasks:
    - name: jinja2 template
      template:
        src: /home/devops/ansible_test/template.j2
        dest: /tmp/jinja-template-test

# 참고 : 매직변수, 팩트변수 사용 시 참고

- 이렇게 여러개의 ansible host를 대상으로 팩트변수를 얻는 구문을 쓸 때는 ansible-playbook 여기에도 해당 호스트를 동일하게 명시해줘야 한다.

- 동일하게 명시하지 않으면 팩트변수가 제대로 수집되지 않아 에러가 발생한다.

- 예를들어, playbook에서는 web.example.com 하나만 했는데, 템플릿에서는 for 문으로 모든 클라이언트를 지정하면 안된다.

 

 

* loop.index

- loop.index는 반복을 1번 돌때마다 숫자 1을 증가시킨다. 즉 반복의 횟수를 보여준다.

{% for host in groups['all'] %}
HOST {{ hostvars[host]['ansible_facts']['hostname'] }} IPADDR : {{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }}
{{ loop.index }}
{% endfor %}

 

- 반복의 횟수에 따라 특정 구문을 실행하도록 할 때 사용할 수도 있고, 여러 방면에서 활용 가능하다.

 

 

 

jinja2 제어구조 - 조건문

템플릿 파일에서도 제어구조인 반복문, 조건문 등을 사용할 수 있다.

 

* 조건문 사용하기

- if 문을 사용하여 조건문을 만들 수 있다.

- 기본 구문은 다음과 같다.

{% if 조건문 %}
조건이 true인 경우 실행할 내용
{% endif %}

 

* 조건문 간단한 예시

- finished 변수의 값이 true일때만 result변수의 값을 찍어낸다.

{% if finished %}
{{ result }}
{% endif %}

 

# 참고 : 조건문과 반복문을 함께 사용할수도 있다.

{# for statement #}
{% for myuser in users if not myuser == "root" %}
User number {{loop.index}} - {{myuser }}
{% endfor %}

 

# 참고 : 템플릿에서는 jinja2 반복문과 조건문을 쓸 수 있지만, ansible-playbook에서는 사용할 수 없다.

 

 

 

변수 필터

- jinja2 에서는 템플릿 식에 대한 출력 형식을 변경할 수 있다. 이것을 필터라고 한다.

- 출력 형식은 yaml, json 등이 있다.

- 아래와 같이 여러 방식이 있으며, 필요한 방식대로 사용할 수 있다.

 

* 예시

vi template.j2

{{ hostvars['web.example.com'] | to_nice_json }}

- 이렇게 하면, hostvars['web.example.com']의 결과에 대해 to_nice_json 필터를 적용하는 것이다.

 

 

* 각 필터의 결과 예시

 

to_json : json 형식으로 보여준다.

 

to_yaml : yaml 형식으로 보여준다.

 

to_nice_json : json형식을 사람이 보기 편하게 보여준다.

 

to_nice_yaml : yaml 형식을 사람이 보기 편하게 보여준다.

 

 

 

 

참고 링크

 

jinja 테스트 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_tests.html 

 

Tests — Ansible Documentation

You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See the latest Ansible documentation. Tests in Jinja are a way o

docs.ansible.com

 

템플릿 - 원격 서버로 파일을 출력하는 템플릿 ansible 설명서

https://docs.ansible.com/ansible/2.7/modules/template_module.html 

 

template – Templates a file out to a remote server — Ansible Documentation

Docs » template – Templates a file out to a remote server You are reading an unmaintained version of the Ansible documentation. Unmaintained Ansible versions can contain unfixed security vulnerabilities (CVE). Please upgrade to a maintained version. See

docs.ansible.com

변수 ansible 설명서

https://docs.ansible.com/ansible/2.7/user_guide/playbooks_variables.html 

필터 및 ansible 설명서

https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html 

 

+ Recent posts