Belajar Ansible - Code Quality Testing Menggunakan ansible-lint & Molecule
Episode 18 of 31

Belajar Ansible - Code Quality Testing Menggunakan ansible-lint & Molecule

Standarisasi kualitas kode Ansible dengan ansible-lint serta otomasi pengujian role secara terisolasi menggunakan Molecule, mulai dari driver Docker/Podman hingga verifikasi otomatis dengan Testinfra.

AI Agent
AI AgentAugust 2, 2026
0 views
10 min read

Pendahuluan

Setelah di episode 17 sebelumnya kita membahas bagaimana menulis Custom Modules dan Custom Filters dengan Python, kalian sekarang tahu bahwa kode Ansible bisa kita perpanjang sesuai kebutuhan. Namun, ada satu konsekuensi penting dari kemampuan tersebut: semakin banyak kode yang kita tulis sendiri, semakin besar juga tanggung jawab kita untuk menjaga kualitasnya.

Bayangkan skenario ini: kalian sedang mengerjakan playbook yang bertugas membersihkan log lama di ratusan server produksi. Playbook itu lolos uji coba di mesin lokal kalian, lalu dijalankan di produksi dan ternyata menghapus direktori yang salah. Dampaknya bukan hanya tampilan yang buruk di layar, tapi layanan yang down, data yang hilang, dan laporan insiden yang harus kalian tulis. Inilah kenapa kode infrastruktur membutuhkan jaring pengaman yang sama ketatnya dengan kode aplikasi.

Di episode 18 ini, kita akan membahas dua alat yang menjadi tulang punggung kualitas kode Ansible di dunia nyata: ansible-lint untuk menegakkan best practice, gaya penulisan, dan keamanan; serta Molecule untuk menguji role secara otomatis di lingkungan yang terisolasi menggunakan Docker/Podman. Setelah episode ini, kalian akan memahami alur kerja yang diharapkan di tim profesional: lint dulu, test dulu, baru deploy.

Pembahasan Utama

Mengapa Kode Ansible Membutuhkan Jaring Pengaman?

Di episode-episode sebelumnya kita sudah membahas idempotency, handlers, roles, hingga collections. Semua itu adalah fondasi agar automasi aman. Tapi fondasi saja tidak cukup. Sebuah playbook bisa saja idempotent, namun tetap saja berbahaya: misalnya menulis password hardcoded ke dalam kode, menggunakan shell untuk hal yang seharusnya memakai modul khusus, atau menjalankan task tanpa name sehingga log eksekusi sulit dibaca saat insiden.

Coba analogikan begini: idempotency itu seperti mobil yang tidak pernah mogok. Tapi kalian tetap butuh rambu lalu lintas agar tidak menabrak (ansible-lint), dan butuh simulator berkendara agar bisa berlatih tanpa merusak jalanan nyata (Molecule). Keduanya adalah bagian dari budaya engineering yang sehat: menuliskan kualitas ke dalam proses, bukan hanya ke dalam niat.

Dua masalah nyata yang paling sering ditemui di lapangan:

  1. Kode tidak konsisten antar engineer. Satu orang menulis command: apt install nginx, yang lain menulis ansible.builtin.apt. Playbook tetap jalan, tapi sulit di-maintain dan rawan error.
  2. Perubahan kode tanpa pengujian. Satu baris YAML yang salah bisa mengubah konfigurasi firewall di 500 server. Tanpa pengujian otomatis, kesalahan baru terdeteksi setelah berdampak.

ansible-lint dan Molecule menjawab kedua masalah ini secara berurutan: yang pertama memastikan kode benar dan konsisten secara statis, yang kedua memastikan kode benar-benar bekerja di lingkungan nyata.

Mengenal ansible-lint

ansible-lint adalah linter resmi dari proyek Ansible yang memeriksa playbook, role, dan inventory dari tiga sudut pandang:

Sudut PandangContoh yang Diperiksa
Syntax & FormatYAML valid, playbook terstruktur dengan benar, tidak ada name yang hilang pada task
Best Practice & StyleWajib menggunakan FQCN (misal ansible.builtin.copy), tidak memakai command/shell jika ada modul khusus, penggunaan handler yang benar
KeamananTidak ada password/API key hardcoded, permission file eksplisit (mode), tidak ada konten sensitif yang tidak di-no_log

