Struktur Direktori #
Sebagai sebuah kakas otomatisasi nir-agen (agentless), Ansible memberikan kebebasan yang sangat tinggi bagi pengembang untuk menata berkas proyek. Kita dapat meletakkan seluruh instruksi playbook, daftar inventaris server, dan berkas konfigurasi dalam satu folder datar (flat folder), dan Ansible akan tetap mengeksekusinya tanpa masalah. Namun, pendekatan tanpa struktur ini adalah jalan pintas yang berbahaya. Ketika proyek otomatisasi kita mulai mengelola puluhan lingkungan (environments), ratusan variabel, serta berbagai peran server (roles), proyek yang tidak terstruktur akan berubah menjadi kode kusut yang mustahil dipelihara secara kolaboratif. Artikel ini membahas pentingnya standardisasi tata letak berkas, membandingkan struktur pengujian dengan struktur produksi standar industri, serta membedah komponen penting di dalamnya.
Pentingnya Standardisasi Struktur Direktori #
Dalam rekayasa perangkat lunak dan otomatisasi infrastruktur sebagai kode (Infrastructure as Code / IaC), standardisasi struktur direktori memiliki peran yang setara dengan penulisan kode yang bersih. Berikut adalah alasan utama mengapa kita harus mengadopsi struktur direktori yang baku:
- Kolaborasi Tim yang Mulus: Saat seluruh anggota tim platform engineering memahami letak berkas variabel, tugas, dan pustaka eksternal, proses peninjauan kode (code review) dan integrasi fitur baru dapat berjalan jauh lebih cepat.
- Keterbacaan dan Navigasi Proyek: Pengembang baru yang bergabung dalam tim dapat langsung menavigasi berkas tanpa harus menebak di mana file variabel tertentu didefinisikan.
- Pemisahan Kepentingan (Separation of Concerns): Memisahkan data lingkungan (IP server, kredensial) dengan logika otomatisasi (cara menginstal Nginx, cara konfigurasi database) memastikan kita dapat memodifikasi infrastruktur target tanpa beresiko merusak logika otomatisasi utama.
- Keamanan Informasi: Dengan memisahkan file variabel lingkungan secara jelas, kita dapat menerapkan kebijakan enkripsi (menggunakan Ansible Vault) khusus pada berkas sensitif tanpa harus mengenkripsi seluruh alur kerja playbook.
Struktur Minimal untuk Pengujian #
Untuk keperluan pembelajaran awal, demonstrasi teknologi (proof of concept), atau pengujian tugas ad-hoc berskala kecil, kita cukup menggunakan struktur minimal satu tingkat. Layout ini sangat ringkas dan mudah dipahami.
ansible-project-minimal/
├── ansible.cfg # File konfigurasi lokal proyek
├── inventory.ini # Daftar alamat IP managed node
└── playbook.yml # Berkas instruksi utama (tugas-tugas)
Struktur minimal ini sangat baik untuk memulai eksekusi cepat. Namun, kita sangat dilarang membawa struktur ini ke lingkungan produksi tingkat perusahaan karena tidak memiliki modularitas untuk skalabilitas.
Struktur Produksi Standar Enterprise #
Untuk proyek skala produksi menengah hingga besar yang mengelola sistem multi-tipe (seperti web server, database, load balancer) di berbagai lingkungan (seperti dev, staging, production), komunitas Ansible merekomendasikan tata letak terstruktur di bawah ini:
ansible-project/
│
├── ansible.cfg # Konfigurasi Ansible tingkat proyek
├── requirements.yml # Manajemen dependensi role/collection eksternal
│
├── environments/ # Pemisahan inventaris berdasarkan lingkungan
│ ├── development/
│ │ ├── hosts.ini # Server lingkungan Development
│ │ ├── group_vars/ # Variabel grup untuk development
│ │ │ ├── all.yml
│ │ │ └── webservers.yml
│ │ └── host_vars/ # Variabel host spesifik development
│ │ └── dev-web-01.yml
│ │
│ └── production/
│ ├── hosts.ini # Server lingkungan Produksi
│ ├── group_vars/ # Variabel grup untuk produksi (Vault-encrypted)
│ │ ├── all.yml
│ │ └── webservers.yml
│ └── host_vars/
│ └── prod-web-01.yml
│
├── playbooks/ # Folder kumpulan berkas playbook utama
│ ├── site.yml # Master playbook (jalankan seluruh infrastruktur)
│ ├── webservers.yml # Playbook khusus tier web server
│ ├── dbservers.yml # Playbook khusus tier database
│ └── app-deployment.yml # Playbook deployment rilis aplikasi
│
├── roles/ # Folder kumpulan module mandiri yang modular
│ ├── common/ # Setup dasar (SSH, NTP, Security Hardening)
│ ├── nginx/ # Konfigurasi reverse proxy
│ └── postgresql/ # Konfigurasi cluster database
│
├── files/ # File statis (SSL cert, banner, public key)
│ └── app-logos/
│
└── templates/ # Berkas dinamis berekstensi Jinja2 (.j2)
└── nginx.conf.j2
Bedah Detail Setiap Komponen #
Mari kita bedah fungsi dan aturan teknis dari masing-masing komponen direktori di atas agar kita dapat mengimplementasikannya dengan benar.
1. File ansible.cfg #
Diletakkan di akar (root) direktori proyek. Tujuannya adalah agar setiap kali kita menjalankan perintah Ansible dari folder ini, konfigurasi lokal proyek ini yang akan digunakan, bukan konfigurasi global sistem /etc/ansible/ansible.cfg.
2. Direktori environments/ #
Praktik terbaik di industri adalah memisahkan berkas inventaris (hosts) secara fisik berdasarkan lingkungannya. Dengan memisahkan berkas hosts.ini development dan production ke dalam folder yang berbeda, kita memperkecil resiko kesalahan eksekusi perintah (seperti tanpa sengaja men-deploy skrip uji coba ke server produksi).
Saat menjalankan otomatisasi, kita diwajibkan menentukan jalur inventaris secara eksplisit:
# Mengeksekusi perubahan ke lingkungan staging
ansible-playbook -i environments/development/hosts.ini playbooks/webservers.yml
# Mengeksekusi perubahan ke lingkungan produksi dengan kunci Vault
ansible-playbook -i environments/production/hosts.ini playbooks/webservers.yml --ask-vault-pass
3. Direktori playbooks/ #
Merupakan folder penampung file alur kerja utama kita. Dibandingkan membuat satu berkas playbook monolitik raksasa yang mengurusi semua hal, kita direkomendasikan untuk memecahnya menjadi bagian-bagian kecil berbasis fungsi.
Master playbook site.yml berfungsi sebagai agregator yang memanggil sub-playbook lainnya menggunakan modul pengimpor:
# File: playbooks/site.yml
---
# Mengimpor alur kerja setup server dasar
- import_playbook: common-setup.yml
# Mengimpor alur kerja setup web server
- import_playbook: webservers.yml
# Mengimpor alur kerja setup database
- import_playbook: dbservers.yml
Manajemen Variabel group_vars dan host_vars #
Ansible memiliki fitur otomatisasi pemuatan variabel yang sangat cerdas melalui dua direktori khusus: group_vars/ dan host_vars/.
group_vars/: Direktori ini berisi file-file variabel yang ditujukan untuk grup server tertentu. Nama berkas di dalam folder ini harus sama persis dengan nama grup server yang kita definisikan di berkas inventarishosts.ini. Berkasall.ymladalah berkas khusus yang variabelnya akan diwarisi oleh seluruh server di inventaris.host_vars/: Berisi file variabel khusus untuk satu server tertentu. Nama berkas harus sesuai dengan nama host (FQDN atau alias IP) di berkas inventaris.
Aturan Resolusi dan Precedence Variabel #
Satu poin teknis penting yang sering membingungkan pengembang adalah: Di mana kita harus meletakkan direktori group_vars dan host_vars?
Ansible secara otomatis mencari folder group_vars dan host_vars di dua tempat:
- Playbook-adjacent: Sejajar dengan lokasi file playbook utama yang sedang dieksekusi.
- Inventory-adjacent: Sejajar dengan file inventaris (
hosts.ini) yang digunakan saat itu.
Jika terdapat variabel dengan nama yang sama di kedua tempat tersebut, variabel yang berada di dekat berkas inventaris (inventory-adjacent) memiliki prioritas lebih tinggi dan akan menimpa variabel yang berada di dekat berkas playbook.
Hierarki penimpaan variabel berdasarkan lokasi direktori digambarkan pada diagram di bawah ini (prioritas terendah di bagian atas hingga prioritas tertinggi di bagian bawah):
flowchart TD
subgraph "Variabel Tingkat Proyek (Playbook-adjacent)"
A["group_vars/all.yml (Playbook)"] -->|"Ditimpa oleh"| B["group_vars/webservers.yml (Playbook)"]
end
subgraph "Variabel Tingkat Lingkungan (Inventory-adjacent)"
B -->|"Ditimpa oleh"| C["environments/production/group_vars/all.yml"]
C -->|"Ditimpa oleh"| D["environments/production/group_vars/webservers.yml"]
end
subgraph "Variabel Tingkat Host Spesifik"
D -->|"Ditimpa oleh"| E["host_vars/prod-web-01.yml (Playbook)"]
E -->|"Ditimpa oleh"| F["environments/production/host_vars/prod-web-01.yml"]
end
subgraph "Variabel Dinamis & CLI (Tertinggi)"
F -->|"Ditimpa oleh"| G["Playbook Internal (vars / vars_files)"]
G -->|"Ditimpa oleh"| H["Argumen CLI (--extra-vars)"]
end
Anatomi Lengkap Struktur Ansible Role #
Role adalah unit modularisasi utama di Ansible. Role memungkinkan kita mengemas task, variabel, template, handler, dan file dalam satu paket mandiri yang dapat digunakan kembali (reusable) di berbagai proyek otomatisasi yang berbeda.
Ketika sebuah playbook memanggil sebuah role (misalnya roles: [ nginx ]), Ansible secara otomatis mencari berkas instruksi di subdirektori role tersebut berdasarkan konvensi nama yang baku.
Berikut anatomi folder role nginx yang ideal:
roles/nginx/
├── defaults/
│ └── main.yml # Variabel default (prioritas paling rendah, mudah ditimpa)
│
├── vars/
│ └── main.yml # Variabel internal role (prioritas tinggi, jangan diubah oleh user)
│
├── tasks/
│ └── main.yml # Daftar tugas utama yang akan dieksekusi
│
├── handlers/
│ └── main.yml # Pemicu aksi tertentu (seperti restart service nginx)
│
├── files/
│ └── block-ips.conf # Berkas statis yang disalin apa adanya ke managed node
│
├── templates/
│ └── nginx.conf.j2 # Template konfigurasi dinamis berbasis Jinja2
│
├── meta/
│ └── main.yml # Metadata role (author, lisensi, dan dependensi role lain)
│
└── tests/ # Skrip uji coba lokal mandiri untuk role ini
├── inventory
└── test.yml
Alur eksekusi internal saat Ansible memproses sebuah role digambarkan pada bagan berikut:
flowchart TD
A["Mulai Jalankan site.yml"] --> B["Baca berkas ansible.cfg"]
B --> C["Muat Inventaris (environments/production/hosts.ini)"]
C --> D["Muat Variabel (group_vars/ dan host_vars/)"]
D --> E["Jalankan Playbook Utama"]
E --> F{"Apakah playbook memanggil role?"}
F -- "Ya" --> G["Masuk ke folder roles/nginx/"]
G --> H["Muat defaults/main.yml (Prioritas Terendah)"]
H --> I["Muat vars/main.yml (Variabel Internal Role)"]
I --> J["Eksekusi tasks/main.yml (Instruksi Kerja)"]
J --> K{"Apakah task memicu Notify?"}
K -- "Ya" --> L["Eksekusi handlers/main.yml di akhir Play"]
K -- "Tidak" --> M["Lanjutkan ke Task berikutnya"]
F -- "Tidak" --> N["Eksekusi Tugas Playbook secara Linear"]
Manajemen Dependensi Pihak Ketiga dengan requirements.yml #
Ketika proyek kita membutuhkan otomatisasi kompleks (seperti memasang database server ter-cluster lengkap dengan monitoring), kita tidak perlu membuat role tersebut dari awal. Kita dapat mengunduh role atau koleksi stabil buatan komunitas yang tersedia di Ansible Galaxy.
Untuk mendokumentasikan dan mengelola versi dari pustaka pihak ketiga ini, kita menggunakan berkas bernama requirements.yml di direktori utama proyek.
Contoh Format File requirements.yml
#
# File: requirements.yml
---
# Bagian 1: Mengunduh Roles pihak ketiga
roles:
# Mengunduh role konfigurasi Nginx dari geerlingguy versi 3.2.0
- name: geerlingguy.nginx
version: "3.2.0"
# Mengunduh role PostgreSQL dari link repository Git eksternal
- src: https://github.com/geerlingguy/ansible-role-postgresql.git
scm: git
version: "main"
name: custom.postgresql
# Bagian 2: Mengunduh Collections pihak ketiga
collections:
# Mengunduh modul-modul AWS untuk kebutuhan komputasi awan
- name: amazon.aws
version: "6.1.0"
# Mengunduh modul Kubernetes komunitas
- name: kubernetes.core
version: "2.4.0"
Untuk menginstal seluruh dependensi yang tertera pada berkas di atas secara otomatis sebelum kita menjalankan playbook, jalankan perintah berikut di terminal:
# Instal seluruh roles ke direktori roles/ lokal
ansible-galaxy role install -r requirements.yml -p ./roles/
# Instal seluruh collections
ansible-galaxy collection install -r requirements.yml
Perbandingan Desain Anti-Pattern vs Best Practice #
Untuk mempermudah pemahaman tata letak berkas, di bawah ini disandingkan contoh desain yang salah (anti-pattern) dan desain yang benar (best practice) dalam pengelolaan folder proyek Ansible.
// ANTI-PATTERN: Menggabungkan semua berkas di folder utama (Monolitik & Kacau)
ansible-project-messy/
├── hosts.ini # Inventaris gabungan dev dan prod (Sangat Berbahaya)
├── ansible.cfg
├── setup-nginx-db-app.yml # Satu playbook berisi ratusan task campuran
├── nginx.conf # File konfigurasi statis tanpa variasi lingkungan
├── variables.yml # Semua variabel dicampur (dev, prod, db, nginx)
└── db-key.pem # Kredensial sensitif disimpan polos tanpa enkripsi
// BEST PRACTICE: Modular, Terisolasi, dan Menggunakan Enkripsi (Aman & Skalabel)
ansible-project-clean/
├── ansible.cfg
├── requirements.yml
├── environments/ # Lingkungan terisolasi secara fisik
│ ├── staging/
│ │ ├── hosts.ini
│ │ └── group_vars/
│ │ └── webservers.yml
│ └── production/
│ ├── hosts.ini
│ └── group_vars/
│ └── webservers.yml # Variabel sensitif dienkripsi dengan Ansible Vault
├── playbooks/ # Playbook modular terpisah sesuai tier
│ ├── site.yml
│ ├── webservers.yml
│ └── dbservers.yml
├── roles/ # Menggunakan role mandiri yang reusable
│ ├── common/
│ ├── nginx/
│ └── postgresql/
└── group_vars/ # Variabel global tingkat proyek
└── all.yml
Ringkasan #
- Modularitas Proyek — Menata proyek dengan struktur direktori yang terstandardisasi memisahkan logika playbook deklaratif dengan data inventaris dan variabel sensitif secara jelas.
- Pemisahan Lingkungan Fisik — Menyimpan inventaris di dalam subdirektori terpisah (seperti
environments/development/danenvironments/production/) menghindari resiko fatal salah eksekusi server target.- Hierarki group_vars & host_vars — Ansible membaca variabel group/host secara otomatis. Variabel di dekat inventaris (inventory-adjacent) memiliki prioritas lebih tinggi untuk menimpa variabel di dekat playbook (playbook-adjacent).
- Struktur Ansible Role — Role membagi fungsionalitas otomatisasi menjadi folder terstandar seperti
tasks/,defaults/,vars/,templates/, danhandlers/untuk memudahkan portabilitas antar proyek.- defaults vs vars di Role — Taruh variabel yang boleh disesuaikan oleh pengguna di folder
defaults/main.yml(prioritas terendah), dan kunci variabel internal sistem divars/main.yml(prioritas tinggi).- requirements.yml — Gunakan file ini untuk mendokumentasikan serta mengotomatisasi pengunduhan role dan collection eksternal dari Ansible Galaxy menggunakan perintah
ansible-galaxy.- Enkripsi Vault Terisolasi — Pisahkan berkas rahasia ke dalam group_vars tertentu untuk dienkripsi dengan Ansible Vault, tanpa perlu merubah folder tugas (tasks) utama.