Task & Module Execution #
Menulis task dalam playbook adalah satu hal — memahami bagaimana Ansible benar-benar mengeksekusi task tersebut di balik layar adalah hal lain. Pengetahuan ini sangat berguna saat debugging eksekusi yang lambat, memahami mengapa urutan task penting, atau menjelaskan perilaku yang tidak terduga saat ada task yang gagal. Artikel ini membahas mekanisme eksekusi task dan module dari sudut pandang yang praktis.
Bagaimana Task Dieksekusi: Linear Strategy #
Secara default, Ansible menggunakan linear strategy — setiap task diselesaikan di semua host sebelum task berikutnya dimulai:
Task 1: Install nginx
├── Eksekusi di web-01 ✓
├── Eksekusi di web-02 ✓
└── Eksekusi di web-03 ✓
↓ (semua host selesai Task 1)
Task 2: Deploy konfigurasi nginx
├── Eksekusi di web-01 ✓
├── Eksekusi di web-02 ✓
└── Eksekusi di web-03 ✓
↓ (semua host selesai Task 2)
Task 3: Start nginx service
├── Eksekusi di web-01 ✓
├── Eksekusi di web-02 ✓
└── Eksekusi di web-03 ✓
Jika satu host gagal di Task 1, host tersebut dikeluarkan dari eksekusi selanjutnya — tapi host lain tetap melanjutkan ke Task 2.
Paralelisme dan Forks #
Meski menggunakan linear strategy, Ansible tidak menunggu satu host selesai sebelum mulai ke host berikutnya dalam task yang sama. Ansible mengelola paralelisme via forks:
Forks = 3, target = 6 host
Task 1: Install nginx
Batch 1 (paralel): web-01, web-02, web-03 ← dieksekusi bersamaan
Batch 2 (paralel): web-04, web-05, web-06 ← dieksekusi setelah Batch 1 selesai
Task 2: Deploy config
Batch 1 (paralel): web-01, web-02, web-03
Batch 2 (paralel): web-04, web-05, web-06
Nilai forks dikonfigurasi di ansible.cfg:
[defaults]
forks = 10 # Default: 5
Free Strategy #
Sebagai alternatif linear, Ansible menyediakan free strategy di mana setiap host berjalan secepat mungkin tanpa menunggu host lain:
- name: Deploy aplikasi (tiap host secepat mungkin)
hosts: webservers
strategy: free # ← aktifkan free strategy
tasks:
- name: Pull kode terbaru
git:
repo: https://github.com/org/app.git
dest: /opt/app
Free strategy — tiap host berjalan independen:
web-01: Task 1 → Task 2 → Task 3 → selesai
web-02: Task 1 → Task 2 → Task 3 → selesai
web-03: Task 1 → Task 2 → Task 3 → selesai
(host yang lebih cepat menyelesaikan lebih dulu tanpa menunggu)
Free strategy cocok saat task-task dalam play tidak bergantung satu sama lain dan kamu ingin menyelesaikan eksekusi secepat mungkin. Tapi gunakan dengan hati-hati — tanpa sinkronisasi antar host, sulit memastikan semua host dalam kondisi yang sama di titik waktu tertentu.
Bagaimana Module Dikirim dan Dieksekusi #
Setiap kali task dieksekusi, Ansible melakukan langkah-langkah berikut:
1. Ansible mengambil kode module (misalnya: apt.py)
│
2. Ansible menggabungkan module dengan argumen yang diberikan
│
3. Kode Python hasil gabungan dikirim ke managed node via SSH/SFTP
│
4. Module dieksekusi di managed node menggunakan Python
│
5. Hasil eksekusi (JSON) dikirim kembali ke control node
│
6. Ansible mengurai hasil dan menentukan status: ok / changed / failed
│
7. File sementara di managed node dibersihkan
Seluruh proses ini terjadi untuk setiap task di setiap host. Inilah mengapa mengaktifkan SSH pipelining (di ansible.cfg) bisa mempercepat eksekusi secara signifikan — pipelining menggabungkan beberapa langkah ke dalam satu koneksi SSH.
register: Menyimpan Hasil Task #
Setiap task mengembalikan data — status eksekusi, output, error. Kamu bisa menyimpan data ini menggunakan register dan menggunakannya di task berikutnya:
- name: Cek status service nginx
systemd:
name: nginx
register: nginx_status # Simpan hasil task ke variabel nginx_status
- name: Debug — tampilkan status nginx
debug:
var: nginx_status # Lihat semua data yang tersimpan
- name: Restart nginx hanya jika sedang berjalan
systemd:
name: nginx
state: restarted
when: nginx_status.status.ActiveState == "active"
Hasil dari command atau shell module menyimpan output di field stdout:
- name: Dapatkan versi nginx yang terinstal
command: nginx -v
register: nginx_version_output
changed_when: false # Perintah ini tidak mengubah sistem
- name: Tampilkan versi nginx
debug:
msg: "Nginx version: {{ nginx_version_output.stderr }}"
# nginx -v menulis ke stderr, bukan stdout
changed_when dan failed_when #
Secara default, Ansible menentukan status changed dan failed berdasarkan return code dan output module. Tapi ada kasus di mana kamu perlu override perilaku ini:
# changed_when: false — task ini tidak pernah mengubah sistem
# Berguna untuk task yang hanya membaca atau mengecek kondisi
- name: Cek apakah database sudah diinisialisasi
command: psql -U postgres -c "SELECT 1"
register: db_check
changed_when: false # Hanya baca, tidak mengubah apapun
# changed_when dengan kondisi — tandai sebagai changed hanya jika kondisi terpenuhi
- name: Jalankan migrasi database
command: python manage.py migrate
register: migration_result
changed_when: "'No migrations to apply' not in migration_result.stdout"
# failed_when — tentukan sendiri kondisi gagal
- name: Cek disk usage
command: df -h /
register: disk_usage
failed_when:
- disk_usage.rc != 0 # Gagal jika perintah error
- "'9' in disk_usage.stdout" # Atau jika disk usage di atas 90%
Timeout Task #
Untuk task yang bisa berjalan lama, kamu bisa mengatur timeout:
- name: Tunggu aplikasi siap
uri:
url: "http://localhost:8080/health"
status_code: 200
register: health_check
until: health_check.status == 200
retries: 10 # Coba maksimal 10 kali
delay: 5 # Tunggu 5 detik antar percobaan
timeout: 10 # Timeout per request: 10 detik
Pola until + retries + delay sangat berguna untuk menunggu kondisi tertentu — misalnya menunggu service siap setelah restart, atau menunggu database menerima koneksi setelah migrasi.
any_errors_fatal #
Secara default, jika satu host gagal, host lain tetap melanjutkan eksekusi. Untuk situasi di mana kegagalan satu host harus menghentikan seluruh play:
- name: Deploy ke production
hosts: webservers
any_errors_fatal: true # Jika satu host gagal, hentikan semua
tasks:
- name: Deploy kode aplikasi
git:
repo: https://github.com/org/app.git
dest: /opt/app
Ini berguna untuk deployment yang harus atomik — jika satu server gagal di-update, lebih baik tidak melanjutkan ke server lain untuk menghindari kondisi di mana sebagian server menjalankan versi lama dan sebagian versi baru.
Ringkasan #
- Linear strategy (default): setiap task diselesaikan di semua host sebelum task berikutnya dimulai — konsisten tapi lebih lambat dari free strategy.
- Free strategy: setiap host berjalan secepat mungkin tanpa sinkronisasi — lebih cepat tapi perlu kehati-hatian ekstra.
- Forks menentukan berapa host dieksekusi secara paralel dalam setiap batch — tingkatkan untuk infrastruktur besar.
- Gunakan
registeruntuk menyimpan hasil task dan menggunakannya di task berikutnya untuk membuat alur eksekusi yang kondisional.changed_when: falseuntuk task yang hanya membaca/mengecek kondisi, tidak mengubah sistem.until+retries+delayuntuk menunggu kondisi tertentu terpenuhi — sangat berguna saat menunggu service siap.any_errors_fatal: trueuntuk deployment yang harus atomik — satu kegagalan menghentikan seluruh play.