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
템플릿 - 원격 서버로 파일을 출력하는 템플릿 ansible 설명서
https://docs.ansible.com/ansible/2.7/modules/template_module.html
변수 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
'Ansible' 카테고리의 다른 글
16장. playbook에 파일 포함하기 및 가져오기 (0) | 2021.02.27 |
---|---|
15장. 병렬 구성 작업 (1) | 2021.02.27 |
13장. 작업 제어 구현 - 오류처리 (0) | 2021.02.25 |
12장. 작업 제어 구현 - 핸들러 (0) | 2021.02.24 |
11장. 작업 제어 구현 - 반복문과 조건문 (0) | 2021.02.23 |