Mendalami dynamic inventory untuk AWS EC2, Google Cloud, Azure, dan VMware menggunakan inventory plugins, keyed groups, compose variables, hingga custom inventory script dan integrasi dengan CMDB seperti NetBox dan ServiceNow.

Setelah di episode 20 sebelumnya kita membahas modern execution environments seperti AAP/AWX, ansible-navigator, dan ansible-builder yang menjawab masalah konsistensi lingkungan eksekusi antar engineer, pada episode kali ini kita akan membahas fondasi yang sering kali menjadi penentu keberhasilan seluruh automasi di environment cloud: inventory management tingkat lanjut dan dynamic inventory.
Bayangkan kalian memegang daftar belanja yang ditulis tangan untuk puluhan toko yang bisa berubah jumlah kapan saja. Setiap kali ada toko baru buka atau tutup, kalian harus memperbarui catatan itu secara manual — rentan telat, keliru, dan melelahkan. Itulah kondisi nyata saat tim DevOps masih mengelola inventory Ansible secara statis di era auto-scaling: instance baru dibuat oleh Auto Scaling Group dalam hitungan menit, lalu dihancurkan saat trafik turun. Kalau daftar host kalian tidak ikut berubah otomatis, playbook akan menjalankan task ke server yang sudah tidak ada, atau melewatkan server baru yang justru paling butuh konfigurasi.
Karena itulah dynamic inventory bukan lagi "fitur bagus", melainkan kebutuhan wajib di dunia cloud. Pada episode ini kita akan membahas tiga pilar utama: inventory plugins untuk cloud provider (AWS, GCP, Azure, dan VMware), konfigurasi plugin tingkat lanjut seperti filtering, keyed groups, dan composed variables, serta custom inventory scripts dan integrasi dengan CMDB seperti NetBox dan ServiceNow.
Sejak episode 3, kita sudah mengenal inventory statis dalam format INI maupun YAML. Inventory statis bekerja sangat baik untuk sekumpulan server yang relatif tetap — misalnya 5 server VM on-premise yang jarang berubah. Masalahnya muncul ketika infrastruktur mulai berpindah ke cloud:
Solusinya adalah dynamic inventory: Ansible meminta daftar host secara langsung kepada API cloud provider setiap kali dibutuhkan, lalu menyusunnya menjadi struktur inventory di dalam memori. Kalian tidak pernah menyimpan daftar host, melainkan menyimpan aturan tentang bagaimana daftar itu harus dibentuk.
Ada dua era pendekatan dynamic inventory di Ansible:
| Aspek | Inventory Script (Legacy) | Inventory Plugin (Modern) |
|---|---|---|
| Bentuk | Skrip eksekutabel (Python/Bash) yang mencetak JSON | File konfigurasi YAML yang mendeskripsikan aturan |
| Instalasi | Manual, harus di-chmod +x | Bagian dari collection, cukup install via Galaxy |
| Logika filter/grouping | Ditulis manual di dalam skrip | Deklaratif lewat filters, keyed_groups, compose |
| Kredensial | Disimpan di env vars / file | Bisa via env vars, file, atau Ansible Vault |
| Pemeliharaan | Tersebar, sulit di-audit | Terpusat, mudah di-review via Git |
Ansible kini mendorong penggunaan inventory plugins karena lebih deklaratif, teruji, dan ikut terbundel dalam collection resmi cloud provider. Namun memahami format JSON yang dikeluarkan script tetap penting — ini akan kita bahas di bagian custom inventory script.
Plugin AWS EC2 bernama amazon.aws.aws_ec2. Plugin ini membaca daftar instance EC2 dari API AWS dan mengubahnya menjadi host Ansible. Syaratnya, collection amazon.aws terpasang dan kredensial AWS tersedia (biasanya lewat environment variable, file ~/.aws/credentials, atau IAM role).
Tip
Kredensial AWS bisa diatur lewat environment variable AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, dan AWS_DEFAULT_REGION, atau memanfaatkan instance profile jika control node berjalan di dalam AWS. Jangan pernah menaruh access key di dalam file inventory secara hardcode.
Install collection yang dibutuhkan terlebih dahulu:
ansible-galaxy collection install amazon.awsSelanjutnya buat file konfigurasi plugin. Nama file harus diakhiri pola tertentu agar dikenali sebagai inventory plugin — untuk AWS, file yang berakhiran aws_ec2.yml atau aws_ec2.yaml akan otomatis dibaca sebagai plugin aws_ec2. Berikut contoh konfigurasi lengkapnya:
plugin: amazon.aws.aws_ec2
regions:
- ap-southeast-1
- us-east-1
filters:
tag:Env: production
tag:Project: "{{ project_name }}"
instance-state-name: running
hostnames:
- tag:Name
- dns-name
- private-ip-address
keyed_groups:
- key: tags.Environment
prefix: env
separator: ""
- key: placement.region
prefix: region
- key: "tags.Role"
prefix: role
compose:
ansible_host: public_ip_address
ansible_user: ubuntu
instance_type: instance_type
vpc_id: vpc_id
strict: falseMari kita bedah satu per satu:
plugin: amazon.aws.aws_ec2 — menunjuk inventory plugin yang digunakan. Wajib menjadi key pertama.regions — membatasi pencarian instance pada region tertentu. Mencari di semua region memperlambat eksekusi, jadi selalu sempitkan.filters — menyaring instance berdasarkan atribut yang didukung AWS. Di sini kita hanya mengambil instance dengan tag Env: production, Project: <project_name>, dan berstatus running.hostnames — menentukan nama host yang dipakai Ansible, berurutan dari prioritas tertinggi. Urutan di atas: pakai nilai tag Name, fallback ke dns-name, terakhir private-ip-address.keyed_groups — membuat group secara otomatis berdasarkan nilai metadata. Ini adalah kunci utama grouping otomatis yang akan kita bahas lebih dalam sebentar lagi.compose — menetapkan atau menimpa host variables dengan ekspresi Jinja2. Di contoh ini ansible_host diisi dari IP publik instance.strict: false — jika true, error pada keyed_groups/compose yang tidak terdefinisi akan menggagalkan inventory; jika false, baris tersebut dilewati dengan peringatan.Filtering adalah mekanisme untuk "memangkas" daftar instance sebelum masuk ke inventory. Di AWS EC2 plugin, filter mengikuti sintaks AWS EC2 DescribeInstances. Beberapa pola yang paling sering dipakai:
| Tujuan | Sintaks Filter |
|---|---|
| Hanya instance yang berjalan | instance-state-name: running |
| Berdasarkan tag tunggal | tag:Env: production |
| Berdasarkan kombinasi tag | tag:Env: production + tag:Role: web (dibaca sebagai AND) |
| Berdasarkan instance type | instance-type: t3.micro |
| Berdasarkan VPC | vpc-id: vpc-0abc1234def56789 |
| Berdasarkan security group | instance.group-name: sg-web |
Filter bersifat server-side — penyaringan terjadi di sisi API AWS, bukan di sisi Ansible. Ini berarti daftar yang dikembalikan sudah ramping sejak awal, menghemat waktu transfer dan parsing.
Keyed groups adalah fitur yang membuat group inventory secara otomatis dari nilai sebuah metadata. Analoginya seperti sistem arsip otomatis: setiap kali ada dokumen baru masuk, ia langsung ditempatkan ke laci yang sesuai berdasarkan labelnya, tanpa kalian menulis satu per satu.
Dengan konfigurasi keyed_groups di atas, instance dengan tag Environment: production dan Role: web akan otomatis masuk ke group env_production dan role_web. Keuntungannya besar:
hosts: env_production tanpa pernah menyebut nama host satu pun.env_production maupun env_staging tinggal ganti pola host.Sementara itu, composed variables memungkinkan kalian menghitung nilai host variable secara dinamis. Ini sangat berguna untuk menyesuaikan detail koneksi per host — misalnya ansible_host dari IP publik, atau ansible_user yang berbeda untuk AMI yang berbeda:
compose:
ansible_host: public_ip_address
ansible_user: "'{{ 'ubuntu' if 'ubuntu' in image_id else 'ec2-user' }}'"
instance_role: "tags.Role"Important
Pada compose, ekspresi Jinja2 yang berupa string literal harus ditulis dalam kutip di dalam kutip, misalnya ansible_user: "'ubuntu'", agar dievaluasi sebagai string bukan nama variabel. Untuk ekspresi yang melibatkan logika percabangan, bungkus seluruh ekspresi dalam string ganda seperti contoh di atas.
ansible-inventorySetelah konfigurasi siap, kita harus memastikan hasilnya benar sebelum menjalankan playbook. Alat utamanya adalah ansible-inventory:
ansible-inventory -i aws_ec2.yml --listansible-inventory -i aws_ec2.yml --graphOutput dari --graph akan terlihat seperti ini:
@all:
|--@aws_ec2:
| |--@env_production:
| | |--@region_ap-southeast-1:
| | | |--@role_web:
| | | | |--web-prod-01
| | | | |--web-prod-02
| | | |--@role_db:
| | | | |--db-prod-01
| | |--@region_us-east-1:
| | | |--@role_worker:
| | | | |--worker-prod-01
| |--@ungrouped:
| | |--legacy-serverGrafik di atas menunjukkan bagaimana group tersusun bertingkat dari keyed_groups. Kalian bisa langsung menargetkan hosts: role_web, hosts: env_production, atau bahkan kombinasi hosts: env_production:&role_web — persis seperti pola host matching yang kita pelajari di episode 3.
Selain AWS, Ansible memiliki plugin resmi untuk cloud provider utama. Pola konfigurasinya sangat mirip karena semuanya mengekstensi mekanisme constructed yang sama (filters, keyed_groups, compose). Mari kita lihat satu per satu.
Plugin google.gcp.gcp_compute mengambil daftar instance Compute Engine. Kredensial GCP bisa berupa service account file atau google.cloud.auth plugin. Contoh konfigurasinya:
plugin: google.gcp.gcp_compute
auth_kind: serviceaccount
service_account_file: /opt/ansible/credentials/gcp-service-account.json
project: my-company-project
zones:
- asia-southeast1-a
filters:
- status = RUNNING
- labels.env = production
hostnames:
- name
keyed_groups:
- key: labels.role
prefix: gcp_role
- key: zone
prefix: gcp_zone
compose:
ansible_host: networkInterfaces[0].accessConfigs[0].natIP
strict: falsePlugin azure.azcollection.azure_rm memanfaatkan kredensial service principal yang biasanya diset via environment variable (AZURE_SUBSCRIPTION_ID, AZURE_TENANT, AZURE_CLIENT_ID, AZURE_SECRET):
plugin: azure.azcollection.azure_rm
auth_source: env
hostname:
- name
- default
conditional_groups:
production: "'prod' in tags.env | default('dev')"
keyed_groups:
- key: tags.role
prefix: az_role
- key: resource_group
prefix: az_rg
groups:
azure: true
compose:
ansible_host: private_ipv4_addresses[0]Untuk lingkungan on-premise maupun hybrid, plugin community.vmware.vmware_vm_inventory mengambil daftar virtual machine langsung dari vCenter:
plugin: community.vmware.vmware_vm_inventory
strict: false
hostname: vcenter01.company.internal
username: administrator@vsphere.local
password: "{{ vault_vsphere_password }}"
validate_certs: false
with_tags: true
properties:
- name
- config.name
- guest.ipAddress
- summary.runtime.powerState
filters:
- summary.runtime.powerState == "poweredOn"
hostnames:
- config.name
keyed_groups:
- key: guest.guestId
prefix: vm_os
- key: tag_category.Environment
prefix: vm_env
compose:
ansible_host: guest.ipAddressWarning
Kredensial vCenter (password di atas) sebaiknya dienkripsi menggunakan Ansible Vault yang sudah kita pelajari di episode 14. Jika file inventory ter-bundle Vault, jalankan ansible-inventory atau playbook dengan --ask-vault-pass atau --vault-password-file. Ingat: kredensial cloud di dalam file inventory adalah risiko keamanan serius bila ter-bocor ke repository publik.
Berikut tabel referensi plugin yang bisa kalian jadikan acuan cepat:
| Cloud / Platform | Collection | Plugin Inventory | Suffix File |
|---|---|---|---|
| AWS EC2 | amazon.aws | amazon.aws.aws_ec2 | aws_ec2.yml |
| Google Cloud | google.gcp | google.gcp.gcp_compute | gcp_compute.yml |
| Microsoft Azure | azure.azcollection | azure.azcollection.azure_rm | azure_rm.yml |
| VMware vSphere | community.vmware | community.vmware.vmware_vm_inventory | vmware_vm_inventory.yml |
| NetBox (CMDB) | netbox.netbox | netbox.netbox.nb_inventory | netbox_inventory.yml |
| ServiceNow ITSM | servicenow.itsm | servicenow.itsm.now | now.yml |
| Kubernetes | kubernetes.core | kubernetes.core.k8s | k8s.yml |
Note
Pola suffix file sangat penting. Ansible mengenali sebuah inventory plugin hanya jika nama file diakhiri dengan pola yang didaftarkan plugin tersebut. Jika file kalian bernama inventory-aws.yml, plugin aws_ec2 tidak akan terpanggil dan Ansible akan menganggapnya file inventory statis biasa — error klasik yang membingungkan banyak orang.
ansible.cfgBeberapa inventory plugin perlu diaktifkan secara eksplisit di ansible.cfg, terutama di versi Ansible yang membatasi daftar plugin yang boleh berjalan:
[inventory]
enable_plugins = aws_ec2, gcp_compute, azure_rm, vmware_vm_inventorySelain itu, aktifkan inventory caching agar Ansible tidak memanggil API cloud setiap kali eksekusi — ini menghemat waktu secara signifikan untuk inventory besar:
[inventory]
enable_plugins = aws_ec2, gcp_compute, azure_rm, vmware_vm_inventory
cache = true
cache_plugin = ansible.builtin.jsonfile
cache_connection = /tmp/ansible_inventory
cache_timeout = 3600Tip
Nilai cache_timeout sebaiknya disesuaikan dengan siklus hidup instance kalian. Untuk environment yang jarang berubah, 3600 detik (1 jam) sangat wajar. Untuk environment auto-scaling yang agresif, pertimbangkan cache_timeout: 300 (5 menit) agar inventory tidak tertinggal dari kondisi nyata.
Meskipun inventory plugins sudah mencakup mayoritas kebutuhan, tetap ada kalanya kalian perlu menarik data dari sistem internal yang belum punya plugin resmi — misalnya API internal tim, database asset management, atau spreadsheet kepemilikan. Di sinilah custom inventory script berperan.
Kontraknya sederhana: skrip menerima argumen --list (dan opsional --host <host>) dan mengeluarkan JSON. Sejak Ansible 2.4, seluruh data bisa dikirim sekaligus melalui key khusus _meta sehingga --host jarang dipakai. Berikut kerangka minimal skrip Python:
#!/usr/bin/env python3
import json
import sys
import argparse
def build_inventory():
inventory = {
"web_servers": {
"hosts": ["web-01.internal", "web-02.internal"],
"vars": {
"ansible_user": "ubuntu",
"nginx_port": 8080,
},
},
"db_servers": {
"hosts": ["db-01.internal"],
},
"_meta": {
"hostvars": {
"web-01.internal": {"ansible_host": "10.0.1.11"},
"web-02.internal": {"ansible_host": "10.0.1.12"},
"db-01.internal": {"ansible_host": "10.0.2.11"},
}
},
}
return inventory
def main():
parser = argparse.ArgumentParser(description="Custom dynamic inventory")
parser.add_argument("--list", action="store_true")
parser.add_argument("--host", nargs="?")
args = parser.parse_args()
inventory = build_inventory()
if args.list:
print(json.dumps(inventory, indent=2))
elif args.host:
host = args.host
print(json.dumps(inventory["_meta"]["hostvars"].get(host, {})))
else:
sys.exit("Argumen --list atau --host wajib diberikan")
if __name__ == "__main__":
main()Struktur JSON di atas terdiri dari:
web_servers, db_servers) — key utama adalah nama group, berisi hosts dan optional vars._meta.hostvars — berisi host variables untuk setiap host. Seluruhnya dikirim sekaligus agar Ansible tidak memanggil skrip per host.{}.Agar dapat dipakai, skrip harus executable:
chmod +x custom_inventory.py
./custom_inventory.py --list
ansible-inventory -i custom_inventory.py --graphSkrip ini tidak perlu menunggu output yang kompleks — yang penting strukturnya mengikuti kontrak di atas. Kalian bisa mengganti build_inventory() dengan panggilan ke API CMDB, query database, atau parsing file CSV.
Pola yang semakin umum di perusahaan besar adalah menjadikan CMDB sebagai sumber kebenaran (source of truth) untuk daftar server, bukan meng-query setiap cloud provider secara terpisah. Manfaatnya: satu kanal data yang konsisten, mencakup hybrid infrastructure, lengkap dengan relasi aplikasi, owner, dan lifecycle.
NetBox adalah open-source CMDB / IPAM yang populer di kalangan network dan infra engineer. Ansible punya plugin inventory resmi netbox.netbox.nb_inventory:
plugin: netbox.netbox.nb_inventory
api_endpoint: https://netbox.company.internal
token: "{{ vault_netbox_token }}"
validate_certs: true
group_by:
- device_roles
- sites
- status
query_filters:
- role: server
- status: active
keyed_groups:
- key: device_roles[0].name
prefix: nb_role
compose:
ansible_host: primary_ip4.addressServiceNow ITSM juga menyediakan inventory plugin servicenow.itsm.now yang membaca data langsung dari tabel CMDB (cmdb_ci_server secara default). Kredensial diambil dari environment variable SN_HOST, SN_USERNAME, SN_PASSWORD, atau blok instance di dalam file:
plugin: servicenow.itsm.now
table: cmdb_ci_server
query:
- os: = Linux Red Hat
- os: = Ubuntu Linux
sysparm_limit: 5000
keyed_groups:
- key: manufacturer
separator: ""
- key: environment
prefix: sn_env
compose:
ansible_host: fqdn
ansible_user: "'cloud-user'"Note
Dengan pola CMDB seperti ini, satu set playbook bisa menjangkau server dari banyak cloud provider sekaligus (AWS, GCP, Azure, bahkan bare-metal) hanya dengan mengarahkan inventory ke NetBox atau ServiceNow. Ini adalah pola kunci untuk organisasi dengan hybrid & multi-cloud infrastructure, dan menjadi fondasi yang akan kita gunakan ketika membahas network automation di episode berikutnya.
1. Kredensial hardcode di file inventory
Menaruh access key AWS atau password vCenter langsung di aws_ec2.yml. File ini biasanya masuk version control, sehingga kredensial bisa bocor. Solusinya: gunakan environment variable, file kredensial terpisah, atau Ansible Vault.
2. Lupa menginstall collection
Menjalankan plugin amazon.aws.aws_ec2 tanpa ansible-galaxy collection install amazon.aws akan menghasilkan error Unable to load inventory plugin. Pastikan collection terpasang di control node atau tercantum di requirements.yml (ingat kembali episode 13).
3. Salah penamaan file
Menamai file inventory-aws.yml padahal pola yang diharapkan aws_ec2.yml. Akibatnya file dianggap inventory statis dan hasilnya kosong atau error YAML. Gunakan suffix persis sesuai tabel plugin.
4. Menargetkan semua region tanpa filter
Konfigurasi tanpa regions akan memindai semua region dan bisa sangat lambat, bahkan berisiko terkena rate limit API. Sempitkan regions dan gunakan filters sedini mungkin.
5. Salah memahami underscore pada keyed_groups
Secara default, keyed group dengan prefix dan separator akan menghasilkan nama seperti env_production (underscore dari separator). Jika kalian ingin nama tanpa pemisah atau tanpa underscore diawal, atur separator: "" dan leading_separator: false.
6. Tidak memverifikasi dengan ansible-inventory
Langsung menjalankan playbook tanpa memeriksa hasil inventory. Selalu jalankan ansible-inventory -i <file> --graph dulu untuk memastikan host dan group terbentuk sesuai harapan.
Pada episode ini kita telah membahas advanced inventory management secara menyeluruh: mengapa static inventory tidak lagi memadai di era cloud, cara kerja inventory plugins untuk AWS EC2, GCP, Azure, dan VMware lengkap dengan filtering, keyed groups, dan composed variables, teknik verifikasi dengan ansible-inventory, custom inventory script Python yang mengikuti kontrak JSON Ansible, serta integrasi dengan CMDB melalui NetBox dan ServiceNow. Kita juga sudah mengupas kesalahan-kesalahan umum beserta solusinya.
Dengan dynamic inventory, playbook kalian kini menjadi environment-aware dan scale-ready: server baru muncul di inventory secara otomatis, dan group-group terbentuk sendiri mengikuti metadata. Ini adalah salah satu pembeda terbesar antara automasi yang hanya "jalan di lab" dan automasi yang siap bertahan di produksi berskala besar.
Di episode 22 selanjutnya, kita akan membahas topik yang menantang dan menarik sekaligus, yaitu Network Automation dengan Ansible — mengelola perangkat jaringan seperti Cisco IOS/NX-OS, Arista EOS, dan Juniper Junos secara terprogram menggunakan collection jaringan, koneksi network_cli, httpapi, dan netconf, lengkap dengan backup running-config otomatis dan deploy konfigurasi templated ke banyak switch sekaligus. Pastikan tetap semangat!