Dari empat tool configuration management di Chapter Configuration Management , satu nama menjadi pilihan bawaan administrator Linux: Ansible, dengan janji yang sederhana tapi memikat — tanpa agent, tanpa daemon, cukup SSH dan Python yang sudah ada di hampir semua server. Seluruh kecerdasan berada di mesin kendali (control node): di situlah inventory, playbook, dan modul digabung menjadi perintah yang didorong ke banyak server sekaligus. Chapter ini membedah ketiga poros itu satu per satu sampai ke format berkasnya. Paket ansible tidak terpasang di container latihan, jadi kita menulis berkas inventory dan playbook sungguhan, lalu mensimulasikan mesin eksekusinya dengan skrip bash yang deterministik.

Agentless: Cukup SSH dan Python #

Ansible bekerja lewat jalur yang sudah kita kuasai: SSH dari Chapter Remote Shell . Mesin kendali membaca inventory, membuka koneksi SSH ke setiap host, lalu mengirimkan modul — potongan kode Python kecil — untuk dijalankan di sana. Hasilnya dikembalikan sebagai JSON, dirangkum menjadi laporan, dan koneksi ditutup; tidak ada yang tertinggal di server. Bandingkan dengan Puppet atau Chef yang memasang daemon permanen di setiap mesin: dengan Ansible, server yang sedang tidak dikelola tidak membuka satu port ekstra pun.

Konsekuensi arsitektur ini: autentikasi SSH adalah kunci kerajaan. Kunci publik yang dikelola lewat Chapter SSH Keys dan Agent harus terpasang di setiap host, dan user yang dipakai harus punya hak sudo untuk task yang menuntutnya — persis pola sudo yang kita kelola di awal Course.

Inventory: Peta Server yang Dikelola #

Sebelum bisa mengerjakan apa pun, Ansible perlu tahu server mana saja yang dikelolanya. Jawabannya adalah inventory — daftar host berformat INI yang dikelompokkan sesuai perannya:

bash
cat > inventory.ini << 'EOF'
[web]
web-jakarta ansible_host=203.0.113.10
web-surabaya ansible_host=203.0.113.11

[database]
db-jakarta ansible_host=203.0.113.20

[produksi:children]
web
database
EOF
cat inventory.ini

Output yang Dihasilkan:

text
[web]
web-jakarta ansible_host=203.0.113.10
web-surabaya ansible_host=203.0.113.11

[database]
db-jakarta ansible_host=203.0.113.20

[produksi:children]
web
database

Mari kita bedah baris demi baris:

  1. [web]: membuka grup bernama web — semua host di bawahnya sampai baris kosong menjadi anggotanya; playbook menarget hosts: web akan menyentuh keduanya.
  2. web-jakarta ansible_host=203.0.113.10: nama host beserta variabel ansible_host yang memberi tahu alamat aslinya — nama boleh human-friendly, alamat tetap presisi.
  3. [database]: grup kedua; server database dipisahkan karena playbooknya berbeda.
  4. [produksi:children]: grup dari grup — produksi berisi seluruh anggota web dan database, sehingga satu playbook bisa menarget keduanya sekaligus bila perlu.

Playbook: Resep dalam YAML #

Playbook mendeskripsikan keadaan akhir yang kita inginkan dalam YAML — format yang sama dengan user-data cloud-init di Chapter cloud-init . Berikut playbook yang memasang nginx, menyebarkan konfigurasi, lalu memastikan service hidup:

bash
cat > playbook-web.yml << 'EOF'
---
- name: Pasang web server nginx
  hosts: web
  become: true
  tasks:
    - name: pastikan nginx terpasang
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: salin konfigurasi situs
      ansible.builtin.copy:
        src: situs.conf
        dest: /etc/nginx/sites-available/default
        mode: "0644"
      notify: muat ulang nginx

    - name: pastikan nginx berjalan
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: muat ulang nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
EOF
cat playbook-web.yml

Output yang Dihasilkan:

text
---
- name: Pasang web server nginx
  hosts: web
  become: true
  tasks:
    - name: pastikan nginx terpasang
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: salin konfigurasi situs
      ansible.builtin.copy:
        src: situs.conf
        dest: /etc/nginx/sites-available/default
        mode: "0644"
      notify: muat ulang nginx

    - name: pastikan nginx berjalan
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: muat ulang nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded

Struktur inilah yang membedakan playbook dari sekadar daftar perintah. Mari kita bedah bagian demi bagiannya:

  1. - name: / hosts: web / become: true: satu play — satuan eksekusi yang menarget grup web dari inventory, dengan become: true menaikkan hak ke sudo seperti flag -b di command line.
  2. tasks: dan tiap - name:: daftar langkah yang berurutan dari atas ke bawah; name wajib dan dibaca manusia — nantinya muncul di layar saat eksekusi.
  3. ansible.builtin.apt: ...: modul pengelola paket Debian dengan argumen name dan state: present — “harus terpasang”, bukan “pasang sekarang”; update_cache: true setara apt update dari Chapter Updating dan Upgrading System .
  4. ansible.builtin.copy: ...: menyalin situs.conf ke server dengan mode "0644" — pola permission dari Chapter File Permissions .
  5. notify: muat ulang nginx dan handlers:: task copy hanya “melapor berubah” ke handler bernama muat ulang nginx; handler berjalan di akhir play dan hanya bila ada yang berubah — service tidak direstart ketika isinya sudah sama.

Module yang Paling Sering Dipakai #

Semua pekerjaan playbook dilakukan modul — ratusan jumlahnya, tetapi segelintir menutup 90% kebutuhan harian:

ModuleFungsiArgumen kunci
ansible.builtin.aptpaket di Debian/Ubuntuname, state
ansible.builtin.copymenyalin berkas apa adanyasrc, dest, mode
ansible.builtin.templatemerender berkas dengan variabelsrc, dest
ansible.builtin.servicemengelola service systemdname, state, enabled
ansible.builtin.usermembuat dan mengubah username, groups, shell
ansible.builtin.commandmenjalankan perintah apa adanyacmd

Dua baris terakhir perlu perhatian ekstra. Modul command menjalankan perintah tanpa pemeriksaan keadaan, jadi selalu melaporkan changed — idempotensinya menjadi tanggung jawab kita. Aturan praktisnya: cari modul khusus dulu (apt, user, service), dan jatuh ke command hanya bila tidak ada yang lebih spesifik.

Simulasi Eksekusi: changed di Lari Pertama, ok di Lari Kedua #

Mesin eksekusi Ansible sederhana secara konsep: untuk tiap task, bacalah keadaan server, bandingkan dengan yang diminta, lalu laporkan ok atau changed — pola idempotensi dari chapter sebelumnya. Simulasi berikut memodelkan tiga task playbook di atas dengan daftar task dan direktori state sebagai keadaan server:

bash
cat > daftar-task.txt << 'EOF'
pastikan nginx terpasang|ansible.builtin.apt
salin konfigurasi situs|ansible.builtin.copy
pastikan nginx berjalan|ansible.builtin.service
EOF
mkdir -p state
jalankan() {
  while IFS='|' read -r nama modul; do
    if [ -e "state/$modul" ]; then
      printf 'ok       [%s]\n' "$nama"
    else
      printf 'changed  [%s]\n' "$nama"
      : > "state/$modul"
    fi
  done < daftar-task.txt
}
echo "== lari pertama =="
jalankan
echo "== lari kedua =="
jalankan

Output yang Dihasilkan:

text
== lari pertama ==
changed  [pastikan nginx terpasang]
changed  [salin konfigurasi situs]
changed  [pastikan nginx berjalan]
== lari kedua ==
ok       [pastikan nginx terpasang]
ok       [salin konfigurasi situs]
ok       [pastikan nginx berjalan]

