Struktur #
Playbook yang bekerja dan playbook yang baik adalah dua hal yang berbeda. Playbook yang bekerja menghasilkan output yang diinginkan. Playbook yang baik juga bisa dipahami oleh orang lain, mudah di-debug saat ada yang salah, dan tidak menjadi mimpi buruk saat perlu dimodifikasi enam bulan kemudian. Artikel ini membahas bagaimana menyusun playbook agar bisa bertahan dalam jangka panjang.
Satu File, Satu Tanggung Jawab #
Anti-pattern yang paling umum adalah satu playbook monolitik yang melakukan segalanya — install semua software, konfigurasi semua service, deploy semua aplikasi. Playbook seperti ini sulit di-debug dan tidak bisa digunakan secara parsial.
# ANTI-PATTERN: satu playbook untuk segalanya
# site.yml — 500+ baris, semua ada di sini
- name: Setup semua server
hosts: all
tasks:
- name: Install nginx
...
- name: Install postgresql
...
- name: Deploy aplikasi
...
- name: Setup monitoring
...
# BENAR: pisahkan berdasarkan tanggung jawab
# playbooks/webservers.yml — hanya untuk web server
# playbooks/dbservers.yml — hanya untuk database
# playbooks/deploy-app.yml — hanya untuk deployment aplikasi
# playbooks/site.yml — orchestrator yang memanggil semua playbook
# playbooks/site.yml
---
- import_playbook: webservers.yml
- import_playbook: dbservers.yml
- import_playbook: monitoring.yml
Struktur Internal Play yang Baik #
Urutan elemen dalam sebuah play mempengaruhi keterbacaan. Ikuti urutan yang konsisten:
---
- name: Deskripsi play yang jelas
hosts: webservers # 1. Target host
become: true # 2. Privilege escalation
gather_facts: true # 3. Facts gathering
vars: # 4. Variabel play (jika ada)
app_version: "2.1.0"
deploy_path: /opt/app
pre_tasks: # 5. Task yang dijalankan SEBELUM roles
- name: Pastikan sistem up-to-date
apt:
update_cache: true
cache_valid_time: 3600
roles: # 6. Roles (jika digunakan)
- common
- nginx
tasks: # 7. Task utama
- name: Deploy konfigurasi aplikasi
template:
src: app.conf.j2
dest: /etc/app/app.conf
post_tasks: # 8. Task yang dijalankan SETELAH semua task selesai
- name: Verifikasi aplikasi berjalan
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
handlers: # 9. Handler di akhir
- name: Restart aplikasi
systemd:
name: myapp
state: restarted
import_playbook vs include_playbook #
Ada dua cara memanggil playbook lain dari dalam playbook:
# import_playbook — diproses saat playbook dimuat (static)
# Semua play di-import sebelum eksekusi dimulai
- import_playbook: webservers.yml
- import_playbook: dbservers.yml
# include_playbook — diproses saat dieksekusi (dynamic)
# Play di-include saat baris ini dieksekusi
- include_playbook: webservers.yml
when: deploy_web | bool
Untuk sebagian besar kasus, import_playbook lebih disukai karena lebih dapat diprediksi dan lebih mudah di-debug. Gunakan include_playbook hanya saat kamu membutuhkan kondisi dinamis.
import_tasks vs include_tasks #
Hal yang sama berlaku untuk task — ada dua cara memasukkan file task eksternal:
tasks:
# import_tasks: diproses saat playbook dimuat (static)
# Tags dan kondisi berlaku untuk semua task yang diimport
- import_tasks: tasks/install.yml
- import_tasks: tasks/configure.yml
# include_tasks: diproses saat dieksekusi (dynamic)
# Berguna saat file task ditentukan oleh variabel
- include_tasks: "tasks/{{ ansible_os_family }}.yml"
# tasks/install.yml — file task yang berdiri sendiri
---
- name: Install nginx
apt:
name: nginx
state: present
- name: Install certbot
apt:
name: certbot
state: present
Memisahkan task ke file-file terpisah (install, configure, deploy, verify) membuat playbook lebih mudah dikelola dan memungkinkan penggunaan ulang task di konteks yang berbeda.
Penamaan Task yang Baik #
Nama task adalah bagian terpenting dari keterbacaan playbook. Nama yang baik menjelaskan tujuan, bukan mekanisme:
# ANTI-PATTERN: nama yang menjelaskan mekanisme, bukan tujuan
- name: apt install nginx
apt:
name: nginx
state: present
- name: copy file
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
# BENAR: nama yang menjelaskan tujuan
- name: Install nginx sebagai web server
apt:
name: nginx
state: present
- name: Deploy konfigurasi nginx dari template
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
Nama task yang baik juga memudahkan penggunaan --start-at-task dan --tags saat debugging.
Penggunaan Tags #
Tags memungkinkan kamu menjalankan hanya subset task dari playbook tanpa memodifikasi file:
tasks:
- name: Install nginx
apt:
name: nginx
state: present
tags:
- install
- nginx
- name: Deploy konfigurasi nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- configure
- nginx
- name: Deploy kode aplikasi
git:
repo: https://github.com/org/app.git
dest: /opt/app
tags:
- deploy
- app
# Jalankan hanya task dengan tag "deploy"
ansible-playbook -i inventory/ site.yml --tags deploy
# Jalankan semua task kecuali yang bertag "install"
ansible-playbook -i inventory/ site.yml --skip-tags install
# List semua tags yang ada di playbook
ansible-playbook -i inventory/ site.yml --list-tags
Handlers: Satu Kali Meski Di-notify Berkali-kali #
Handler adalah task khusus yang hanya dijalankan saat di-notify oleh task lain — dan hanya dijalankan sekali di akhir play, tidak peduli berapa kali di-notify.
tasks:
- name: Deploy konfigurasi nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Reload nginx # Trigger handler ini
- name: Deploy SSL certificate
copy:
src: files/app.crt
dest: /etc/ssl/certs/app.crt
notify: Reload nginx # Handler yang sama di-notify dua kali...
handlers:
- name: Reload nginx
systemd:
name: nginx
state: reloaded
# ...tapi hanya dijalankan SEKALI di akhir play
Ini adalah perilaku yang diinginkan — jika lima task berbeda mengubah konfigurasi nginx, kamu tidak ingin nginx di-reload lima kali. Satu kali di akhir sudah cukup.
Ringkasan #
- Satu file, satu tanggung jawab — pisahkan playbook berdasarkan fungsi, gunakan
import_playbookdisite.ymlsebagai orchestrator.- Ikuti urutan elemen play yang konsisten: hosts → become → vars → pre_tasks → roles → tasks → post_tasks → handlers.
import_tasksuntuk file task statis (lebih dapat diprediksi);include_tasksuntuk file task dinamis (nama file dari variabel).- Nama task menjelaskan tujuan, bukan mekanisme — “Deploy konfigurasi nginx” lebih baik dari “copy file”.
- Tags memungkinkan eksekusi parsial tanpa memodifikasi playbook — berguna untuk deployment cepat atau debugging.
- Handler hanya dijalankan sekali di akhir play meski di-notify berkali-kali — ideal untuk reload/restart service.
← Sebelumnya: Apa itu Playbook? Berikutnya: Task & Module Execution →