Ansible Jinja2 템플릿

AnsibleBeginner
지금 연습하기

소개

이 랩에서는 Ansible 에서 사용되는 강력한 템플릿 엔진인 Jinja2 를 탐구합니다. Jinja2 를 사용하면 동적 콘텐츠를 생성하여 Ansible 플레이북의 유연성과 적응성을 높일 수 있습니다. 이 랩을 마치면 변수, 필터, 조건문 및 루프를 포함하여 Ansible 에서 Jinja2 구문을 사용하는 방법을 이해하게 됩니다. 이 지식을 통해 더욱 동적이고 효율적인 Ansible 플레이북과 역할을 만들 수 있습니다.

이것은 가이드 실험입니다. 학습과 실습을 돕기 위한 단계별 지침을 제공합니다.각 단계를 완료하고 실무 경험을 쌓기 위해 지침을 주의 깊게 따르세요. 과거 데이터에 따르면, 이것은 초급 레벨의 실험이며 완료율은 88%입니다.학습자들로부터 97%의 긍정적인 리뷰율을 받았습니다.

Jinja2 기본 이해

Jinja2 는 Django 의 템플릿을 모델로 한 Python 용 현대적이고 디자이너 친화적인 템플릿 언어입니다. Ansible 에서 Jinja2 는 파일을 템플릿화하고, 동적 플레이 구조를 만드는 등 다양한 용도로 사용됩니다.

간단한 Jinja2 템플릿을 만들어 보겠습니다. 먼저, 프로젝트 디렉토리로 이동합니다.

cd ~/project

이제 템플릿을 위한 디렉토리를 만들어 보겠습니다.

mkdir templates
cd templates

hello.j2라는 새 파일을 만듭니다.

nano hello.j2

다음 내용을 추가합니다.

Hello, {{ name }}!

Today is {{ ansible_date_time.date }}.
Your home directory is {{ ansible_env.HOME }}.

nano 편집기를 저장하고 종료합니다 (Ctrl+X, Y, Enter).

이 템플릿에서:

  • {{ name }}은 템플릿이 렌더링될 때 실제 값으로 대체될 변수입니다.
  • {{ ansible_date_time.date }}{{ ansible_env.HOME }}은 자동으로 채워질 Ansible 팩트 (fact) 입니다.

이제 이 템플릿을 사용하기 위한 플레이북을 만들어 보겠습니다. 프로젝트 루트로 돌아가서 use_template.yml이라는 새 파일을 만듭니다.

cd ~/project
nano use_template.yml

다음 내용을 추가합니다.

---
- name: Use Jinja2 template
  hosts: localhost
  vars:
    name: "Ansible Learner"
  tasks:
    - name: Create file from template
      template:
        src: templates/hello.j2
        dest: /tmp/hello.txt

이 플레이북은 template 모듈을 사용하여 Jinja2 템플릿을 렌더링하고 /tmp/hello.txt에 파일을 생성합니다.

플레이북을 실행합니다.

ansible-playbook use_template.yml

플레이북을 실행한 후, 생성된 파일의 내용을 확인합니다.

cat /tmp/hello.txt

변수와 팩트가 실제 값으로 대체된 렌더링된 템플릿을 볼 수 있습니다.

Jinja2 필터 사용

Jinja2 필터는 변수에 적용할 수 있는 함수입니다. 파이프 기호 (|) 로 변수와 구분됩니다. Ansible 에는 많은 내장 필터가 포함되어 있으며, 사용자 정의 필터도 만들 수 있습니다.

몇 가지 일반적인 필터를 보여주는 새 템플릿을 만들어 보겠습니다. filters.j2라는 새 파일을 만듭니다.

cd ~/project/templates
nano filters.j2

다음 내용을 추가합니다.

1. Uppercase filter: {{ name | upper }}
2. Length filter: {{ name | length }}
3. Default filter: {{ optional_var | default('No value provided') }}
4. Join filter: {{ fruits | join(', ') }}
5. Random item: {{ fruits | random }}
6. First item: {{ fruits | first }}
7. JSON encode: {{ complex_data | to_json }}

이제 이 템플릿을 사용하기 위한 플레이북을 만들어 보겠습니다. 프로젝트 루트로 돌아가서 use_filters.yml이라는 새 파일을 만듭니다.

cd ~/project
nano use_filters.yml

다음 내용을 추가합니다.

---
- name: Use Jinja2 filters
  hosts: localhost
  vars:
    name: "ansible learner"
    fruits:
      - apple
      - banana
      - cherry
    complex_data:
      key1: value1
      key2:
        - item1
        - item2
  tasks:
    - name: Create file from template
      template:
        src: templates/filters.j2
        dest: /tmp/filters.txt

    - name: Display file contents
      command: cat /tmp/filters.txt
      register: file_contents

    - name: Show file contents
      debug:
        var: file_contents.stdout_lines

이 플레이북은 다양한 Jinja2 필터를 변수에 적용하고 결과를 표시합니다.

플레이북을 실행합니다.

ansible-playbook use_filters.yml

