Template (Jinja2)

Template (Jinja2) #

Template adalah cara Ansible menghasilkan file konfigurasi yang berbeda per host atau per lingkungan dari satu sumber yang sama. Sebuah template nginx yang sama bisa menghasilkan konfigurasi untuk server staging (port 80, debug mode on) maupun production (port 443, SSL enabled, debug mode off) — hanya dengan mengubah nilai variabelnya. Ansible menggunakan Jinja2 sebagai mesin template, bahasa yang sama yang digunakan oleh Flask dan Django.

Sintaks Dasar Jinja2 #

Jinja2 menggunakan tiga jenis sintaks:

{# Ini adalah komentar — tidak muncul di output #}

{{ variabel }}          {# Substitusi variabel #}

{% if kondisi %}        {# Blok kontrol (if, for, dll.) #}
  ...
{% endif %}

Contoh template sederhana:

{# templates/app.conf.j2 #}
[server]
host = {{ ansible_default_ipv4.address }}
port = {{ app_port }}
workers = {{ app_workers | default(4) }}
environment = {{ env }}

[database]
host = {{ db_host }}
port = {{ db_port | default(5432) }}
name = {{ db_name }}

Filter Jinja2 yang Paling Berguna #

Filter mengubah nilai variabel sebelum ditampilkan. Format: {{ nilai | filter }}:

{# Default value jika variabel tidak terdefinisi #}
{{ app_port | default(8080) }}

{# Konversi tipe #}
{{ some_number | int }}
{{ some_value | string }}
{{ some_value | bool }}
{{ some_list | list }}

{# Manipulasi string #}
{{ app_name | upper }}              {# APP_NAME #}
{{ app_name | lower }}              {# app_name #}
{{ " nginx " | trim }}              {# nginx #}
{{ "/etc/app" | basename }}         {# app #}
{{ "/etc/app/config.conf" | dirname }} {# /etc/app #}

{# Manipulasi list #}
{{ packages | join(', ') }}         {# package1, package2, package3 #}
{{ servers | length }}              {# jumlah item #}
{{ servers | first }}               {# item pertama #}
{{ servers | last }}                {# item terakhir #}
{{ servers | sort }}                {# diurutkan #}
{{ servers | unique }}              {# hapus duplikat #}

{# Kondisi dengan filter #}
{{ value | ternary('yes', 'no') }}  {# 'yes' jika value truthy, 'no' jika falsy #}

Kondisi dalam Template #

{# Kondisi sederhana #}
{% if nginx_ssl_enabled %}
listen 443 ssl;
ssl_certificate {{ nginx_ssl_cert }};
ssl_certificate_key {{ nginx_ssl_key }};
{% else %}
listen {{ nginx_port }};
{% endif %}

{# Kondisi dengan elif #}
{% if env == 'production' %}
log_level = warning
{% elif env == 'staging' %}
log_level = info
{% else %}
log_level = debug
{% endif %}

{# Kondisi untuk blok opsional #}
{% if nginx_access_log_enabled | default(true) %}
access_log {{ nginx_log_dir }}/access.log main;
{% else %}
access_log off;
{% endif %}

Loop dalam Template #

{# Iterasi list untuk generate konfigurasi #}
upstream backend {
{% for server in groups['appservers'] %}
    server {{ hostvars[server]['ansible_default_ipv4']['address'] }}:{{ app_port }} weight=1;
{% endfor %}
}

{# Loop dengan index #}
{% for vhost in virtual_hosts %}
server {
    listen {{ vhost.port }};
    server_name {{ vhost.domain }};
    
    location / {
        proxy_pass http://{{ vhost.upstream }};
    }
}
{% if not loop.last %}

{% endif %}
{% endfor %}

{# Iterasi dictionary #}
{% for key, value in app_config.items() %}
{{ key }} = {{ value }}
{% endfor %}

Template Multi-Host: Menggunakan hostvars #

Template yang paling powerful menggunakan informasi dari semua host, bukan hanya host yang sedang dikonfigurasi. Ini memungkinkan load balancer dikonfigurasi dengan otomatis menggunakan IP semua backend server:

{# templates/haproxy.cfg.j2 — konfigurasi HAProxy yang otomatis #}
global
    maxconn 50000

defaults
    timeout connect 5s
    timeout client 30s
    timeout server 30s

frontend http_front
    bind *:80
    default_backend http_back

backend http_back
    balance roundrobin
{% for host in groups['webservers'] %}
    server {{ host }} {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port }} check
{% endfor %}

Output yang dihasilkan (misalnya untuk 3 web server):

backend http_back
    balance roundrobin
    server web-01 10.0.1.10:8080 check
    server web-02 10.0.1.11:8080 check
    server web-03 10.0.1.12:8080 check
hostvars hanya berisi data untuk host yang sudah menjalankan Gathering Facts dalam run playbook yang sama. Pastikan semua host yang direferensikan sudah dieksekusi sebelum template yang menggunakan hostvars di-render.

Template yang Aman: Hindari Nilai Kosong #

Template yang tidak menangani nilai kosong bisa menghasilkan konfigurasi yang rusak:

{# ANTI-PATTERN: tidak menangani nilai kosong #}
db_password = {{ db_password }}
{# Jika db_password tidak terdefinisi: db_password = (kosong) — konfigurasi rusak #}

{# BENAR: gunakan default atau mandatory check #}
db_password = {{ db_password | mandatory }}
{# mandatory akan gagal dengan error yang jelas jika variabel tidak terdefinisi #}

{# Atau berikan nilai default yang aman #}
max_connections = {{ db_max_connections | default(100) | int }}
{# BENAR: validasi dan bersihkan nilai #}
server_name {{ nginx_server_name | lower | trim }};
listen {{ nginx_port | int }};
worker_processes {{ nginx_worker_processes | default('auto') }};

Memvalidasi Template Sebelum Deploy #

Banyak aplikasi (nginx, Apache, PostgreSQL) menyediakan perintah untuk memvalidasi file konfigurasi sebelum digunakan. Manfaatkan ini dengan parameter validate:

- name: Deploy konfigurasi nginx dari template
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
    validate: "nginx -t -c %s"    # Validasi sebelum disimpan
  notify: Reload nginx

- name: Deploy konfigurasi sudoers
  template:
    src: sudoers.j2
    dest: /etc/sudoers.d/myapp
    mode: '0440'
    validate: "visudo -cf %s"     # Validasi syntax sudoers

Jika validasi gagal, Ansible tidak akan menyimpan file dan task dianggap gagal — mencegah konfigurasi rusak masuk ke production.


Ringkasan #

  • Jinja2 menggunakan tiga sintaks: {{ }} untuk variabel, {% %} untuk kontrol flow, {# #} untuk komentar.
  • Filter seperti default(), int, join(), dan ternary() adalah alat terpenting untuk template yang robust.
  • Gunakan hostvars dalam template untuk mengakses informasi dari host lain — powerful untuk menggenerate konfigurasi load balancer dan service discovery.
  • | mandatory untuk variabel yang harus ada — template akan gagal dengan pesan yang jelas jika variabel tidak terdefinisi.
  • Gunakan parameter validate: di module template untuk memvalidasi file konfigurasi sebelum disimpan — mencegah konfigurasi rusak masuk ke server.
  • Untuk file konfigurasi yang kompleks, template selalu lebih baik dari lineinfile atau blockinfile — lebih mudah dibaca, lebih mudah di-maintain, dan lebih mudah di-review.

← Sebelumnya: Copy Module   Berikutnya: Drift Handling →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact