Dynamic Inventory

Dynamic Inventory #

Static inventory bekerja baik saat infrastruktur stabil dan berubah jarang. Tapi di cloud atau lingkungan yang dinamis — server di-provision dan di-terminate setiap hari, container scale up dan down — memelihara file hosts.ini secara manual adalah pekerjaan yang tidak mungkin. Dynamic inventory menyelesaikan ini: Ansible mengambil daftar host secara real-time dari sumber yang otoritatif seperti AWS EC2, GCP, Azure, VMware, atau CMDB internal, setiap kali playbook dijalankan.

Menggunakan Inventory Plugin Bawaan (AWS EC2) #

Collection amazon.aws menyediakan inventory plugin aws_ec2 yang mengambil instance secara langsung dari AWS API:

ansible-galaxy collection install amazon.aws
pip install boto3
# inventory/aws_ec2.yml
# Nama file HARUS diakhiri dengan aws_ec2.yml atau aws_ec2.yaml

plugin: amazon.aws.aws_ec2

regions:
  - ap-southeast-1      # Singapura
  - ap-southeast-3      # Jakarta

# Filter: hanya ambil instance yang running
filters:
  instance-state-name: running
  "tag:Environment": production

# Gunakan private IP untuk koneksi internal
hostnames:
  - private-ip-address

# Kelompokkan instance berdasarkan tag
keyed_groups:
  - prefix: role
    key: tags.Role          # Group: role_webserver, role_database, dll.
  - prefix: env
    key: tags.Environment   # Group: env_production, env_staging

# Buat grup berdasarkan region
groups:
  singapore: "'ap-southeast-1' in placement.region"
  jakarta: "'ap-southeast-3' in placement.region"

# Tambahkan variabel dari tag EC2
compose:
  ansible_host: private_ip_address
  instance_type: instance_type
  availability_zone: placement.availability_zone
# Test inventory sebelum digunakan di playbook
ansible-inventory -i inventory/aws_ec2.yml --list
ansible-inventory -i inventory/aws_ec2.yml --graph

# Gunakan dalam playbook
ansible-playbook -i inventory/aws_ec2.yml site.yml

Inventory Plugin untuk GCP #

# inventory/gcp_compute.yml
plugin: google.cloud.gcp_compute

projects:
  - my-production-project

zones:
  - asia-southeast2-a    # Jakarta
  - asia-southeast2-b

filters:
  - status = RUNNING
  - labels.environment = production

keyed_groups:
  - prefix: role
    key: labels.role
  - prefix: zone
    key: zone

compose:
  ansible_host: networkInterfaces[0].networkIP

Untuk sumber inventory yang tidak punya plugin bawaan (CMDB internal, database legacy), buat inventory script Python:

#!/usr/bin/env python3
# inventory/cmdb_inventory.py

import json
import sys
import argparse

try:
    import requests
except ImportError:
    print(json.dumps({"_meta": {"hostvars": {}}}))
    sys.exit(0)

CMDB_URL = "https://cmdb.company.internal/api"
CMDB_TOKEN = "your-token-here"  # Gunakan env variable di production


def get_inventory():
    """Ambil semua server dari CMDB dan kelompokkan."""
    headers = {"Authorization": f"Bearer {CMDB_TOKEN}"}

    try:
        response = requests.get(
            f"{CMDB_URL}/servers",
            params={"status": "active"},
            headers=headers,
            timeout=15
        )
        response.raise_for_status()
        servers = response.json()
    except Exception as e:
        sys.stderr.write(f"Error mengambil inventory dari CMDB: {e}\n")
        return {"_meta": {"hostvars": {}}}

    inventory = {
        "_meta": {"hostvars": {}},
        "all": {"children": []},
    }

    for server in servers:
        hostname = server["hostname"]
        env = server.get("environment", "unknown")
        role = server.get("role", "unknown")

        # Tambahkan host variables
        inventory["_meta"]["hostvars"][hostname] = {
            "ansible_host": server.get("ip_address", hostname),
            "server_id": server.get("id"),
            "datacenter": server.get("datacenter"),
            "os": server.get("os"),
        }

        # Buat grup berdasarkan environment
        env_group = f"env_{env}"
        if env_group not in inventory:
            inventory[env_group] = {"hosts": [], "vars": {"env": env}}
            inventory["all"]["children"].append(env_group)
        inventory[env_group]["hosts"].append(hostname)

        # Buat grup berdasarkan role
        role_group = f"role_{role}"
        if role_group not in inventory:
            inventory[role_group] = {"hosts": []}
            inventory["all"]["children"].append(role_group)
        inventory[role_group]["hosts"].append(hostname)

    return inventory


