るつぼっと

NWエンジニアな人たちに向けて

[Ansible] Jinja2テンプレートの役割と使い方

はじめに

AnsibleにおけるJinja2テンプレートの役割について自分なりの理解を纏めてみました。 Ansible触りたての方がイメージを掴む参考になれば幸いです。

AnsibleにおけるJinja2テンプレートとは

順を追って確認してみる。

そもそも、Jinja2テンプレートってなんなのか

Jinja2の公式サイトには下記のように掲げられている。

Jinja — Jinja Documentation (3.0.x)

Jinja is a fast, expressive, extensible templating engine. Special placeholders in the template allow writing code similar to Python syntax. Then the template is passed data to render the final document.

抑えたいのは下記の点。なお括弧内は勝手な補足。

  • Python用の)テンプレートエンジン
  • Pythonの構文に似た形で(変数や制御文を使った)コードが書ける
  • 受け取ったデータを(書かれたコードに従って)整形し文書として出力してくれる

じゃあ、AnsibleにおけるJinja2の役割ってなんなのか

Ansibleの公式サイトでは下記のように説明されている。

Templating (Jinja2) — Ansible Documentation

As already referenced in the variables section, Ansible uses Jinja2 templating to enable dynamic expressions and access to variables.

「AnsibleはJinja2テンプレートを使うことで動的な式や変数の参照を可能にする 」
という意味合いのことが書かれている。

ということは

以上を踏まえるとAnsibleにおけるJinja2テンプレートの役割は下記のとおりとなる。

Playbook記述形式であるYAMLは動的な式や変数の参照に対応していない。
それでは不便なのでJinja2テンプレートを用いてその仕組みを実装している。

どの箇所がJinja2テンプレートなのか

Jinja2テンプレートの役割は分かったけど、Playbookのどの箇所がJinja2なのか。
ざっくり言うと "{{ 文(変数等) }}""{% 式 %}" の書式で表される箇所になる。
一例を挙げてみる。

  • Playbook
---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: print
      debug:
        msg: “It's {{ season }}. An {{ name }} costs {{ cost }}vars:
        season: "winter"
        name:  "peach"
        cost: "{% if season == 'fall' %}100{% else %}200{% endif %} now."


  • 実行結果
TASK [print] ****************************************************
ok: [localhost] => 
  msg: “It's winter. An peach costs 200 now.”

このようになる。
Playbookでよく見る{{ }}の表記はYAMLというよりJinja2の構文なのです。

Jinja2構文の色々な使い方

上記のようにPlaybook内に構文を直接記載する以外にも幾つかの使い方がある。

外部ファイルに記述されたJInja2構文を使う

Ansibleのlookupプラグインにより、外部ファイルに記述されたJinja2構文を利用できる。

docs.ansible.com

  • Playbook
---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: print
      debug:
        msg: “It's {{ season }}. An {{ name }} costs {{ cost }}vars:
        season: "winter"
        name:  "peach"
        cost: "{{ lookup('template', './test.j2') }}"


  • jinja2テンプレートファイル
$ more test.j2 
{% if season == 'fall' %}100{% else %}200{% endif %} now.

Playbook内に記述する場合と違い、全体をダブルクォートで囲む必要はない。

  • 実行結果
TASK [print] ****************************************************
ok: [localhost] => 
  msg: “It's winter. An peach costs 200 now.”

複雑な構文になる場合は外部ファイルへ切り出したほうが
Playbook自体は簡潔になる。

Jinja2の処理結果を外部ファイルへ出力する

これまでは処理結果をPlaybook内で利用していたが、
外部ファイルへ出力することもできる。

docs.ansible.com

  • Playbook
---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: Output to file
      template:
        src: ./test.j2
        dest: ./test.txt
      vars:
        season: "winter"
        name:  "peach"


  • jinja2テンプレートファイル
$ more test.j2 
It's {{ season }}.
An {{ name }} costs {% if season == 'fall' %}10{% else %}20{% endif %} now.


  • 実行結果
TASK [Output to file] **********************************************
changed: [localhost]
$ more test.txt 
It's winter.
An peach costs 20 now.

Taskの実行結果を整形してログとして保存したい場合などに有用。

所感

学び始めのころは全く知識がなく、YAMLとJinja2の区別も
ついていなかったので記事に起こしてみました。