Panduan Otomasi Infrastruktur dengan Ansible

Foto oleh Coding Ninjas

Foto oleh Coding Ninjas
Otomasi infrastruktur Ansible mengubah tugas setup server yang berulang menjadi kode yang dapat diulang dan dikontrol versi. Alih-alih SSH ke setiap server dan menjalankan perintah secara manual, Anda menulis playbook — file YAML yang mendeskripsikan state yang diinginkan dari infrastruktur Anda. Ansible kemudian terhubung melalui SSH, menjalankan langkah-langkah yang diperlukan secara idempoten, dan meninggalkan server Anda dalam keadaan yang tepat seperti yang Anda tentukan. Tidak ada agen yang perlu diinstal, tidak ada control plane yang rumit — cukup Python di host remote dan akses SSH.
Arsitektur Ansible sengaja dibuat sederhana. Mesin lokal Anda (atau server CI) adalah control node. Anda mendeskripsikan host remote mana yang akan dikelola dalam file inventory, dan apa yang harus dilakukan padanya dalam playbook. Ketika Anda menjalankan 'ansible-playbook site.yml', Ansible terhubung ke setiap host melalui SSH secara paralel, mengunggah modul Python kecil, mengeksekusinya, mengalirkan hasilnya kembali, dan membersihkan — tidak meninggalkan apa pun yang persisten di host remote.
File inventory memetakan hostname atau alamat IP ke grup. Grup memungkinkan Anda menargetkan set host tertentu dengan play yang berbeda — misalnya play '[webservers]' menginstal Nginx dan aplikasi Anda, sementara play '[dbservers]' menginstal PostgreSQL. Inventory bisa statis (file INI atau YAML) atau dinamis (skrip atau plugin yang memquery AWS EC2, GCP, atau API mana pun).
Variabel Ansible memungkinkan Anda memparameterisasi playbook. Tetapkan variabel di level inventory, grup, host, atau inline dalam play. Mesin templating Jinja2 menggerakkan baik interpolasi variabel maupun template file (templates/*.j2). Pola umum adalah menyimpan file 'group_vars/all.yml' dengan default bersama dan mengoverride nilai tertentu dalam 'host_vars/<hostname>.yml'.
Gunakan 'ansible-playbook site.yml --check' (mode dry-run) untuk mempratinjau apa yang akan diubah Ansible tanpa membuat modifikasi nyata apa pun. Gabungkan dengan '--diff' untuk melihat perubahan konten yang tepat untuk task file. Ini sangat berharga untuk meninjau perubahan infrastruktur sebelum menerapkannya ke produksi.
Playbook yang baik bersifat idempoten — menjalankannya dua kali menghasilkan hasil yang sama dengan menjalankannya sekali. Modul Ansible dirancang untuk idempotency: 'apt: state=present' hanya menginstal paket jika belum terinstal, 'file: state=link' hanya membuat symlink jika belum ada. Tulis task kustom dengan kondisi 'creates:' atau 'when:' untuk menjaga idempotency untuk perintah shell.
Playbook di bawah ini mem-provisioning environment web server yang lengkap: menginstal paket sistem, menyiapkan Node.js via repositori NodeSource, men-deploy kode aplikasi menggunakan rsync, menginstal dependensi npm, mengkonfigurasi Nginx sebagai reverse proxy dari template Jinja2, dan memastikan semua service dimulai dan diaktifkan. Handler memisahkan aksi 'reload nginx' dari task yang memicunya.
# inventory.ini
[webservers]
web1.example.com ansible_user=ubuntu
web2.example.com ansible_user=ubuntu
[dbservers]
db1.example.com ansible_user=ubuntu
# site.yml — master playbook
---
- name: Provision web servers
hosts: webservers
become: yes
vars:
node_version: "20"
app_port: 3000
tasks:
- name: Install system dependencies
apt:
name:
- curl
- git
- nginx
state: present
update_cache: yes
- name: Install Node.js {{ node_version }}
shell: |
curl -fsSL https://deb.nodesource.com/setup_{{ node_version }}.x | bash -
apt-get install -y nodejs
args:
creates: /usr/bin/node
- name: Copy application code
synchronize:
src: ./app/
dest: /opt/myapp/
delete: yes
rsync_opts:
- "--exclude=node_modules"
- name: Install npm dependencies
npm:
path: /opt/myapp
production: yes
- name: Configure nginx reverse proxy
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/myapp
notify: Reload nginx
- name: Enable nginx site
file:
src: /etc/nginx/sites-available/myapp
dest: /etc/nginx/sites-enabled/myapp
state: link
- name: Ensure app service is running
systemd:
name: myapp
state: started
enabled: yes
daemon_reload: yes
handlers:
- name: Reload nginx
service:
name: nginx
state: reloadedRole adalah unit utama reusabilitas di Ansible. Sebuah role merangkum task, variabel, default, template, dan handler untuk kebutuhan tertentu — 'common', 'nginx', 'nodejs', 'docker'. Komunitas Ansible Galaxy meng-hosting ribuan role yang sudah dibuat. Gunakan 'ansible-galaxy install geerlingguy.docker' untuk menambahkan role Docker yang sudah teruji ke proyek Anda dalam hitungan detik.
Ansible Vault mengenkripsi data sensitif — password database, kunci API, private key TLS — langsung di dalam file YAML Anda menggunakan AES-256. File terenkripsi aman untuk di-commit ke version control. Dekripsi saat runtime dengan '--ask-vault-pass' atau dengan mengarahkan Ansible ke file vault password yang disimpan di luar repository.
Anda dapat mengenkripsi seluruh file ('ansible-vault encrypt vars/secrets.yml') atau nilai string individual ('ansible-vault encrypt_string mypassword --name db_password'). Yang terakhir memungkinkan Anda menjaga sebagian besar file variabel tetap dapat dibaca sementara hanya mengenkripsi nilai sensitif. Dalam pipeline CI, simpan vault password sebagai CI secret terenkripsi dan tulis ke file sementara sebelum menjalankan playbook.
Menyimpan file vault password di repository Git Anda mengalahkan seluruh tujuan enkripsi. Simpan di CI secrets store (GitHub Actions Secrets, GitLab CI variables, HashiCorp Vault) dan tulis ke file temp hanya selama eksekusi playbook. Rotasi vault password Anda secara berkala dan enkripsi ulang file menggunakan 'ansible-vault rekey'.
Koleksi 'community.docker' Ansible menyediakan modul untuk mengelola container, image, network, dan volume. Dikombinasikan dengan playbook yang mentemplating docker-compose.yml dan menjalankan 'docker compose up -d', Anda mendapatkan deployment container yang sepenuhnya otomatis tanpa orchestrator khusus. Pendekatan ini populer untuk deployment Docker node tunggal atau multi-node kecil.
Gunakan 'docker_image' untuk menarik image terbaru, kemudian 'docker_container' dengan 'recreate: yes' dan 'pull: yes' untuk restart container dengan image baru. Untuk update tanpa downtime di satu host, implementasikan swapping blue-green sederhana di Ansible: mulai container baru di port alternatif, verifikasi bahwa ia sehat, perbarui upstream Nginx, kemudian hentikan container lama.
Kata kunci 'serial:' dalam sebuah play mengontrol berapa banyak host yang diperbarui Ansible sekaligus. Mengatur 'serial: 1' berarti Ansible sepenuhnya menyelesaikan play di server pertama sebelum pindah ke server kedua — rolling update di level server. Gunakan persentase seperti 'serial: 25%' untuk memperbarui seperempat armada Anda sekaligus. Gabungkan dengan 'max_fail_percentage: 0' untuk membatalkan seluruh play jika ada host yang gagal.
Gunakan direktif 'delegate_to' untuk menjalankan task di host berbeda dari host inventory saat ini. Ini berguna untuk menguras server dari load balancer (jalankan panggilan API di host load balancer), memperbarui record DNS (jalankan di host manajemen DNS), atau mengirim notifikasi Slack dari control node sebelum memulai deployment.
Playbook Ansible harus diuji sebelum mencapai produksi. Molecule adalah framework pengujian standar untuk role Ansible — ia menggunakan Docker untuk memunculkan container sementara, menjalankan playbook, memverifikasi state yang diharapkan, dan menghancurkan. Mengintegrasikan Molecule ke pipeline GitHub Actions memberi Anda pengujian role otomatis pada setiap pull request.
ansible-lint menegakkan praktik terbaik Ansible dan menangkap kesalahan umum: nama modul yang sudah usang, 'name:' yang hilang pada task, 'command:' digunakan di mana modul tersedia, dan izin file yang berisiko. Tambahkan 'ansible-lint' ke pre-commit hook atau pipeline CI Anda untuk menangkap masalah sebelum code review. Ruleset 'profile: production' adalah yang paling ketat dan direkomendasikan untuk playbook produksi.
Konsep inti Ansible yang perlu diketahui: playbook, inventory, role, idempotency, Ansible Vault, and handler.