출력 결과는 각 필터가 입력 데이터를 어떻게 수정하는지 보여줍니다. 이는 필터가 템플릿 내에서 데이터를 조작하는 데 어떻게 사용될 수 있는지를 보여줍니다.

Jinja2 조건문 사용

Jinja2 를 사용하면 템플릿에서 조건문을 사용할 수 있습니다. 이는 특정 조건에 따라 콘텐츠를 포함하거나 제외해야 할 때 특히 유용합니다.

conditionals.j2라는 새 템플릿 파일을 만듭니다.

cd ~/project/templates
nano conditionals.j2

다음 내용을 추가합니다.

{% if user_type == 'admin' %}
Welcome, Administrator!
You have full access to the system.
{% elif user_type == 'user' %}
Welcome, User!
You have limited access to the system.
{% else %}
Welcome, Guest!
You have read-only access to the system.
{% endif %}

{% if fruits %}
Available fruits:
{% for fruit in fruits %}
  - {{ fruit }}
{% endfor %}
{% else %}
No fruits available.
{% endif %}

이제 이 템플릿을 사용하기 위한 플레이북을 만들어 보겠습니다. 프로젝트 루트로 돌아가서 use_conditionals.yml이라는 새 파일을 만듭니다.

cd ~/project
nano use_conditionals.yml

다음 내용을 추가합니다.

---
- name: Use Jinja2 conditionals
  hosts: localhost
  vars:
    user_type: "admin"
    fruits:
      - apple
      - banana
      - cherry
  tasks:
    - name: Create file from template (admin)
      template:
        src: templates/conditionals.j2
        dest: /tmp/conditionals_admin.txt

    - name: Create file from template (user)
      template:
        src: templates/conditionals.j2
        dest: /tmp/conditionals_user.txt
      vars:
        user_type: "user"

    - name: Create file from template (guest)
      template:
        src: templates/conditionals.j2
        dest: /tmp/conditionals_guest.txt
      vars:
        user_type: "guest"
        fruits: []

    - name: Display file contents
      command: "cat {{ item }}"
      loop:
        - /tmp/conditionals_admin.txt
        - /tmp/conditionals_user.txt
        - /tmp/conditionals_guest.txt
      register: file_contents

    - name: Show file contents
      debug:
        var: file_contents.results[item].stdout_lines
      loop: [0, 1, 2]

이 플레이북은 동일한 템플릿을 사용하지만 다른 변수 값을 사용하여 세 개의 다른 파일을 생성하여 템플릿의 조건문이 어떻게 작동하는지 보여줍니다.

플레이북을 실행합니다.

ansible-playbook use_conditionals.yml

출력 결과는 템플릿 내용이 다른 조건에 따라 어떻게 변경되는지 보여줍니다.

Jinja2 루프 사용법

Jinja2 는 리스트 (list) 와 딕셔너리 (dictionary) 를 반복 처리할 수 있는 루프 구문을 제공합니다. 이는 변수 데이터를 기반으로 반복적인 콘텐츠를 생성해야 할 때 특히 유용합니다.

loops.j2라는 새 템플릿 파일을 만듭니다.

cd ~/project/templates
nano loops.j2

다음 내용을 추가합니다.

1. Simple loop:
{% for item in simple_list %}
   - {{ item }}
{% endfor %}

2. Loop with index:
{% for item in simple_list %}
   {{ loop.index }}. {{ item }}
{% endfor %}

3. Loop over a dictionary:
{% for key, value in simple_dict.items() %}
   {{ key }}: {{ value }}
{% endfor %}

4. Nested loop:
{% for category, items in nested_dict.items() %}
   {{ category }}:
   {% for item in items %}
     - {{ item }}
   {% endfor %}
{% endfor %}

5. Conditional in loop:
{% for item in simple_list %}
   {% if loop.first %}First item: {% endif %}
   {% if loop.last %}Last item: {% endif %}
   {{ item }}
{% endfor %}

이제 이 템플릿을 사용하기 위한 플레이북을 만들어 보겠습니다. 프로젝트 루트로 돌아가서 use_loops.yml이라는 새 파일을 만듭니다.

cd ~/project
nano use_loops.yml

다음 내용을 추가합니다.

---
- name: Use Jinja2 loops
  hosts: localhost
  vars:
    simple_list:
      - apple
      - banana
      - cherry
    simple_dict:
      name: John Doe
      age: 30
      city: New York
    nested_dict:
      fruits:
        - apple
        - banana
      vegetables:
        - carrot
        - potato
  tasks:
    - name: Create file from template
      template:
        src: templates/loops.j2
        dest: /tmp/loops.txt

    - name: Display file contents
      command: cat /tmp/loops.txt
      register: file_contents

    - name: Show file contents
      debug:
        var: file_contents.stdout_lines

이 플레이북은 Jinja2 템플릿에서 루프를 사용하는 다양한 방법을 보여줍니다.

플레이북을 실행합니다.

ansible-playbook use_loops.yml

출력 결과는 템플릿의 다양한 루프 구문이 제공된 변수를 기반으로 어떻게 콘텐츠를 생성하는지 보여줍니다.