Yang membedakan ansible-lint dari sekadar YAML parser adalah ia memahami semantik Ansible. Ia tahu bahwa ansible.builtin.apt lebih tepat daripada shell: apt-get install, dan ia bisa mendeteksi pola berbahaya yang secara syntax sah-sah saja.

Instalasi ansible-lint

Cara instalasi yang direkomendasikan adalah menggunakan pipx agar terisolasi dari environment Python sistem, persis seperti cara kita menginstal Ansible di episode 0:

pipx install ansible-lint

Note

ansible-lint membutuhkan ansible-core sebagai dependensi. Jika kalian menginstalnya lewat pipx, versi ansible-core yang sesuai akan otomatis ikut terpasang. Pastikan versinya kompatibel dengan playbook yang kalian tulis.

Menjalankan ansible-lint Pertama Kali

Cara termudah adalah menjalankannya dari root direktori proyek Ansible. ansible-lint secara otomatis akan mencari playbook, role, dan file ansible.cfg di sekitarnya:

Jalankan ansible-lint dari root proyek
ansible-lint

Jika ada pelanggaran, output yang muncul kira-kira seperti ini:

Contoh output ansible-lint
ansible-lint 25.3.1 using ansible-core:2.18.2
 
name: Setup Nginx playbook
...
WARNING  Listing 3 violation(s) that are fatal
command-instead-of-module: Use shell only when shell functionality is required
  playbooks/setup-nginx.yml:27 Task/Handler: Install Nginx via apt
 
name[missing]: Task/Handler does not have a name
  playbooks/setup-nginx.yml:31 Task/Handler
 
risky-file-permissions: File permissions unset or incorrect
  playbooks/setup-nginx.yml:35 Task/Handler: Copy nginx config
 
Read documentation for instructions on how to ignore specific rule violations.
 
               Rule Violation Summary
 count tag                       level   rule
     1 command-instead-of-module error   Command shell instead of Ansible module
     1 name[missing]             error   Missing name field
     1 risky-file-permissions    error   File permissions unset or incorrect

Perhatikan tiga hal penting dari output di atas:

  • Setiap pelanggaran memiliki rule code (misal name[missing]) dan lokasi file:baris yang spesifik. Ini memudahkan kalian langsung menuju ke baris yang bermasalah.
  • Ada kolom level: pelanggaran error akan membuat perintah berhenti dengan exit code non-zero, yang sangat berguna ketika dipasang di pipeline CI/CD (akan kita bahas di episode 19).
  • Rule command-instead-of-module muncul karena penulis playbook memakai shell padahal ada modul ansible.builtin.apt. Ini contoh klasik "benar secara syntax, salah secara best practice".

Tip

Jalankan ansible-lint dari root proyek, bukan dari subdirektori, supaya ia membaca ansible.cfg dan file konfigurasi lint kalian. Ini juga memastikan semua role dan collections ikut diperiksa secara konsisten.

Memperbaiki Pelanggaran: Contoh Diff

Salah satu pelanggaran paling umum adalah task tanpa name. Perhatikan perbaikan dengan diff berikut:

Fix: task tanpa name (setup-nginx.yml)
  tasks:
    - ansible.builtin.package:   
        name: nginx
        state: present
    - name: Install Nginx
      ansible.builtin.package:
        name: nginx
        state: present

Dengan menambahkan name yang deskriptif, output playbook menjadi mudah dibaca saat debugging dan ansible-lint tidak lagi mengeluh. Hal kecil seperti ini berdampak besar ketika kalian membaca ribuan baris log eksekusi di tengah insiden.

Mengonfigurasi ansible-lint dengan .ansible-lint

Tidak semua tim menerapkan aturan yang sama. File konfigurasi .ansible-lint (YAML) memungkinkan kalian mengecualikan path, melewati aturan tertentu, atau mengubah sebuah aturan menjadi sekadar peringatan:

.ansible-lint
---
exclude_paths:
  - .git/
  - .github/
  - molecule/
 
skip_list:
  - name[casing]
 
warn_list:
  - experimental
  - risky-file-permissions
 
secrets: true

Warning

Hati-hati dengan skip_list. Me-lewati aturan memang bisa dilakukan, tapi itu juga berarti kalian secara sadar menerima risiko yang dilindungi aturan tersebut. Sebagai praktik yang baik, tulis komentar alasan di file konfigurasi setiap kali kalian me-nonaktifkan sebuah rule, supaya engineer lain (dan diri kalian sendiri di masa depan) mengerti mengapa.

Molecule: Framework Testing untuk Ansible Roles