Mari kita bedah mekanismenya:

  1. daftar-task.txt: daftar task playbook dalam format nama|modul — persis tiga task yang kita tulis di playbook-web.yml.
  2. Direktori state/: model keadaan server — keberadaan berkas penanda menggantikan “nginx sudah terpasang” yang sesungguhnya dibaca dari sistem.
  3. if [ -e "state/$modul" ]: keputusan ok versus changed; di Ansible sungguhan pemeriksaan ini dilakukan modul terhadap keadaan nyata, bukan penanda.
  4. Dua pemanggilan jalankan: lari pertama mengubah semuanya, lari kedua tidak mengubah apa pun — playbook yang sehat selalu begini.

Di layar, eksekusi nyata ditampilkan per task per host. Berikut contoh tampilan ansible-playbook untuk playbook kita di dua server:

text
PLAY [Pasang web server nginx] *************************************

TASK [pastikan nginx terpasang] ************************************
changed: [web-jakarta]
changed: [web-surabaya]

TASK [salin konfigurasi situs] *************************************
changed: [web-jakarta]
ok: [web-surabaya]

PLAY RECAP *********************************************************
web-jakarta  : ok=3    changed=2    unreachable=0    failed=0
web-surabaya : ok=3    changed=1    unreachable=0    failed=0

Baris PLAY RECAP di akhir adalah ringkasan yang dibaca cepat: changed besar berarti banyak yang bergeser, failed bukan nol berarti ada yang harus diperbaiki sebelum lari berikutnya.

Ad-hoc, Dry Run, dan Kebiasaan Aman #

Untuk pekerjaan sekali jalan tanpa playbook, ada perintah ad-hoc: satu modul, satu target. Contohnya memasang htop di seluruh grup web:

bash
ansible web -i inventory.ini -m ansible.builtin.apt -a "name=htop state=present" -b

Struktur argumennya: target web, inventory -i, modul -m, argumen modul -a, dan -b untuk sudo. Untuk playbook, padanan lengkapnya adalah ansible-playbook -i inventory.ini playbook-web.yml — tambahkan --check dan Ansible masuk mode dry run: semua task dijalankan tanpa mengubah apa pun, hanya melaporkan apa yang akan berubah.

Roles dan Vault #

Playbook yang tumbuh panjang sebaiknya dipecah menjadi role — paket task, handler, dan template yang bisa dipakai ulang. Anatominya berkonvensi ketat:

text
roles/
└── nginx/
    ├── tasks/main.yml      # langkah utama role
    ├── handlers/main.yml   # handler seperti "muat ulang nginx"
    ├── templates/          # berkas dengan variabel jinja2
    └── defaults/main.yml   # nilai bawaan yang bisa ditimpa

Satu playbook tinggal memanggil roles: - nginx, dan seluruh isi folder itu terangkai — cara yang sama seperti package di dunia pemrograman: sekali ditulis, dipakai di mana saja. Untuk data rahasia seperti kunci database, Ansible menyediakan ansible-vault: perintah ini mengenkripsi berkas variabel sehingga di repository Git hanya tampil sebagai teks tersandi, dan playbook tetap bisa membacanya dengan --ask-vault-pass saat eksekusi. Prinsipnya sama dengan Chapter Secrets dan Credential Management : rahasia tidak pernah tidur dalam plaintext.

Dengan Ansible, server kini punya resep yang bisa dijalankan ulang kapan pun — dan definisi yang sama bisa kita perlakukan seperti kode aplikasi. Chapter berikutnya, Deployment Automation , mengangkat pola itu ke ranah yang paling sering berubah: meluncurkan versi aplikasi baru ke server-server ini dengan aman, terukur, dan bisa dibatalkan.

Referensi lanjut: Arch Wiki: Ansible untuk instalasi dan pola penggunaan di berbagai distro, serta OpenSSH untuk protokol transport yang menjadi fondasi seluruh model agentless ini.