Jinja2 고급 기술

이 마지막 단계에서는 매크로 (macros) 와 필터 (filters) 를 포함한 몇 가지 고급 Jinja2 기술을 살펴보겠습니다. 매크로는 프로그래밍 언어의 함수와 유사한 재사용 가능한 템플릿 조각입니다.

advanced.j2라는 새 템플릿 파일을 만듭니다.

cd ~/project/templates
nano advanced.j2

다음 내용을 추가합니다.

{% macro render_list(title, items) %}
{{ title }}:
{% for item in items %}
  - {{ item }}
{% endfor %}
{% endmacro %}

1. Using a macro:
{{ render_list("Fruits", fruits) }}

{{ render_list("Vegetables", vegetables) }}

2. Using set:
{% set greeting = "Hello, " + name + "!" %}
{{ greeting }}

3. Custom filter (defined in playbook):
{{ complex_data | to_nice_json }}

4. Whitespace control:
{% for item in fruits -%}
    {{ item }}
{%- if not loop.last %}, {% endif %}
{%- endfor %}

5. Raw block (no processing):
{% raw %}
This {{ will_not_be_processed }}
{% endraw %}

6. Include another template:
{% include 'simple_include.j2' %}

이제 간단한 include 파일을 만들어 보겠습니다. simple_include.j2라는 새 파일을 만듭니다.

nano simple_include.j2

다음 내용을 추가합니다.

This is content from an included template.
Current user: {{ ansible_user_id }}

이제 이 고급 템플릿을 사용하기 위한 플레이북을 만들어 보겠습니다. 프로젝트 루트로 돌아가서 use_advanced.yml이라는 새 파일을 만듭니다.

cd ~/project
nano use_advanced.yml

다음 내용을 추가합니다.

---
- name: Use advanced Jinja2 techniques
  hosts: localhost
  vars:
    name: "Ansible Expert"
    fruits:
      - apple
      - banana
      - cherry
    vegetables:
      - carrot
      - potato
      - broccoli
    complex_data:
      key1: value1
      key2:
        - item1
        - item2
    custom_filters:
      to_nice_json: "{{ '(' ~ ((complex_data | to_json) | replace('\"', '\\\"')) ~ ')' | from_json | to_nice_json }}"
  tasks:
    - name: Create file from template
      template:
        src: templates/advanced.j2
        dest: /tmp/advanced.txt

    - name: Display file contents
      command: cat /tmp/advanced.txt
      register: file_contents

    - name: Show file contents
      debug:
        var: file_contents.stdout_lines

이 플레이북은 매크로, 사용자 정의 필터, 공백 제어 및 다른 템플릿 포함을 포함한 고급 Jinja2 기술을 보여줍니다.

플레이북을 실행합니다.

ansible-playbook use_advanced.yml

출력 결과는 이러한 고급 Jinja2 기술이 실제로 어떻게 작동하는지 보여줍니다.

요약

이 랩에서는 Ansible 에서 Jinja2 템플릿을 탐구하여 광범위한 기능과 기술을 다루었습니다. 다음은 주요 내용입니다.

  1. 기본 Jinja2 구문: 템플릿에서 변수와 Ansible 팩트 (facts) 를 사용하는 방법을 배웠습니다.
  2. Jinja2 필터 (filters): 템플릿 내에서 데이터를 조작하기 위해 다양한 내장 필터를 탐구했습니다.
  3. 조건문: if-elif-else 문을 사용하여 조건에 따라 동적 콘텐츠를 만들었습니다.
  4. 루프 (loops): 중첩 루프 (nested loops) 및 루프 제어를 포함하여 목록과 딕셔너리를 반복하는 방법을 배웠습니다.
  5. 고급 기술: 매크로, 사용자 정의 필터, 공백 제어, raw 블록 (blocks) 및 템플릿 포함을 탐구했습니다.

이러한 Jinja2 기능을 사용하면 Ansible 에서 매우 동적이고 유연한 템플릿을 만들 수 있습니다. 이를 통해 다양한 시나리오와 데이터 입력에 적응할 수 있는 구성 파일, 스크립트 및 기타 콘텐츠를 생성할 수 있습니다.

Ansible 작업을 계속하면서 Jinja2 템플릿을 마스터하는 것이 효율적이고 적응 가능한 플레이북 (playbooks) 과 롤 (roles) 을 만드는 데 매우 중요하다는 것을 알게 될 것입니다. 이를 통해 더 간결하고 유지 관리 가능한 코드를 작성하여 반복을 줄이고 Ansible 프로젝트의 확장성을 높일 수 있습니다.

Jinja2 가 강력하지만 유연성과 가독성의 균형을 맞추는 것이 중요합니다. 지나치게 복잡한 템플릿은 유지 관리가 어려울 수 있으므로 템플릿 디자인에서 항상 명확성을 추구하십시오.

Ansible 프로젝트에서 이러한 Jinja2 기능을 연습하면 점점 더 복잡한 자동화 작업을 쉽게 처리할 수 있습니다.