Ansible Jinja2 模板

AnsibleAnsibleBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在本实验中,你将探索 Jinja2,这是 Ansible 使用的强大模板引擎。Jinja2 允许你创建动态内容,使你的 Ansible playbook 更加灵活和适应性强。通过本实验,你将了解如何在 Ansible 中使用 Jinja2 语法,包括变量、过滤器、条件语句和循环。这些知识将使你能够创建更加动态和高效的 Ansible playbook 和角色。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL ansible(("`Ansible`")) -.-> ansible/ModuleOperationsGroup(["`Module Operations`"]) ansible(("`Ansible`")) -.-> ansible/PlaybookEssentialsGroup(["`Playbook Essentials`"]) ansible/ModuleOperationsGroup -.-> ansible/template("`Generate Files from Templates`") ansible/PlaybookEssentialsGroup -.-> ansible/loop("`Iteration`") ansible/PlaybookEssentialsGroup -.-> ansible/playbook("`Execute Playbook`") subgraph Lab Skills ansible/template -.-> lab-390470{{"`Ansible Jinja2 模板`"}} ansible/loop -.-> lab-390470{{"`Ansible Jinja2 模板`"}} ansible/playbook -.-> lab-390470{{"`Ansible Jinja2 模板`"}} end

理解 Jinja2 基础

Jinja2 是一种现代且对设计者友好的 Python 模板语言,其设计灵感来源于 Django 的模板系统。在 Ansible 中,Jinja2 被用于模板化文件、创建动态的 play 结构等。

让我们从创建一个简单的 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 事实(facts),它们会被自动填充。

现在,让我们创建一个 playbook 来使用这个模板。回到项目根目录并创建一个名为 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

这个 playbook 使用 template 模块来渲染我们的 Jinja2 模板,并在 /tmp/hello.txt 处创建一个文件。

运行 playbook:

ansible-playbook use_template.yml

运行 playbook 后,检查生成文件的内容:

cat /tmp/hello.txt

你应该会看到渲染后的模板,其中的变量和事实已被实际值替换。

使用 Jinja2 过滤器

Jinja2 过滤器是可以应用于变量的函数。它们通过管道符号(|)与变量分隔。Ansible 包含许多内置过滤器,你也可以创建自定义过滤器。

让我们创建一个新模板来演示一些常见的过滤器。创建一个名为 filters.j2 的新文件:

cd ~/project/templates
nano filters.j2

添加以下内容:

1. 大写过滤器:{{ name | upper }}
2. 长度过滤器:{{ name | length }}
3. 默认过滤器:{{ optional_var | default('未提供值') }}
4. 连接过滤器:{{ fruits | join(', ') }}
5. 随机项:{{ fruits | random }}
6. 第一项:{{ fruits | first }}
7. JSON 编码:{{ complex_data | to_json }}

现在,让我们创建一个 playbook 来使用这个模板。回到项目根目录并创建一个名为 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

这个 playbook 将各种 Jinja2 过滤器应用于我们的变量并显示结果。

运行 playbook:

ansible-playbook use_filters.yml

输出将显示每个过滤器如何修改输入数据。这展示了如何在模板中使用过滤器来操作数据。

Jinja2 条件语句

Jinja2 允许你在模板中使用条件语句。这在需要根据某些条件包含或排除内容时特别有用。

创建一个名为 conditionals.j2 的新模板文件:

cd ~/project/templates
nano conditionals.j2

添加以下内容:

{% if user_type == 'admin' %}
欢迎,管理员!
你拥有系统的完全访问权限。
{% elif user_type == 'user' %}
欢迎,用户!
你拥有系统的有限访问权限。
{% else %}
欢迎,访客!
你拥有系统的只读访问权限。
{% endif %}

{% if fruits %}
可用水果:
{% for fruit in fruits %}
  - {{ fruit }}
{% endfor %}
{% else %}
没有可用的水果。
{% endif %}

现在,让我们创建一个 playbook 来使用这个模板。回到项目根目录并创建一个名为 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]

这个 playbook 使用相同的模板但不同的变量值创建了三个不同的文件,展示了模板中条件语句的工作原理。

运行 playbook:

ansible-playbook use_conditionals.yml

输出将显示模板内容如何根据不同的条件而变化。