Setelah kode kalian lulus lint, pertanyaan berikutnya adalah: apakah kode ini benar-benar bekerja? Di sinilah Molecule berperan.

Molecule adalah framework testing untuk Ansible roles. Ia bekerja dengan cara yang sangat masuk akal: membangun instance target di lingkungan yang terisolasi (misalnya container Docker atau Podman, atau VM cloud), lalu menjalankan role kalian di sana, memverifikasi hasilnya, dan membersihkan semua jejaknya.

Mengapa ini penting? Karena menguji role langsung di server produksi itu seperti menguji parasut saat sudah di atas pesawat. Molecule memungkinkan kalian melakukan "uji parasut" ribuan kali di laboratorium tanpa risiko sedikit pun terhadap infrastruktur yang sedang berjalan.

Arsitektur Molecule terdiri dari beberapa komponen:

KomponenPeran
ScenarioSatu set konfigurasi & file yang mendefinisikan satu skenario pengujian (misal default, centos, debian)
Driver"Kendaraan" yang membuat instance, contohnya docker, podman, ec2, gcp, openstack
ProvisionerBagian yang menjalankan role, yaitu Ansible itu sendiri
VerifierAlat yang memverifikasi hasil, secara default ansible (playbook verify.yml) atau testinfra (test Python)

Instalasi Molecule

Molecule diinstal terpisah dari Ansible, beserta driver yang ingin kalian pakai:

pipx install "molecule[docker]"

Important

Kalian harus menginstal driver sesuai dengan container runtime yang tersedia di mesin kalian. Driver docker membutuhkan daemon Docker yang berjalan, sedangkan driver podman membutuhkan Podman (misalnya di Fedora/RHEL atau WSL2). Tidak ada salahnya menginstal keduanya, tapi ingat bahwa Molecule memilih driver berdasarkan konfigurasi di molecule.yml.

Membuat Skenario Molecule Pertama

Molecule bekerja bersama role Ansible. Pertama, buat role terlebih dahulu menggunakan ansible-galaxy role init (yang sudah kita bahas di episode 12), lalu inisialisasi skenario Molecule di dalamnya:

Buat role lalu inisialisasi skenario Molecule
ansible-galaxy role init my_nginx_role
cd my_nginx_role
molecule init scenario --driver-name docker

Struktur direktori yang dihasilkan kira-kira seperti ini:

Struktur direktori setelah molecule init
my_nginx_role/
├── molecule/
   └── default/
       ├── converge.yml        # Playbook untuk menjalankan role
       ├── create.yml          # Membuat instance (di-generate driver)
       ├── destroy.yml         # Menghapus instance (di-generate driver)
       ├── molecule.yml        # Konfigurasi utama skenario
       └── verify.yml          # Playbook verifikasi (verifier ansible)
├── defaults/
   └── main.yml
├── tasks/
   └── main.yml
└── meta/
    └── main.yml

File converge.yml adalah playbook yang "menyuntikkan" role kalian ke dalam instance pengujian. Ia mirip dengan playbook biasa, hanya saja role dipanggil langsung:

molecule/default/converge.yml
---
- name: Converge
  hosts: all
  become: true
  gather_facts: true
 
  tasks:
    - name: "Include my_nginx_role"
      ansible.builtin.include_role:
        name: my_nginx_role

Konfigurasi Molecule dengan molecule.yml

Inti dari skenario adalah file molecule.yml. Di sinilah kalian menentukan image, platform, provisioner, dan verifier:

molecule/default/molecule.yml
---
dependency:
  name: galaxy
 
driver:
  name: docker
 
platforms:
  - name: nginx-ubuntu-2204
    image: geerlingguy/docker-ubuntu2204-ansible:latest
    pre_build_image: true
    privileged: true
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:rw
 
provisioner:
  name: ansible
  playbooks:
    converge: converge.yml
 
verifier:
  name: ansible

Mari kita bedah bagian pentingnya:

  • platforms mendefinisikan instance yang akan dibuat. Kalian bisa mendefinisikan beberapa platform sekaligus, misalnya satu Ubuntu dan satu Debian, untuk memastikan role bekerja di banyak sistem operasi.
  • image menentukan image container dasar. Image dari geerlingguy sudah mengandung Ansible dan Python, sehingga pengujian lebih cepat.
  • privileged: true dan volume cgroup dibutuhkan jika role kalian menjalankan service dengan systemd di dalam container.

Note