def get_host(hostname):
    """Ambil variabel untuk host tertentu."""
    headers = {"Authorization": f"Bearer {CMDB_TOKEN}"}
    try:
        response = requests.get(
            f"{CMDB_URL}/servers/{hostname}",
            headers=headers,
            timeout=10
        )
        response.raise_for_status()
        server = response.json()
        return {
            "ansible_host": server.get("ip_address", hostname),
            "server_id": server.get("id"),
        }
    except Exception:
        return {}


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--list', action='store_true',
                        help='Tampilkan semua inventory')
    parser.add_argument('--host', type=str,
                        help='Tampilkan variabel untuk host tertentu')
    args = parser.parse_args()

    if args.list:
        print(json.dumps(get_inventory(), indent=2))
    elif args.host:
        print(json.dumps(get_host(args.host), indent=2))
    else:
        print(json.dumps({}))


if __name__ == '__main__':
    main()
# Beri permission executable
chmod +x inventory/cmdb_inventory.py

# Test
./inventory/cmdb_inventory.py --list
./inventory/cmdb_inventory.py --host web-01.company.com

# Gunakan dalam playbook
ansible-playbook -i inventory/cmdb_inventory.py site.yml

Menggabungkan Beberapa Sumber Inventory #

Ansible bisa menggabungkan beberapa sumber inventory sekaligus — cukup arahkan ke direktori:

inventory/
  ├── aws_ec2.yml           # Server di AWS
  ├── cmdb_inventory.py     # Server on-premise dari CMDB
  ├── static_hosts.ini      # Server khusus yang tidak ada di dua sumber di atas
  └── group_vars/
      ├── all.yml
      ├── role_webserver.yml
      └── env_production.yml
# Ansible otomatis menggabungkan semua sumber
ansible-playbook -i inventory/ site.yml

Caching Inventory #

Untuk infrastruktur besar, memanggil API cloud setiap kali playbook dijalankan lambat dan mungkin kena rate limit. Aktifkan caching:

# ansible.cfg
[inventory]
cache = true
cache_plugin = jsonfile
cache_connection = /tmp/ansible_inventory_cache
cache_timeout = 300   # Cache berlaku 5 menit
# Refresh cache manual saat diperlukan
ansible-inventory -i inventory/ --list --flush-cache

Ringkasan #

  • Inventory plugin (seperti aws_ec2, gcp_compute) lebih direkomendasikan dari inventory script — lebih terintegrasi dengan ekosistem Ansible dan mendukung caching bawaan.
  • Gunakan keyed_groups untuk otomatis membuat grup dari tag/label cloud — semua server dengan tag Role: webserver langsung masuk ke grup role_webserver.
  • compose untuk memetakan field API ke variabel Ansible — misalnya, ansible_host: private_ip_address memastikan Ansible menggunakan IP private, bukan public.
  • Inventory script Python harus mendukung flag --list dan --host — ini adalah interface yang diharapkan Ansible.
  • Gabungkan beberapa sumber dengan mengarahkan -i ke direktori — Ansible otomatis memuat semua file inventory di direktori tersebut.
  • Aktifkan caching inventory untuk menghindari API call berulang — sangat penting untuk infrastruktur cloud besar dengan ribuan instance.

← Sebelumnya: Custom Plugin   Berikutnya: Collection →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact