Checklist pre-production, operational best practices, monitoring operasional, disaster recovery, dan continuous improvement untuk membawa automasi Ansible kalian ke level production-grade — episode pamungkas dari seri Belajar Ansible.

Setelah di episode 29 sebelumnya kita membahas scaling Ansible untuk enterprise — arsitektur sentral dengan AAP/AWX, repositori GitOps, pemisahan inventory/playbook/role, hingga optimasi performa untuk ribuan host — kalian sekarang punya gambaran bagaimana Ansible dijalankan di skala organisasi. Namun ada pertanyaan yang lebih mendasar yang sering dilupakan: bagaimana kita tahu bahwa automasi itu benar-benar siap dijalankan di production tanpa menimbulkan malapetaka?
Jawabannya bukan terletak pada satu fitur ajaib, melainkan pada proses dan disiplin. Sebuah playbook yang ditulis bagus tapi dijalankan tanpa pengujian, tanpa code review, dan tanpa dokumentasi tetaplah berbahaya — seperti pilot yang lancar menerbangkan pesawat tapi lupa menjalankan pre-flight checklist.
Episode 30 ini adalah episode pamungkas dari seri Belajar Ansible. Setelah 29 episode membangun fondasi dari nol — mulai dari arsitektur agentless, playbook, roles, hingga scaling enterprise — sekarang saatnya merangkum semua pelajaran itu menjadi satu paket lengkap: production deployment checklist dan best practices. Di episode ini kita akan membahas gerbang pre-production, operational best practices, kesalahan umum yang harus dihindari, monitoring operasional, disaster recovery, dan continuous improvement. Ini bukan sekadar teori: ini adalah cara kerja tim infrastruktur yang sehat di dunia nyata.
Analogi paling pas untuk pre-production checklist adalah checklist pilot sebelum lepas landas. Seorang pilot tidak berdebat dengan checklist; dia menjalankannya secara berurutan, langkah demi langkah, karena ia tahu bahwa satu item yang terlewat bisa berarti perbedaan antara penerbangan normal dan kecelakaan. Playbook Ansible yang kalian tulis juga berpotensi menyentuh ratusan server sekaligus — dan satu baris YAML yang salah bisa membuat layanan mati total.
Berikut adalah gerbang pre-production yang harus kalian lewati setiap kali akan mendeploy perubahan ke environment production:
| No | Item Checklist | Alat / Metode | Tujuan |
|---|---|---|---|
| 1 | Code review selesai dan disetujui | Pull Request di GitHub/GitLab | Memastikan logika diverifikasi oleh engineer lain, bukan hanya penulisnya |
| 2 | Linting lulus tanpa error | ansible-lint | Menegakkan best practice, FQCN, dan keamanan statis (episode 18) |
| 3 | Automated testing selesai | Molecule + Testinfra | Menguji role di environment terisolasi sebelum menyentuh host nyata (episode 18) |
| 4 | Dokumentasi up-to-date | README, runbook, komentar variabel | Orang lain (dan kalian 6 bulan ke depan) bisa menjalankan & memecahkan masalah |
| 5 | Secret terenkripsi dengan Vault | ansible-vault + vault ID terpisah per environment | Tidak ada password/API key dalam plaintext di Git (episode 14) |
| 6 | Inventory divalidasi | ansible-inventory --list --yaml | Host, variabel, dan group tersusun benar sebelum eksekusi |
| 7 | Dry-run testing lulus | ansible-playbook --check --diff | Memastikan perubahan yang akan terjadi persis seperti yang diharapkan |
Important
Jangan jadikan checklist ini optional. Di tim profesional, checklist ini dijaga oleh CI/CD pipeline (episode 19): jika ansible-lint menemukan pelanggaran atau Molecule gagal, PR tidak boleh di-merge dan deployment tidak boleh jalan. Mesin yang menegakkan disiplin selalu lebih andal daripada niat baik manusia.
Struktur direktori yang rapi adalah dokumentasi pertama yang akan dibaca orang. Sebuah project production yang sehat biasanya terlihat seperti ini:
ansible-prod/
├── ansible.cfg # konfigurasi global (forks, callback, ssh)
├── requirements.yml # dependensi collection (episode 13)
├── inventory/
│ ├── production.yml # inventory production
│ └── staging.yml # inventory staging
├── group_vars/
│ ├── production/
│ │ ├── all.yml # variabel bersama environment production
│ │ └── webservers.yml # variabel spesifik group
│ └── staging/
├── host_vars/ # variabel per-host
├── playbooks/
│ ├── site.yml # playbook utama / entry point
│ ├── deploy-app.yml # playbook deploy & rollback
│ └── maintenance.yml
├── roles/
│ ├── nginx/
│ ├── postgresql/
│ └── hardened/ # security hardening (episode 27)
├── vault/
│ ├── production.vault.yml # secret terenkripsi per environment
│ └── staging.vault.yml
├── docs/
│ ├── README.md # cara menjalankan project
│ └── runbooks/ # prosedur insiden & recovery
├── .github/workflows/
│ ├── lint-test.yml # CI: lint + Molecule
│ └── deploy.yml # CD: deploy ke staging/production
└── .ansible-lint # konfigurasi ansible-lintPerhatikan pemisahan tegas antara inventory/, group_vars/, playbooks/, dan roles/. Ini adalah prinsip separation of concerns yang sudah kita bahas di episode 29 — data terpisah dari logika, sehingga satu role bisa dipakai ulang di banyak environment hanya dengan mengganti inventory dan variabelnya.
--check + --diff: Dry-Run Sebelum Menyentuh ProductionDua flag yang paling sering menyelamatkan infrastruktur adalah --check dan --diff. --check (dry-run) mensimulasikan eksekusi tanpa melakukan perubahan nyata, sedangkan --diff menunjukkan perubahan teks yang akan terjadi pada file konfigurasi. Kombinasi keduanya memberi kalian "peta perubahan" sebelum benar-benar mengeksekusi.
ansible-playbook -i inventory/production.yml playbooks/site.yml \
--check --diff --limit webservers --tags configTip
Gunakan --limit webservers untuk membatasi dry-run ke sebagian host dulu, dan --tags config untuk menguji hanya satu lapisan perubahan. Kalian juga bisa menambahkan --list-tasks --list-hosts untuk melihat ringkasan task dan host yang akan terpengaruh sebelum menjalankan apa pun.
Setelah lolos gerbang pre-production, kalian akan menjalankan dan memelihara automasi ini setiap hari. Berikut prinsip-prinsip operasional yang menjaga automasi tetap sehat dalam jangka panjang.
Semua aset Ansible harus ada di Git: playbook, role, inventory (tanpa secret), ansible.cfg, requirements, bahkan dokumentasi runbook. Ini bukan sekadar backup — ini adalah audit trail (episode 19). Jika production bermasalah, kalian bisa menjawab pertanyaan: perubahan apa yang menyebabkan ini? siapa yang menulisnya? kapan?. Tanpa Git, pertanyaan itu hanya bisa dijawab dengan tebakan.
git checkout -b fix/nginx-reload-handler
# ... perbaiki playbook ...
ansible-lint . # 1. lint
molecule test -s production # 2. test
git add playbooks/ roles/
git commit -m "fix: pindahkan reload handler ke role nginx"
git push -u origin fix/nginx-reload-handler
# 3. buka PR → code review → merge → pipeline deployJangan menulis ulang logika yang sama di setiap playbook. Bungkus fungsionalitas yang bisa dipakai ulang ke dalam roles (episode 12) dan pakai collections dari Galaxy (episode 13) untuk hal-hal umum. Satu role nginx yang matang bisa dipakai di dev, staging, dan production hanya dengan mengubah variabel — bukan dengan menyalin-paste 200 baris YAML. Ini menghemat waktu dan, yang lebih penting, mengurangi permukaan bug.
Ingat kembali pelajaran episode 10: gunakan block/rescue/always untuk menangani kegagalan dengan anggun, failed_when untuk menetapkan kondisi gagal yang tepat, dan ignore_errors hanya dengan alasan yang jelas. Playbook yang menyerah begitu saja di tengah jalan tanpa pesan yang jelas adalah musuh terbesar operator yang sedang menangani insiden di malam hari.
Playbook besar yang menjalankan semuanya setiap kali adalah pemborosan dan risiko. Gunakan tags untuk memecah playbook menjadi unit-unit yang bisa dieksekusi secara selektif — misalnya hanya memperbarui konfigurasi tanpa me-restart, atau hanya menarik artefak baru tanpa menyentuh konfigurasi sistem.
- name: Deploy web server production
hosts: webservers
become: true
vars:
app_version: "1.4.2"
app_domain: "app.example.com"
tasks:
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present
tags: install
- name: Salin konfigurasi virtual host
ansible.builtin.template:
src: vhost.conf.j2
dest: "/etc/nginx/conf.d/{{ app_domain }}.conf"
mode: "0644"
notify: reload nginx
tags: config
- name: Deploy artefak aplikasi
ansible.builtin.copy:
src: "build/app-{{ app_version }}.tar.gz"
dest: "/var/www/{{ app_domain }}/"
tags: deploy
handlers:
- name: reload nginx
ansible.builtin.systemd_service:
name: nginx
state: reloadedSekarang kalian bisa menjalankan lapisan perubahan yang berbeda secara independen:
ansible-playbook -i inventory/production.yml playbooks/webserver.yml --tags installWarning
Tags adalah pedang bermata dua. Jika kalian menandai task dengan banyak tag, pastikan tag tersebut benar-benar mencakup semua task yang dibutuhkan untuk sebuah operasi yang aman. Melewati satu task yang tampaknya tidak penting (misalnya verifikasi health-check) bisa menyebabkan deployment yang berhasil di atas layanan yang mati.
Idempotency adalah DNA Ansible sejak episode 1, dan di production ia bukan lagi nice-to-have melainkan persyaratan mutlak. Playbook yang idempotent bisa dijalankan ulang tanpa efek samping, sehingga aman dipicu oleh cron, retry setelah kegagalan, atau pipeline CI yang jalan dua kali. Jika kalian menemukan task yang selalu changed setiap kali dijalankan, itu sinyal ada sesuatu yang tidak deklaratif — misalnya memakai shell untuk hal yang seharusnya memakai modul khusus, atau menulis timestamp acak ke file konfigurasi.
Don't Repeat Yourself. Jangan hardcode nilai yang sama di sepuluh tempat. Simpan nilai yang bisa berubah antar environment di group_vars/ dan host_vars/ (episode 7), lalu jadikan playbook sebagai logika murni yang membaca variabel:
domain: "app.example.com"
nginx_worker_processes: "auto"
nginx_ssl_cert: "/etc/ssl/certs/app.example.com.crt"
backend_ports: [8080, 8081, 8082]
monitoring_enabled: truePlaybook kemudian tinggal mereferensikan {{ domain }} dan {{ nginx_worker_processes }} tanpa perlu tahu nilainya — perubahan environment cukup dilakukan di satu file variabel, bukan dengan mengedit playbook.
Sebuah variabel tanpa dokumentasi adalah teka-teki. Di setiap role, sediakan defaults/main.yml dengan komentar singkat, dan buat README ringkas yang menjelaskan variabel yang wajib diisi, dependensi role, dan contoh penggunaannya. Runbook untuk operasi penting (deploy, rollback, restore backup) harus ditulis seolah-olah akan dibaca oleh orang yang baru join minggu lalu — karena suatu saat akan begitu.
Setelah menulis banyak playbook di production, pola-pola kesalahan berikut ini muncul berulang kali. Kenali ciri-cirinya agar kalian bisa menghindarinya sejak awal:
| Kesalahan | Mengapa Berbahaya | Solusi |
|---|---|---|
Memakai command/shell ketika modul sudah ada | Tidak idempotent, error-prone, log tidak informatif | Selalu cari modul khusus dulu (apt, file, copy, template, dst.) |
| Hardcode nilai di dalam playbook | Playbook tidak portabel, sulit diubah, sulit dipahami | Pindahkan ke group_vars/host_vars (prinsip DRY) |
| Mengabaikan idempotency | Eksekusi ulang memicu perubahan tak terduga | Uji dengan --check, perhatikan task yang selalu changed |
| Error handling yang hilang | Playbook berhenti diam-diam, tidak ada cleanup | block/rescue/always, failed_when, changed_when |
| Langsung testing di production | Satu bug menghancurkan ratusan server | Uji di staging dulu (Molecule + environment staging) |
| Secret management buruk | Password & API key bocor ke Git / log | ansible-vault + no_log: true + vault ID per environment |
| Playbook terlalu kompleks | Sulit direview, diuji, dan dirawat | Pecah jadi role; satu playbook melakukan satu hal dengan baik |
| Dokumentasi yang hilang | Ketergantungan pada memori satu orang | README + runbook + komentar di defaults/main.yml |
Salah satu kasus yang paling sering ditemui adalah penggunaan shell untuk instalasi paket. Perhatikan diff berikut — mengubahnya ke modul khusus membuat playbook idempotent dan mudah dibaca:
- name: Install Nginx (CARA LAMA - salah)
ansible.builtin.shell: apt-get update && apt-get install -y nginx
- name: Install Nginx (CARA BENAR)
ansible.builtin.apt:
name: nginx
state: presentCaution
Aturan praktis yang sederhana: jika kalian menemukan diri kalian menulis command/shell untuk melakukan sesuatu, berhentilah dan cari modul yang tepat. Modul apt, dnf, file, copy, template, systemd_service, git, dan get_url sudah menangani hampir semua kebutuhan sehari-hari. shell hanya untuk kasus yang benar-benar tidak ada modulnya.
Automasi yang tidak diobservasi hanyalah harapan. Di production, kalian harus tahu jawaban atas pertanyaan-pertanyaan berikut: berapa lama playbook berjalan? berapa yang berhasil dan gagal? apa yang sebenarnya berubah? siapa yang menjalankan apa dan kapan?
Berikut metrik kunci yang perlu kalian pantau:
| Metrik | Cara Mengukur | Tool / Referensi | Nilai Target |
|---|---|---|---|
| Waktu eksekusi playbook | Callback timer & profile_tasks, durasi job di AWX/AAP | callbacks_enabled = timer, profile_tasks | Stabil & tren menurun seiring optimasi |
| Tingkat sukses / gagal | Job status dari API AWX, log CI/CD, exit code | AWX Job API, Prometheus exporter | Keberhasilan > 99%, tidak ada failed mendadak |
Change rate (rasio changed) | Persentase task berstatus changed per run | Callback json, review diff | Menurun seiring playbook matang → "konvergen" |
| Cakupan host | Jumlah host yang terjangkau vs total inventory | ansible-playbook --list-hosts, laporan AAP | 100% tanpa unreachable |
| Audit trail | Siapa menjalankan apa, kapan, dari mana | AWX/AAP job history, log callback | 100% eksekusi tercatat |
Untuk membangun jejak yang bisa dianalisis, aktifkan callback yang mengeluarkan output terstruktur:
[defaults]
stdout_callback = json
callbacks_enabled = timer, profile_tasksDengan stdout_callback = json, output playbook bisa diparsing oleh tooling lain. Timer mencatat durasi total per task, dan profile_tasks menampilkan task mana yang paling lambat — data berharga untuk optimasi performa. Di skala enterprise, AWX/AAP (episode 20) sudah menyediakan job history, RBAC, dan REST API yang bisa diintegrasikan ke dashboards observability (episode 25) untuk memicu alert jika satu playbook mulai gagal berulang kali.
Tip
Satu praktik yang sangat berguna: catat change rate setiap run. Playbook yang "matang" seharusnya semakin jarang mengubah sesuatu — artinya sistem sudah konvergen ke state yang diinginkan. Lonjakan changed yang tiba-tiba hampir selalu mengindikasikan drift konfigurasi yang harus diselidiki.
Terima kenyataannya: suatu saat sesuatu akan gagal. Playbook akan menghapus file yang salah, release akan bermasalah, atau server production akan disusupi. Pertanyaannya bukan apakah itu terjadi, tapi seberapa cepat kalian bisa pulih.
Yang perlu di-backup adalah sumber kebenaran automasi kalian:
ansible.cfg dan requirements — konfigurasi global dan daftar collection yang sudah dipatok versinya (untuk reproducibility).Important
Backup tanpa uji restore bukanlah backup — itu hanya penyimpanan. Prosedur restore harus diuji berkala, minimal seperempat, di environment terisolasi. Sebuah backup yang tidak bisa direstore nilainya sama dengan tidak punya backup sama sekali.
Pola rollback yang paling andal adalah yang berbasis deploy versi yang sama dengan rollback — gunakan tags untuk menandai task yang relevan, dan jadikan versi target sebagai variabel yang bisa di-override saat run:
- name: Deploy / rollback aplikasi
hosts: appservers
become: true
vars:
target_version: "1.4.2"
tasks:
- name: Unduh artefak versi target
ansible.builtin.get_url:
url: "https://artifacts.internal/app-{{ target_version }}.tar.gz"
dest: "/opt/app/app-{{ target_version }}.tar.gz"
tags: [deploy, rollback]
- name: Arahkan symlink ke versi target
ansible.builtin.file:
src: "/opt/app/releases/app-{{ target_version }}"
dest: /opt/app/current
state: link
notify: restart app
tags: [deploy, rollback]
handlers:
- name: restart app
ansible.builtin.systemd_service:
name: app
state: restartedKetika versi 1.4.3 bermasalah, rollback cukup dilakukan dengan satu perintah — tanpa mengubah satu baris pun playbook:
ansible-playbook -i inventory/production.yml playbooks/deploy-app.yml \
--tags rollback -e target_version=1.4.2Note
Kunci pola ini adalah deployment immutable: setiap versi aplikasi disimpan sebagai direktori terpisah dan symlink current cukup diarahkan ulang. Rollback menjadi operasi yang cepat, aman, dan bisa dipicu kapan saja — tidak bergantung pada proses reverse yang rumit dan rawan error.
Rencana recovery terbaik pun tidak berarti jika tidak pernah diuji. Jadwalkan latihan rutin: restore backup database di host staging, rollback release, rebuild control node dari nol dari repository Git. Catat hasilnya di runbook dan perbaiki prosedur yang gagal. Tim yang rutin berlatih recovery akan jauh lebih tenang dan lebih cepat saat insiden nyata terjadi.
Automation bukanlah proyek sekali jadi; ia adalah sistem hidup yang harus dirawat. Berikut kebiasaan yang menjaga kualitas automasi tetap naik dari waktu ke waktu:
with_items → loop), dan ansible-lint akan membantu mendeteksinya.profile_tasks (episode 15) untuk menemukan bottleneck; matikan fact gathering yang tidak perlu, manfaatkan fact caching, dan atur forks dengan tepat.ansible-core dan collection secara terjadwal, pantau advisory keamanan, dan jalankan security hardening secara berkala (episode 27).Selamat — kalian telah menyelesaikan perjalanan panjang dari episode 0 hingga episode 30! Mari kita rekap sebentar peta besar yang sudah kita lalui bersama:
| Fase | Episode | Materi Inti |
|---|---|---|
| Pre-Requisites & Fundamentals | 0–2 | Setup environment, sejarah automasi, arsitektur agentless Ansible |
| Basic Operational & Core Concepts | 3–10 | Inventory, ad-hoc, playbook, handler, variabel & facts, Jinja2, control flow, error handling |
| Networking, Security & Reusability | 11–14 | Includes/imports, roles, collections, Ansible Vault |
| Advanced Topics & Optimization | 15–17 | Performance tuning, async actions, custom modules & filters |
| Modern Ecosystem & Production Readiness | 18–30 | Lint & Molecule, CI/CD, execution environments, dynamic inventory, network/k8s/database/monitoring/cloud/security/Windows automation, scaling enterprise, dan checklist produksi ini |
Dari sekadar memahami ansible -m ping di episode 0, kalian kini memiliki kemampuan untuk mengotomasi server Linux dan Windows, jaringan, cloud multi-vendor, Kubernetes, hingga database — dengan kualitas yang dijaga oleh linting, testing, dan pipeline CI/CD, dan dieksekusi dengan aman di scale enterprise. Itu adalah kemampuan langka yang bernilai sangat tinggi di pasar kerja DevOps dan SRE.
Ingatlah tiga prinsip inti yang selalu menuntun kita: idempotency, declarative thinking, dan automation over documentation — tulis apa yang kalian lakukan, dan buat mesin yang melakukan apa yang kalian tulis.
Perjalanan tidak berhenti di sini. Setelah menyelesaikan seri ini, langkah berikutnya yang bisa kalian ambil untuk menguasai Ansible lebih dalam:
ansible-navigator, dan sertifikasi Red Hat (EX294/RHCE) untuk memvalidasi kemampuan.Automasi adalah investasi yang terus berbunga: setiap jam yang kalian habiskan menulis otomasi yang baik akan menghemat ratusan jam di masa depan. Teruslah otomasi, teruslah berlatih, dan jadikan infrastruktur sebagai sesuatu yang bisa kalian bangun ulang dengan satu perintah. Sampai jumpa di perjalanan berikutnya — dan selamat berkarya sebagai engineer infrastruktur yang sesungguhnya!