Basic Ansible Scripting
Ansible: From Zero to Paham Beneran
1. Pengertian
Ansible adalah configuration management & automation tool yang ngizinin lu ngontrol ratusan server sekaligus dari satu mesin — tanpa perlu install agent di server target.
2. Konsep & Teori
- Agentless — komunikasi pure lewat SSH (Linux) atau WinRM (Windows). Nggak ada daemon jalan di server target.
- Idempotent — jalanin playbook 10x = hasilnya sama. Nggak bakal double-install atau rusak state yang udah bener.
- Push-based — Control Node yang push perintah ke managed nodes. Kebalikan dari Puppet/Chef yang pull.
- Ditulis pake YAML — human-readable, nggak perlu belajar bahasa baru.
- Berbasis Python — modulnya semua Python, bisa di-extend.
3. Arsitektur & Komponen Inti
┌─────────────────────────────────────────────────────┐
│ CONTROL NODE │
│ (Laptop/Server lo yang jalanin Ansible) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │Inventory │ │Playbook │ │ansible.cfg │ │
│ │(hosts) │ │(task list│ │(global config) │ │
│ └──────────┘ └──────────┘ └──────────────────┘ │
└───────────────────────┬─────────────────────────────┘
│ SSH / WinRM
┌─────────────┼─────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ web-01 │ │ db-01 │ │ lb-01 │
└────────────┘ └────────────┘ └────────────┘
MANAGED NODES (target server)
Komponen wajib paham:
| Komponen | Fungsi |
|---|---|
| Control Node | Mesin yang lu pake buat jalanin Ansible |
| Managed Node | Server target yang dikontrol |
| Inventory | Daftar server target (file hosts) |
| Playbook | Script YAML berisi urutan task |
| Task | Satu unit pekerjaan (install nginx, copy file, dll) |
| Module | "Tool" bawaan Ansible (apt, yum, copy, service, dll) |
| Role | Kumpulan playbook + file yang distrukturkan rapi |
| Handler | Task yang cuma jalan kalau dipanggil (triggered) |
| Vault | Enkripsi secret/password di dalam playbook |
| Facts | Info otomatis tentang server target (OS, IP, RAM, dll) |
4. Cara Kerja
Step 1: Lu tulis Inventory → siapa server targetnya
↓
Step 2: Lu tulis Playbook → mau ngapain di server itu
↓
Step 3: ansible-playbook dijalanin
↓
Step 4: Ansible SSH ke tiap node
↓
Step 5: Ansible push Python module (temporary) ke /tmp di target
↓
Step 6: Module dieksekusi di target
↓
Step 7: Output balik ke Control Node
↓
Step 8: Ansible hapus temporary file → BERSIH
↓
Step 9: Lu dapat laporan: OK / CHANGED / FAILED
5. Tujuan
- Provisioning massal — setup 100 server baru sekaligus dalam menit
- Config management — pastiin semua server punya config yang sama
- Deployment aplikasi — deploy code ke staging/production otomatis
- Compliance — enforce security policy di semua node
- Orchestration — koordinasi urutan task antar banyak server
6. Analogi
Bayangin lu mandor proyek konstruksi.
Lu punya blueprint (Playbook), daftar tukang (Inventory), dan toolbox (Modules).
Lu nggak perlu ada di tiap lokasi — lu kirim instruksi lewat radio (SSH), tukang-tukang lu kerjain sesuai blueprint, lalu laporan balik ke lu. Kalau ada yang udah beres, lu nggak suruh ngerjain ulang (idempotent).
7. Pros & Cons
| Kelebihan | Kekurangan |
|---|---|
| Agentless, setup cepet | Lambat kalau node ribuan (banding Puppet) |
| YAML mudah dibaca siapapun | YAML indent-sensitive, error gampang |
| Idempotent by design | Debugging playbook kompleks bisa pusing |
| Library modul sangat luas | Nggak ada native GUI (butuh AWX/Tower) |
| Komunitas besar, dokumentasi oke | Windows support lebih terbatas |
8. Core Config & Praktik Langsung
8.1 — Instalasi di Control Node
# Update repo dulu
$ sudo apt update
# Install Ansible (Ubuntu/Debian)
$ sudo apt install ansible -y
# Cek versi
$ ansible --version
# Cek path config yang aktif
$ ansible --version | grep "config file"
8.2 — Struktur Project yang Rapi
my-ansible-project/
├── ansible.cfg # Config global project ini
├── inventory/
│ ├── hosts # Daftar server
│ └── group_vars/
│ ├── all.yml # Variabel berlaku ke semua group
│ └── webservers.yml
├── playbooks/
│ ├── site.yml # Master playbook
│ ├── webservers.yml
│ └── dbservers.yml
└── roles/
└── nginx/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
└── vars/
└── main.yml
8.3 — ansible.cfg
# File: ansible.cfg (taruh di root project)
[defaults]
# Lokasi inventory default
inventory = ./inventory/hosts
# User SSH yang dipake ke managed node
remote_user = ubuntu
# Private key SSH
private_key_file = ~/.ssh/id_rsa
# Matiin host key checking (hati-hati di prod!)
host_key_checking = False
# Jumlah host yang diproses paralel
forks = 10
# Log semua aktivitas ansible
log_path = ./ansible.log
[privilege_escalation]
# Aktifin sudo otomatis
become = True
become_method = sudo
become_user = root
8.4 — Inventory (INI Format)
# File: inventory/hosts
# ── Group: webservers ──
[webservers]
web-01 ansible_host=192.168.1.10
web-02 ansible_host=192.168.1.11
web-03 ansible_host=192.168.1.12
# ── Group: dbservers ──
[dbservers]
db-01 ansible_host=192.168.1.20 ansible_port=2222 # Port SSH non-standard
db-02 ansible_host=192.168.1.21
# ── Group of Groups ──
[production:children] # Group "production" berisi webservers + dbservers
webservers
dbservers
# ── Variabel per-group ──
[webservers:vars]
http_port=80
ansible_user=ubuntu
8.5 — Playbook Pertama (Basic)
# File: playbooks/webservers.yml
---
- name: Setup Web Server # Nama play (deskriptif)
hosts: webservers # Target group dari inventory
become: true # Jalanin sebagai sudo
vars: # Variabel lokal playbook ini
app_port: 80
pkg_list:
- nginx
- curl
- git
tasks:
- name: Update apt cache # Task 1: update repo
apt:
update_cache: yes
cache_valid_time: 3600 # Cache valid 1 jam, skip kalau masih fresh
- name: Install required packages # Task 2: install paket
apt:
name: "{{ pkg_list }}" # Pakai variabel list di atas
state: present # Pastiin terinstall (idempotent)
- name: Start dan enable nginx # Task 3: pastiin nginx running
service:
name: nginx
state: started
enabled: yes # Auto-start saat boot
- name: Copy konfigurasi nginx # Task 4: push config file
template:
src: ../roles/nginx/templates/nginx.conf.j2 # Template Jinja2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Restart nginx # Trigger handler kalau ada perubahan
handlers: # Hanya jalan kalau di-notify
- name: Restart nginx
service:
name: nginx
state: restarted
8.6 — Variabel & Facts
# Cara akses Facts (info otomatis dari target server)
- name: Debug info server
hosts: all
tasks:
- name: Tampilkan semua facts # Lihat semua facts yang tersedia
debug:
var: ansible_facts
- name: Tampilkan IP address # Akses fact spesifik
debug:
msg: "IP server ini: {{ ansible_default_ipv4.address }}"
- name: Tampilkan versi OS
debug:
msg: "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: Kondisional berdasarkan OS # Task hanya jalan di Ubuntu
apt:
name: nginx
state: present
when: ansible_distribution == "Ubuntu"
8.7 — Loop & Kondisional
tasks:
# ── LOOP: buat banyak user sekaligus ──
- name: Buat user developer
user:
name: "{{ item }}" # item = tiap elemen di loop
shell: /bin/bash
create_home: yes
loop: # Iterasi list ini
- alice
- bob
- charlie
# ── KONDISIONAL: hanya di server production ──
- name: Disable root SSH login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
when: "'production' in group_names" # Cek apakah host ada di group production
# ── REGISTER: simpan output task ke variabel ──
- name: Cek apakah file config ada
stat:
path: /etc/app/config.yml
register: config_file # Simpan hasil ke variabel config_file
- name: Buat config kalau belum ada
copy:
content: "key: value\n"
dest: /etc/app/config.yml
when: not config_file.stat.exists # Hanya jalan kalau file belum ada
8.8 — Ansible Vault (Enkripsi Secret)
# Buat file encrypted baru
$ ansible-vault create secrets.yml
# Encrypt file yang udah ada
$ ansible-vault encrypt group_vars/all/vault.yml
# Lihat isi file terenkripsi
$ ansible-vault view secrets.yml
# Edit file terenkripsi
$ ansible-vault edit secrets.yml
# Decrypt permanen
$ ansible-vault decrypt secrets.yml
# Jalanin playbook yang pakai vault
$ ansible-playbook site.yml --ask-vault-pass
# Atau pakai password file (buat CI/CD)
$ ansible-playbook site.yml --vault-password-file ~/.vault_pass
# secrets.yml (setelah di-encrypt, isinya jadi gibberish)
# Sebelum encrypt, isinya:
db_password: "S3cr3tP@ssw0rd"
api_key: "sk-prod-xxxxxxxxxxxx"
# Pake di playbook:
- name: Set DB password
lineinfile:
path: /etc/app/.env
line: "DB_PASS={{ db_password }}" # Referensi variabel dari vault
8.9 — Command Harian & Troubleshooting
# ── AD-HOC COMMAND (tanpa playbook) ──
# Ping semua host (cek koneksi)
$ ansible all -m ping
# Ping group tertentu
$ ansible webservers -m ping
# Jalanin command shell di semua node
$ ansible all -m shell -a "uptime"
# Cek disk di dbservers
$ ansible dbservers -m shell -a "df -h"
# Copy file ke semua web server
$ ansible webservers -m copy -a "src=/local/file dest=/remote/path"
# Install paket di satu host spesifik
$ ansible web-01 -m apt -a "name=htop state=present" --become
# ── JALANIN PLAYBOOK ──
# Dry-run (check mode, nggak ada yang berubah)
$ ansible-playbook site.yml --check
# Lihat diff perubahan file sebelum apply
$ ansible-playbook site.yml --check --diff
# Jalanin hanya task dengan tag tertentu
$ ansible-playbook site.yml --tags "nginx,ssl"
# Skip task tertentu
$ ansible-playbook site.yml --skip-tags "update"
# Limit ke host/group tertentu
$ ansible-playbook site.yml --limit webservers
$ ansible-playbook site.yml --limit web-01
# Verbose mode (debug)
$ ansible-playbook site.yml -v # Verbose level 1
$ ansible-playbook site.yml -vvv # Verbose level 3 (paling detail)
# Mulai dari task tertentu (kalau gagal di tengah)
$ ansible-playbook site.yml --start-at-task="Copy konfigurasi nginx"
# ── TROUBLESHOOTING ──
# Lihat semua facts server (debug awal)
$ ansible web-01 -m setup
# Filter facts tertentu
$ ansible web-01 -m setup -a "filter=ansible_distribution*"
# Cek inventory sudah terbaca benar
$ ansible-inventory --list
$ ansible-inventory --graph # Tampilkan tree
# Syntax check playbook (sebelum jalanin)
$ ansible-playbook site.yml --syntax-check
# Test koneksi SSH manual ke node
$ ssh -i ~/.ssh/id_rsa ubuntu@192.168.1.10
9. Best Practice
- Selalu
--checkdulu sebelum apply ke production. Nggak adaundodi Ansible. - Pakai Roles, bukan satu playbook raksasa. Roles bikin kode reusable & maintainable.
- Simpan secrets di Vault, bukan hardcode di playbook. Apalagi kalau repo lu public.
- Idempotent check — selalu tanya: "Kalau task ini dijalanin 2x, apakah aman?" Kalau nggak aman, pake
creates:atauwhen:. - Naming convention — nama task harus deskriptif kayak kalimat. Bukan
task1tapiInstall nginx web server. - Pakai
group_vars&host_varsbuat pisahin variabel dari playbook. - Version control — semua Ansible project wajib masuk Git. Infrastructure as Code.
- Test dengan Molecule — kalau udah advance, pake Molecule buat unit test roles.
- Jangan pake
shell:kalau ada modulnya —shell: apt install nginxitu salah. Pake modulapt. Shell nggak idempotent. - Forks — default 5, naikkan ke 20-50 kalau node banyak dan jaringan oke.
10. Glosarium
| Istilah | Penjelasan |
|---|---|
| Agentless | Ansible nggak perlu software tambahan di server target, cukup SSH |
| Idempotent | Dijalanin berkali-kali hasilnya tetap sama, nggak nambah-nambahin |
| Inventory | File daftar server target yang dikelola Ansible |
| Playbook | File YAML berisi daftar tasks yang mau dijalanin ke host |
| Task | Satu instruksi tunggal dalam playbook (jalanin satu modul) |
| Module | Kode Python bawaan Ansible untuk satu fungsi spesifik (apt, copy, service) |
| Role | Struktur direktori terstandarisasi untuk kumpulan playbook yang reusable |
| Handler | Task khusus yang cuma jalan kalau dipanggil via notify |
| Facts | Variabel otomatis berisi info sistem target yang dikumpulkan saat playbook mulai |
| Vault | Fitur enkripsi Ansible untuk menyimpan data sensitif |
| Jinja2 | Template engine yang dipake Ansible untuk variabel dinamis di file config |
| YAML | Format file yang dipake Ansible untuk nulis playbook |
| Ad-hoc | Command Ansible satu baris tanpa playbook, buat task cepat |
| become | Mekanisme privilege escalation (sudo) di Ansible |
| Register | Simpan output task ke variabel buat dipakai task berikutnya |
| notify | Trigger handler setelah task selesai (biasanya buat restart service) |
Comments
Post a Comment