Variable #
Dalam pengembangan otomatisasi infrastruktur berskala besar, fleksibilitas adalah salah satu pilar utama keberhasilan. Kita tidak ingin membuat puluhan playbook yang hampir identik hanya karena beberapa parameter kecil—seperti port layanan, nama database, atau lokasi direktori backup—berbeda di setiap server. Ansible mengatasi masalah ini melalui mekanisme Variables (Variabel). Dengan memisahkan logika playbook yang bersifat statis dengan data parameter yang bersifat dinamis di dalam inventaris, kita dapat menggunakan satu playbook yang sama untuk mengatur ratusan server yang berbeda. Artikel ini membedah metode pendefinisian variabel inventaris, pemanfaatan struktur folder variabel kompleks, variabel koneksi penting, urutan prioritas (precedence), hingga pengelolaan variabel per-lingkungan.
Abstraksi Konfigurasi Dinamis #
Secara filosofis, variabel dalam inventaris Ansible berfungsi sebagai jembatan abstraksi yang dinamis. Melalui variabel, kita dapat menerapkan konsep pemrograman berorientasi objek dalam pengelolaan server: kita menetapkan perilaku dasar (methods) di tingkat playbook, sedangkan data properti (properties) disuntikkan secara dinamis saat playbook dieksekusi berdasarkan host target.
Hal ini memberikan tiga keuntungan operasional yang sangat besar:
- Dapat Digunakan Kembali (Reusability): Playbook kita terbebas dari nilai-nilai keras (hardcoded values) sehingga aman dibagikan di repositori publik.
- Keamanan Data Sensitif: Kita dapat memisahkan variabel bernilai rahasia (seperti token API) untuk dienkripsi secara khusus, sementara kode playbook tetap terbaca dengan jelas.
- Portabilitas Lingkungan: Kita dapat dengan mudah meniru susunan infrastruktur produksi ke lingkungan pengembangan lokal hanya dengan merubah file variabel terkait.
Tiga Metode Pendefinisian Variabel #
Ansible menyediakan tiga tempat utama untuk meletakkan variabel di tingkat inventaris. Pemilihan tempat ini menentukan kemudahan pemeliharaan seiring berkembangnya tim kita.
1. Langsung di dalam File Inventaris (Inline Variables) #
Metode ini mendefinisikan variabel langsung di sebelah alamat IP atau nama host pada file hosts.ini atau hosts.yml.
- Format INI (Inline Variables):
# File: inventory/hosts.ini [webservers] web-01.example.com http_port=80 max_clients=200 web-02.example.com http_port=8080 max_clients=100 [webservers:vars] nginx_version=1.24 deploy_dir=/opt/nginx - Format YAML (Inline Variables):
# File: inventory/hosts.yml --- webservers: hosts: web-01.example.com: http_port: 80 max_clients: 200 web-02.example.com: http_port: 8080 max_clients: 100 vars: nginx_version: "1.24" deploy_dir: /opt/nginx
# ANTI-PATTERN: Menumpuk variabel langsung di file inventaris
# hosts.ini
web-01.example.com http_port=80 max_clients=200 db_user=root db_pass=secret log_level=debug path=/opt/app
# BENAR: Biarkan file inventaris tetap bersih hanya berisi daftar host dan grup
# hosts.ini
web-01.example.com
Menuliskan variabel inline seperti contoh anti-pattern di atas sangat tidak dianjurkan untuk proyek jangka panjang karena merusak keterbacaan file inventaris dan mempersulit pelacakan perubahan variabel lewat Git commit history.
2. Menggunakan Direktori group_vars/ (Variabel Tingkat Grup) #
Ansible secara otomatis memuat seluruh variabel dari direktori bernama group_vars/ yang berada sejajar dengan file inventaris atau file playbook kita. Nama berkas YAML di dalam folder ini harus mewakili nama grup server target.
inventory/
├── hosts.ini
└── group_vars/
├── all.yml # Variabel global untuk seluruh host
├── webservers.yml # Hanya untuk host di grup webservers
└── dbservers.yml # Hanya untuk host di grup dbservers
Contoh isi berkas group_vars/webservers.yml:
# File: inventory/group_vars/webservers.yml
---
nginx_version: "1.24"
http_port: 80
https_port: 443
nginx_worker_processes: 4
deploy_path: /opt/webapp
3. Menggunakan Direktori host_vars/ (Variabel Tingkat Host) #
Untuk kasus di mana sebuah server memiliki parameter khusus yang berbeda dengan server lain di dalam grup yang sama (misalnya server database primary membutuhkan memori cache lebih besar dibanding replica), kita meletakkan variabelnya di direktori host_vars/.
inventory/
├── hosts.ini
└── host_vars/
├── db-primary.example.com.yml
└── db-replica-01.example.com.yml
Contoh isi berkas host_vars/db-primary.example.com.yml:
# File: inventory/host_vars/db-primary.example.com.yml
---
db_max_connections: 500
db_shared_buffers: "4GB"
# Indikator status primary server
db_is_primary: true
Struktur Folder untuk Variabel Kompleks #
Ketika proyek otomatisasi kita mengelola puluhan layanan yang kompleks, satu file group_vars/webservers.yml dapat membengkak hingga ratusan baris berisi campuran variabel Nginx, SSL, PHP, dan sistem pemantauan. Ini akan mempersulit proses modifikasi parameter.
Ansible mendukung pembagian variabel menggunakan struktur subdirektori. Kita dapat mengubah file group_vars/webservers.yml menjadi sebuah direktori bernama group_vars/webservers/, lalu membaginya ke dalam beberapa berkas terpisah berdasarkan kepentingannya:
inventory/group_vars/
├── all/
│ ├── common.yml
│ └── security.yml
│
└── webservers/ # Menggantikan file webservers.yml
├── main.yml # Variabel umum grup
├── nginx.yml # Konfigurasi spesifik web server Nginx
├── php-fpm.yml # Konfigurasi PHP processor
└── monitoring.yml # Variabel agen pemantau prometheus
Ansible akan memproses seluruh berkas berakhiran .yml atau .yaml di dalam folder webservers/ secara alfabetis dan menggabungkannya ke dalam satu namespace variabel grup webservers.
Bedah Parameter Koneksi Penting #
Ansible memiliki kumpulan variabel khusus bawaan yang diawali dengan kata kunci ansible_. Variabel ini bukan digunakan untuk konfigurasi aplikasi kita, melainkan untuk mengatur perilaku taktis koneksi SSH dan otentikasi dari control node menuju managed node.
Berikut daftar variabel koneksi yang wajib kita pahami:
ansible_host: Alamat IP aktual atau nama host alternatif yang digunakan untuk koneksi jika nama host yang terdaftar di inventaris hanyalah sebuah alias.# Contoh penggunaan alias di hosts.ini: # prod-web-01 ansible_host=10.0.4.12ansible_port: Port koneksi SSH target jika managed node dikonfigurasi untuk tidak menggunakan port SSH default (22).ansible_user: Nama pengguna (username) yang digunakan untuk masuk ke target server via SSH.ansible_ssh_private_key_file: Jalur ke file kunci privat SSH (misalnya~/.ssh/id_ed25519) jika kita tidak menggunakan agent forwarding.ansible_python_interpreter: Menentukan jalur absolut interpreter Python di server target. Sangat penting jika target server menggunakan versi Python kustom (seperti/usr/bin/python3pada Ubuntu modern atau/usr/libexec/platform-pythonpada RHEL 8).ansible_connection: Jenis koneksi yang digunakan. Default-nya adalahssh. Opsi lainnya adalahlocal(untuk mengeksekusi mekanisme lokal di control node) atauwinrm(untuk server Windows via WinRM).ansible_ssh_common_args: Menambahkan argumen SSH tambahan yang bersifat global. Parameter ini sangat penting dalam topologi jaringan aman produksi di mana server managed node kita berada di dalam sub-jaringan tertutup (private subnet) tanpa akses IP publik langsung. Kita dapat menggunakan proxy tunneling melewati mesin Bastion (Jump Host):# Contoh melewatkan koneksi SSH ke target server melalui Bastion Host ansible_ssh_common_args: '-o ProxyCommand="ssh -W %h:%p -q [email protected]"'ansible_ssh_extra_args: Digunakan untuk menambahkan argumen SSH ekstra yang hanya ditempelkan pada eksekusi perintah pemindahan data (seperti SFTP/SCP), sedangkan koneksi interaktif tetap menggunakan konfigurasi umum.ansible_ssh_pass&ansible_become_pass: Menyimpan password SSH dan password eskalasi privilege sudo. Ingat, menyimpan data ini secara plaintext di file variabel adalah ancaman keamanan tinggi. Parameter ini harus selalu dienkripsi via Ansible Vault.
Contoh konfigurasi global parameter koneksi di group_vars/all.yml:
# File: inventory/group_vars/all.yml
---
ansible_user: deployer
ansible_port: 22
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
ansible_python_interpreter: /usr/bin/python3
ansible_become: true
ansible_become_method: sudo
Hierarki dan Urutan Precedence #
Salah satu aspek yang paling sering memicu kebingungan dan kegagalan logika eksekusi playbook adalah pemahaman yang salah tentang Precedence (Urutan Prioritas). Ketika sebuah variabel dengan nama yang sama didefinisikan di beberapa tempat sekaligus, Ansible akan menerapkan aturan resolusi prioritas yang ketat.
Berikut urutan prioritas variabel khusus di tingkat inventaris, diurutkan dari prioritas terendah (paling mudah ditimpa) ke prioritas tertinggi (paling kuat menimpa):
Prioritas Variabel Inventaris (Prioritas Rendah ke Tinggi):
1. group_vars/all (Tingkat Global) ← Prioritas Terendah
2. group_vars/parent (Grup Induk) ← Mewarisi properti dasar
3. group_vars/child (Grup Anak) ← Lebih spesifik dari induk
4. host_vars (Tingkat Host Spesifik) ← Prioritas Tertinggi Inventaris
Visualisasi pewarisan prioritas ini dapat dilihat pada diagram berikut:
flowchart TD
A["group_vars/all (Prioritas 1)"] -->|"Ditimpa oleh"| B["group_vars/parent (Prioritas 2)"]
B -->|"Ditimpa oleh"| C["group_vars/child (Prioritas 3)"]
C -->|"Ditimpa oleh"| D["host_vars/host.yml (Prioritas 4)"]
D -->|"Ditimpa oleh"| E["Variabel tingkat Playbook / CLI (Prioritas 5+)"]
Studi Kasus Nyata Resolusi Precedence: #
Misalkan kita mendefinisikan port aplikasi http_port di beberapa file berikut:
- Di dalam
group_vars/all.yml(semua server):http_port: 80 - Di dalam
group_vars/webservers.yml(grup web):http_port: 8080 - Di dalam
host_vars/web-01.example.com.yml(host tertentu):http_port: 9090
Hasil resolusi akhir saat Ansible memproses variabel:
- Untuk server
web-01.example.com, nilaihttp_portadalah9090(karenahost_varsmenimpa semuanya). - Untuk server
web-02.example.com(yang juga anggota grupwebservers), nilaihttp_portadalah8080(karena ditimpa olehgroup_vars/webservers). - Untuk server
db-01.example.com(yang bukan anggota grupwebservers), nilaihttp_portadalah80(menggunakan nilai global darigroup_vars/all).
Strategi Multi-Lingkungan #
Dalam siklus rilis aplikasi modern, kita wajib mengisolasi konfigurasi antara lingkungan Pengembangan (development), Pengujian (staging), dan Produksi (production). Kita menggunakan playbook yang sama, namun menyuntikkan variabel yang berbeda untuk masing-masing lingkungan menggunakan arsitektur folder inventaris terpisah.
Jalur implementasi layout multi-lingkungan:
environments/
├── staging/
│ ├── hosts.ini
│ └── group_vars/
│ ├── all.yml # Variabel global lingkungan Staging
│ └── webservers.yml # Konfigurasi web server Staging
│
└── production/
├── hosts.ini
└── group_vars/
├── all.yml # Variabel global lingkungan Produksi
└── webservers.yml # Konfigurasi web server Produksi
Perbedaan Nilai Variabel Berdasarkan Lingkungan #
- Staging (
environments/staging/group_vars/all.yml):env_label: "staging" db_host: "staging-db.internal" enable_debug_mode: true log_level: "debug" - Produksi (
environments/production/group_vars/all.yml):env_label: "production" db_host: "prod-db-cluster.internal" enable_debug_mode: false log_level: "error"
Ketika kita memicu eksekusi, perbedaan perilaku ini dikontrol secara eksplisit dari baris perintah terminal kita:
# Menjalankan deployment ke staging
ansible-playbook -i environments/staging/ playbooks/deploy.yml
# Menjalankan deployment ke produksi
ansible-playbook -i environments/production/ playbooks/deploy.yml
Anti-Pattern dan Mitigasi #
Berikut adalah beberapa kesalahan umum (anti-pattern) dalam pengelolaan variabel inventaris beserta cara mengatasinya.
1. Menyimpan Kredensial Sensitif secara Polos (Plaintext Secrets) #
Menyimpan token API, password database, atau private key SSH langsung di file YAML dalam format plaintext yang dapat dibaca oleh siapa saja.
# ANTI-PATTERN: Kredensial polos di group_vars/all.yml
db_password: "MySuperSecretDBPassword123"
- Mitigasi: Selalu gunakan Ansible Vault untuk mengenkripsi variabel sensitif. Kita direkomendasikan memisahkan variabel non-sensitif dengan variabel sensitif ke dalam file terpisah di dalam folder grup yang sama:
- File non-sensitif:
group_vars/webservers/vars.yml - File terenkripsi:
group_vars/webservers/vault.yml(dienkripsi dengan perintahansible-vault encrypt)
- File non-sensitif:
2. Duplikasi Variabel yang Berlebihan #
Mendefinisikan parameter yang bernilai sama di setiap berkas grup variabel secara berulang kali.
# ANTI-PATTERN: Duplikasi data di group_vars/webservers.yml dan group_vars/dbservers.yml
# group_vars/webservers.yml
timezone: "Asia/Jakarta"
ntp_server: "time.unisbadri.com"
# group_vars/dbservers.yml
timezone: "Asia/Jakarta"
ntp_server: "time.unisbadri.com"
- Mitigasi: Pindahkan seluruh parameter yang bersifat homogen (sama untuk semua server) ke dalam berkas global
group_vars/all.yml. Berkas grup spesifik hanya boleh berisi variabel yang unik untuk grup tersebut.
Ringkasan #
- Pemisahan Logika & Parameter — Variabel memisahkan alur eksekusi playbook yang statis dengan data konfigurasi dinamis target server untuk mengoptimalkan reusability.
- Tiga Metode Deklarasi — Variabel tingkat inventaris dapat ditulis secara inline di file hosts, dalam berkas
group_vars/(grup), atau berkashost_vars/(host spesifik).- Abstraksi Folder Kompleks — Mengganti file grup YAML tunggal menjadi sebuah direktori dengan berkas-berkas terpisah berbasis concern (seperti
nginx.yml,ssl.yml) memudahkan pemeliharaan jangka panjang.- Variabel Otentikasi Khusus — Opsi penentuan perilaku koneksi dikelola oleh parameter internal seperti
ansible_user,ansible_port, danansible_python_interpreter.- Aturan Precedence Ketat — Pewarisan variabel mengikuti urutan prioritas:
host_varsmenimpagroup_vars/child, yang kemudian menimpagroup_vars/parent, lalu menimpagroup_vars/all.- Isolasi Multi-Lingkungan — Pembagian data parameter dev/staging/production dikelola melalui pemisahan direktori inventaris secara fisik di bawah folder
environments/.- Pencegahan Kebocoran Kredensial — Selalu gunakan enkripsi Ansible Vault untuk melindungi parameter sensitif (kunci rahasia, password) sebelum mengunggah kode otomatisasi ke Git.