Jinja2 循环

Jinja2 提供了循环结构,允许你遍历列表和字典。这在需要基于变量数据生成重复内容时特别有用。

创建一个名为 loops.j2 的新模板文件:

cd ~/project/templates
nano loops.j2

添加以下内容:

1. 简单循环:
{% for item in simple_list %}
   - {{ item }}
{% endfor %}

2. 带索引的循环:
{% for item in simple_list %}
   {{ loop.index }}. {{ item }}
{% endfor %}

3. 遍历字典:
{% for key, value in simple_dict.items() %}
   {{ key }}: {{ value }}
{% endfor %}

4. 嵌套循环:
{% for category, items in nested_dict.items() %}
   {{ category }}:
   {% for item in items %}
     - {{ item }}
   {% endfor %}
{% endfor %}

5. 循环中的条件语句:
{% for item in simple_list %}
   {% if loop.first %}第一项:{% endif %}
   {% if loop.last %}最后一项:{% endif %}
   {{ item }}
{% endfor %}

现在,让我们创建一个 playbook 来使用这个模板。回到项目根目录并创建一个名为 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

这个 playbook 展示了在 Jinja2 模板中使用循环的各种方式。

运行 playbook:

ansible-playbook use_loops.yml

输出将显示模板中不同循环结构如何根据提供的变量生成内容。

高级 Jinja2 技术

在最后一步中,我们将探索一些高级 Jinja2 技术,包括宏(macros)和过滤器。宏是可重用的模板片段,类似于编程语言中的函数。

创建一个名为 advanced.j2 的新模板文件:

cd ~/project/templates
nano advanced.j2

添加以下内容:

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

1. 使用宏:
{{ render_list("水果", fruits) }}

{{ render_list("蔬菜", vegetables) }}

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

3. 自定义过滤器(在 playbook 中定义):
{{ complex_data | to_nice_json }}

4. 空白控制:
{% for item in fruits -%}
    {{ item }}
{%- if not loop.last %}, {% endif %}
{%- endfor %}

5. 原始块(不进行处理):
{% raw %}
This {{ will_not_be_processed }}
{% endraw %}

6. 包含另一个模板:
{% include 'simple_include.j2' %}

现在,让我们创建简单的包含文件。创建一个名为 simple_include.j2 的新文件:

nano simple_include.j2

添加以下内容:

这是来自包含模板的内容。
当前用户:{{ ansible_user_id }}

现在,让我们创建一个 playbook 来使用这个高级模板。回到项目根目录并创建一个名为 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

这个 playbook 展示了高级 Jinja2 技术,包括宏、自定义过滤器、空白控制以及包含其他模板。

运行 playbook:

ansible-playbook use_advanced.yml

输出将展示这些高级 Jinja2 技术在实际中的应用。

总结

在本实验中,你探索了 Ansible 中的 Jinja2 模板技术,涵盖了广泛的功能和技巧。以下是关键要点:

  1. 基本 Jinja2 语法:你学习了如何在模板中使用变量和 Ansible 事实(facts)。
  2. Jinja2 过滤器:你探索了各种内置过滤器,以在模板中操作数据。
  3. 条件语句:你使用 if-elif-else 语句根据条件创建动态内容。
  4. 循环:你学习了如何遍历列表和字典,包括嵌套循环和循环控制。
  5. 高级技术:你探索了宏、自定义过滤器、空白控制、原始块和模板包含。

这些 Jinja2 功能使你能够在 Ansible 中创建高度动态和灵活的模板。它们使你能够生成配置文件、脚本和其他内容,以适应不同的场景和数据输入。

随着你继续使用 Ansible,你会发现掌握 Jinja2 模板技术对于创建高效且适应性强的 playbook 和角色至关重要。它使你能够编写更简洁、更易维护的代码,减少重复并使你的 Ansible 项目更具可扩展性。

请记住,虽然 Jinja2 功能强大,但在灵活性和可读性之间取得平衡非常重要。过于复杂的模板可能难以维护,因此始终要在模板设计中追求清晰性。

在你的 Ansible 项目中练习使用这些 Jinja2 功能,你将能够轻松处理日益复杂的自动化任务。

您可能感兴趣的其他 Ansible 教程