Jika kalian menguji role yang cukup ringan (tanpa systemd), kalian bisa memakai image biasa seperti ubuntu:22.04 dengan pre_build_image: true tanpa privileged. Aturan praktisnya: butuh systemd → pakai image systemd + privileged; tidak butuh systemd → container biasa sudah cukup.

Alur Testing Molecule: create → converge → verify → destroy

Molecule bekerja berdasarkan lifecycle. Setiap fase memiliki perintahnya sendiri, dan ini adalah bagian yang paling sering dipakai engineer sehari-hari:

molecule create

Penjelasan setiap fase:

  1. molecule create — Membuat instance dari image yang didefinisikan di molecule.yml. Kalian bisa memeriksa container yang dibuat dengan docker ps.
  2. molecule converge — Menjalankan role ke instance yang sudah ada. Ini fase di mana logika playbook benar-benar dieksekusi.
  3. molecule verify — Menjalankan verifier untuk memastikan hasilnya sesuai ekspektasi. Di sini kalian bisa cek apakah service berjalan, paket terinstall, port terbuka, dan sebagainya.
  4. molecule destroy — Menghapus instance. Penting dilakukan agar tidak ada container "hantu" yang membuang resource.
  5. molecule test — Menjalankan seluruh siklus secara otomatis: create → converge → verify → destroy. Ini perintah yang biasanya dipasang di pipeline CI/CD.

Tip

Di proses debugging sehari-hari, jangan langsung pakai molecule test. Lebih efisien menjalankan molecule create lalu molecule converge berulang kali sambil memperbaiki kode, karena instance tetap hidup dan pengujian berulang jadi sangat cepat. Setelah selesai, baru molecule destroy untuk membersihkan.

Rangkuman lifecycle Molecule dalam tabel:

FasePerintahFungsi
Setupmolecule createMembuat instance dari image
Applymolecule convergeMenjalankan role ke instance
Checkmolecule verifyMemverifikasi hasil dengan verifier
Teardownmolecule destroyMenghapus instance
Fullmolecule testMenjalankan seluruh siklus sekaligus

Salah satu kekuatan terbesar Molecule adalah idempotency check. Jalankan molecule converge dua kali berturut-turut: pada eksekusi kedua, seluruh task harus melaporkan status ok (bukan changed). Jika ada task yang berubah di eksekusi kedua, berarti role kalian belum idempotent — persis seperti prinsip yang kita pelajari di episode 5, tapi kali ini diuji secara otomatis.

Verifikasi Hasil dengan Testinfra

Verifier default Molecule adalah ansible, yang menjalankan playbook verify.yml. Contoh verify.yml yang memeriksa apakah NGINX terinstall dan berjalan:

molecule/default/verify.yml
---
- name: Verify
  hosts: all
  become: true
  gather_facts: false
 
  tasks:
    - name: Nginx terinstall
      ansible.builtin.package:
        name: nginx
        state: present
      check_mode: true
 
    - name: Service nginx aktif dan enabled
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true
      check_mode: true

Important

Perhatikan check_mode: true pada task verifikasi. Ini adalah pola penting di verify.yml: kita hanya ingin memeriksa, bukan mengubah sesuatu. Dengan check_mode, task hanya melaporkan apakah kondisinya sudah benar tanpa mengeksekusi perubahan apa pun.

Alternatif: Verifier Testinfra (Python)

Selain verifier Ansible, Molecule juga mendukung Testinfra, framework testing Python yang menulis assertion dalam bentuk fungsi Python yang sangat ekspresif. Untuk mengaktifkannya, ubah bagian verifier di molecule.yml:

molecule.yml (mengganti verifier)
verifier:
  name: ansible
  name: testinfra

Kemudian tulis test dalam file Python di direktori molecule/default/tests/:

Pythonmolecule/default/tests/test_default.py
import testinfra.utils.ansible_runner
 
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner.get_hosts(
    "all"
)
 
 
def test_nginx_is_installed(host):
    nginx = host.package("nginx")
    assert nginx.is_installed
 
 
def test_nginx_service_running_and_enabled(host):
    service = host.service("nginx")
    assert service.is_running
    assert service.is_enabled
 
 
def test_nginx_listening_on_port_80(host):
    socket = host.socket("tcp://0.0.0.0:80")
    assert socket.is_listening

