Struktur

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_playbook di site.yml sebagai orchestrator.
  • Ikuti urutan elemen play yang konsisten: hosts → become → vars → pre_tasks → roles → tasks → post_tasks → handlers.
  • import_tasks untuk file task statis (lebih dapat diprediksi); include_tasks untuk 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 →

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