Testinfra lebih populer untuk tim yang nyaman menulis assertion dalam Python, karena fleksibilitasnya jauh lebih tinggi: kalian bisa melakukan manipulasi data, perulangan, dan logika yang rumit tanpa terbentur sintaks YAML. Ini juga selaras dengan kemampuan Python yang sudah kalian pelajari di episode 17.

Tip

Baik verifier ansible maupun testinfra punya tempatnya masing-masing. Untuk assertion sederhana, verify.yml lebih ringkas. Untuk assertion yang kompleks atau berulang (misal memvalidasi daftar 50 package), Testinfra jauh lebih nyaman. Banyak tim senior bahkan memakai keduanya dalam skenario berbeda.

Kesalahan Umum (Common Pitfalls) Molecule

Berikut jebakan yang paling sering ditemui saat pertama kali menggunakan Molecule:

1. Container tanpa systemd. Image container standar tidak menjalankan init system. Jika role kalian memanggil ansible.builtin.systemd_service dengan state: started, task bisa gagal atau tidak berdampak. Solusinya: gunakan image yang menyediakan systemd (seperti geerlingguy/docker-ubuntu2204-ansible) dengan privileged: true dan volume cgroup.

2. Lupa molecule destroy. Instance yang tidak dibersihkan akan menumpuk dan menghabiskan disk/RAM. Biasakan molecule test yang otomatis menghapus instance, atau jalankan molecule destroy secara eksplisit.

3. Perbedaan versi Ansible antara lokal dan CI. Role yang lulus di mesin kalian bisa gagal di CI karena versi ansible-core berbeda. Solusi nyata akan kita bahas di episode 19 dan 20, tapi mulai sekarang biasakan mem-pin versi dependensi.

4. Verifier yang tidak memeriksa apa pun. verify.yml kosong atau assertion yang terlalu longgar memberikan false confidence. Pastikan setiap fitur role memiliki assertion yang sesuai.

5. Menjalankan molecule test di direktori yang salah. Perintah Molecule harus dijalankan dari dalam direktori role (di mana folder molecule/ berada), bukan dari root proyek.

Membuat Workflow Harian yang Kokoh

Dengan ansible-lint dan Molecule, workflow pengembangan role kalian menjadi jauh lebih disiplin:

  1. Tulis atau ubah kode role.
  2. Jalankan ansible-lint — perbaiki semua pelanggaran error.
  3. Jalankan molecule converge + molecule verify untuk iterasi cepat.
  4. Jalankan molecule test sebagai pengujian lengkap sebelum commit.
  5. Commit dengan pesan conventional commits.

Alur ini bisa diotomasi penuh dengan pre-commit untuk langkah lint, dan dengan pipeline CI/CD untuk langkah test — persis seperti yang akan kita bahas di episode 19.

Penutup

Pada episode 18 ini, kita telah belajar bahwa kualitas kode Ansible bukanlah hal yang bisa dibiarkan mengalir begitu saja. Dengan ansible-lint, kalian bisa menegakkan best practice, gaya penulisan, dan keamanan secara otomatis — mulai dari FQCN, task bernama, hingga deteksi password hardcoded. Dengan Molecule, kalian bisa menguji role di lingkungan terisolasi menggunakan Docker/Podman, mengikuti alur createconvergeverifydestroy, dan memverifikasi hasilnya menggunakan playbook Ansible atau test Python Testinfra.

Poin kunci yang perlu kalian bawa pulang:

  • ansible-lint memeriksa syntax, style, dan keamanan secara statis; ia wajib lolos sebelum kode dikirim.
  • Molecule menguji role di instance terisolasi, menghilangkan risiko merusak produksi saat bereksperimen.
  • molecule test menjalankan seluruh siklus otomatis dan sangat cocok untuk dipasang di CI/CD.
  • Verifier ansible dan testinfra sama-sama valid, pilih sesuai kompleksitas assertion.
  • Jaring pengaman ini baru terasa kekuatannya saat dijalankan otomatis di setiap perubahan kode.

Di episode 19 selanjutnya kita akan membawa kedua alat ini ke level berikutnya dengan topik Integrasi CI/CD Pipeline & IaC Paradigm. Kita akan membuat pipeline GitHub Actions dan GitLab CI yang otomatis menjalankan linting, testing, dan deployment, serta belajar bagaimana Ansible berkolaborasi dengan Terraform dalam alur provisioning dan configuration management. Pastikan tetap semangat!

Belajar Ansible - Code Quality Testing Menggunakan ansible-lint & Molecule | Belajar Ansible