Pengenalan Ansible

Pengenalan Ansible

Bitnesia Aug 27, 2026 2 EN

Bab 35 menutup dengan janji yang sengaja digantung: script backup-config.sh, cleanup-temp.sh, dan health-check.sh yang sudah kita tulis dan jadwalkan lewat cron maupun systemd timer semuanya hanya berlaku untuk satu server. Begitu jaringan bertambah dari satu server jadi tiga seperti skema 192.168.1.0/24 yang sudah kita bangun sejak Bab 9 (DNS di 192.168.1.10) dan Bab 12 (Nginx di 192.168.1.20), menyalin script yang sama satu per satu ke setiap server lewat scp lalu menjalankannya manual lewat SSH mulai terasa tidak masuk akal. Sepuluh server berarti sepuluh kali proses manual yang identik, dan human error tinggal menunggu waktu saat salah satu server terlewat atau mendapat versi script yang sedikit berbeda dari yang lain. Bab ini membuka Ansible sebagai jawaban langsung atas masalah tersebut, sekaligus konsep Infrastructure as Code yang jadi payung besar di baliknya.

Skenario ini sangat familier bagi Sysadmin yang mengelola lebih dari satu server. Developer meminta paket Node.js versi tertentu terpasang di lima server aplikasi sekaligus. Tim keamanan meminta konfigurasi firewall yang sama diterapkan ke seluruh server produksi setelah insiden di satu server ketahuan. Tanpa alat bantu, permintaan semacam ini berubah jadi checklist manual yang dikerjakan berulang, rawan lupa satu langkah, dan nyaris mustahil diaudit siapa mengubah apa. Ansible menjawabnya dengan pendekatan yang berbeda dari script bash biasa, yaitu mendeskripsikan kondisi akhir yang diinginkan lewat file konfigurasi terstruktur, lalu membiarkan Ansible sendiri yang menghitung langkah apa saja yang perlu dijalankan agar kondisi itu tercapai di setiap server tujuan.

Kita akan mulai bab ini dari konsep Infrastructure as Code dan cara kerja Ansible secara singkat, dilanjutkan instalasi Ansible di control node, lalu inventory dan anatomi playbook dasar, dan ditutup dengan menjalankan playbook pertama yang benar-benar memasang Nginx di server target. Bab 37 nanti melengkapi sisi provisioning awal lewat cloud-init, sementara bab ini fokus pada konfigurasi server yang sudah berjalan.

36.1 Konsep Infrastructure as Code

Infrastructure as Code (IaC) adalah praktik mengelola dan menyediakan infrastruktur, mulai dari konfigurasi server, jaringan, sampai provisioning VM, lewat file definisi yang bisa dibaca mesin, bukan lewat langkah manual di terminal atau klik di dashboard. File definisi ini sifatnya deklaratif: kita menuliskan kondisi akhir yang diinginkan (misalnya "paket nginx harus terpasang dan service-nya harus berjalan"), bukan urutan perintah imperatif langkah demi langkah seperti pada script bash di Bab 35.

36.1.1 Masalah Configuration Drift yang Diselesaikan IaC

Configuration drift adalah istilah untuk kondisi ketika konfigurasi aktual di sebuah server pelan-pelan menyimpang dari konfigurasi yang seharusnya, biasanya karena perubahan manual yang tidak tercatat di mana pun. Satu server mendapat patch keamanan lebih dulu karena Sysadmin sempat login langsung untuk memperbaiki masalah mendesak, sementara empat server lain di belakang load balancer yang sama tetap berjalan dengan versi lama karena perubahan itu tidak pernah direplikasi. Ketika insiden terjadi, drift semacam ini membuat troubleshooting jadi lebih sulit karena server yang "identik" ternyata punya riwayat konfigurasi berbeda-beda.

IaC menutup celah ini dengan menjadikan file definisi sebagai satu-satunya sumber kebenaran. Perubahan konfigurasi dilakukan dengan mengubah file tersebut, lalu menjalankannya ulang ke seluruh server target, bukan login manual ke satu server tertentu. File ini juga bisa disimpan di Git seperti kode aplikasi pada umumnya, sehingga setiap perubahan konfigurasi server punya riwayat, bisa di-review lewat pull request, dan bisa di-rollback persis seperti kode. Konsep version control untuk infrastruktur inilah yang membedakan IaC dari sekadar "script otomasi" biasa.

36.1.2 Cara Kerja Ansible: Agentless, Push-Based, dan Idempotent

Ansible bukan satu-satunya tool IaC, tetapi karakteristiknya membuatnya jadi pilihan yang cocok sebagai titik masuk. Tiga sifat berikut yang paling membedakannya dari tool sejenis seperti Puppet dan Chef.

  • Ansible bersifat agentless, artinya tidak perlu ada software daemon khusus terpasang dan berjalan terus-menerus di server yang dikelola. Ansible cukup terhubung lewat SSH, protokol yang sudah kita konfigurasi sejak Bab 3, sehingga tidak ada proses tambahan yang perlu dipelihara atau jadi celah keamanan baru di setiap server target.
  • Ansible bekerja dengan model push-based: satu mesin yang disebut control node mendorong konfigurasi ke sejumlah managed node (server target) begitu perintah dijalankan. Model ini berbeda dari tool pull-based seperti Puppet, yang mengandalkan agent di tiap server target untuk secara berkala menarik konfigurasi terbaru sendiri dari server pusat.
  • Setiap operasi Ansible dirancang idempotent, artinya menjalankan playbook yang sama berkali-kali ke server yang sama akan menghasilkan kondisi akhir yang sama persis, tanpa efek samping tambahan pada eksekusi kedua dan seterusnya. Jika paket nginx sudah terpasang, menjalankan ulang playbook instalasi nginx tidak akan memasangnya lagi atau menimbulkan error, cukup melaporkan bahwa kondisi yang diminta sudah tercapai. Sifat inilah yang membuat playbook aman dijalankan berulang sebagai bagian dari proses deployment rutin, berbeda dari script bash naif yang bisa gagal atau berperilaku aneh kalau dijalankan dua kali ke server yang sama.

Perlu dibedakan juga antara tool configuration management seperti Ansible, Puppet, dan Chef dengan tool provisioning seperti Terraform yang disinggung lagi di Bab 44 sebagai area pendalaman lanjutan. Configuration management berurusan dengan "bagaimana mengonfigurasi server yang sudah ada", sedangkan provisioning berurusan dengan "bagaimana membuat server/instance itu sendiri" di cloud maupun on-premise. Cloud-init yang dibahas di Bab 37 mengisi celah di antara keduanya, yaitu provisioning awal saat VM pertama kali menyala, sebelum Ansible sempat masuk untuk konfigurasi lanjutan.

AspekAnsiblePuppet/ChefTerraform
ArsitekturAgentless, push-based lewat SSHButuh agent di tiap node, umumnya pull-basedAgentless, memanggil API provider cloud
Fokus utamaConfiguration managementConfiguration managementProvisioning infrastruktur (VM, network, storage)
Bahasa konfigurasiYAML (playbook)DSL khusus (Puppet) / Ruby (Chef)HCL (HashiCorp Configuration Language)
Kurva belajar awalRelatif landaiLebih curam, perlu belajar DSL/RubyLandai untuk provisioning, konsep state terpisah

Ringkasnya, Ansible dipilih di bab ini karena arsitekturnya yang agentless membuat instalasi awal jauh lebih sederhana dibanding Puppet atau Chef, sementara fokusnya di configuration management melengkapi shell script di Bab 35, bukan menggantikannya sepenuhnya.

36.2 Instalasi Ansible di Control Node

Control node adalah mesin tempat Ansible terpasang dan dari mana seluruh perintah dijalankan, sedangkan managed node adalah server target yang dikonfigurasi. Ansible mensyaratkan control node berjalan di sistem mirip Unix (Linux, macOS, atau BSD) dengan Python terpasang; Windows tidak didukung sebagai control node, meski tetap bisa jadi managed node lewat protokol WinRM (di luar cakupan bab ini). Managed node juga umumnya perlu Python 3 terpasang, karena sebagian besar module Ansible dieksekusi sebagai script Python di sisi managed node; Ubuntu Server pada dasarnya sudah menyertakan Python 3, kecuali pada image cloud minimal tertentu yang sengaja dipangkas.

36.2.1 Instalasi Ansible via APT

Ubuntu menyediakan package ansible di repository universe sejak beberapa rilis LTS terakhir. Package ini adalah metapackage yang membundel ansible-core (mesin inti Ansible) bersama kumpulan collection resmi yang sudah dikurasi, cukup untuk kebutuhan belajar dan penggunaan sehari-hari tanpa instalasi tambahan.

Langkah Praktik

  1. Pastikan repository universe aktif, lalu perbarui daftar paket dan pasang Ansible di control node.
    sudo apt update
    sudo apt install ansible
  2. Periksa versi Ansible yang terpasang.
    ansible --version

Verifikasi dan Troubleshooting

  • Baris pertama output ansible --version berformat ansible [core X.Y.Z], diikuti baris config file, python version, dan sejenisnya. Angka X.Y.Z mengikuti versi yang sedang dikemas di repository Ubuntu Server 26.04 LTS saat paket ini dipasang, jadi jangan heran kalau berbeda dari contoh versi mana pun yang pernah dilihat di internet; selalu jadikan output di server ini sebagai acuan, bukan angka di tutorial manapun termasuk bab ini.
  • Jika butuh versi Ansible paling baru dari upstream yang belum sempat masuk ke repository Ubuntu, dokumentasi resmi Ansible merekomendasikan instalasi lewat pipx alih-alih PPA pihak ketiga yang dukungannya sudah berkurang untuk rilis-rilis terbaru. Untuk kebutuhan belajar di bab ini, package ansible dari APT sudah lebih dari cukup.
  • Error Unable to locate package ansible biasanya berarti repository universe belum aktif. Aktifkan lewat sudo add-apt-repository universe lalu ulangi apt update.

36.2.2 Menyiapkan Akses SSH ke Managed Node

Sebab Ansible terhubung ke managed node lewat SSH, autentikasi berbasis key yang sudah kita konfigurasi di Bagian 3.2 adalah prasyarat mutlak sebelum lanjut ke bagian berikutnya. Tanpa itu, Ansible akan berhenti di setiap host menunggu input password yang tidak pernah bisa diketik karena dijalankan otomatis. Bagian ini mengasumsikan sudah ada satu server tambahan yang disiapkan khusus untuk latihan bab ini, kita beri nama app01 dengan IP 192.168.1.40 mengikuti skema jaringan 192.168.1.0/24 yang sudah dipakai sejak Bab 9; sesuaikan IP dan hostname ini dengan server yang benar-benar tersedia.

Langkah Praktik

  1. Dari control node, salin public key yang sudah dibuat di Bagian 3.2.1 ke app01.
    ssh-copy-id [email protected]
  2. Login manual satu kali lewat SSH biasa untuk mengonfirmasi koneksi berjalan sekaligus menerima host key app01 ke known_hosts milik control node.
    ssh [email protected] exit
  3. Pastikan user tersebut punya akses sudo di app01, karena instalasi paket pada Bagian 36.4 memerlukan privilege escalation lewat directive become yang akan kita pakai di playbook.
    ssh [email protected] sudo whoami

Verifikasi dan Troubleshooting

  • Perintah sudo whoami pada langkah ketiga semestinya mencetak root tanpa diminta password jika sudoers app01 sudah dikonfigurasi NOPASSWD, atau meminta password sekali jika belum. Kedua kondisi ini valid; jika diminta password, catat karena nanti perlu ditambahkan flag --ask-become-pass saat menjalankan playbook di Bagian 36.4.2.
  • Langkah login manual pada urutan kedua bukan formalitas. Tanpa host key app01 lebih dulu tersimpan di known_hosts, percobaan koneksi pertama Ansible bisa menggantung menunggu konfirmasi interaktif Are you sure you want to continue connecting (yes/no)? yang tidak pernah muncul di konteks non-interaktif, sebuah jebakan yang sering luput disadari Sysadmin yang baru pertama kali memakai Ansible.
  • Error Permission denied (publickey) di langkah mana pun berarti kembali dulu ke troubleshooting Bagian 3.2, karena masalahnya ada di lapisan SSH, bukan di Ansible.

36.3 Inventory dan Playbook Dasar

Dua file jadi fondasi setiap pekerjaan Ansible: inventory yang mendaftar server mana saja yang dikelola, dan playbook yang mendefinisikan apa yang harus dilakukan terhadap server-server itu. Kita akan membuat direktori kerja khusus, lalu menyusun keduanya secara bertahap.

36.3.1 Membuat Inventory Statis

Inventory adalah daftar host dan group host yang jadi target Ansible, ditulis dalam format INI atau YAML. Bagian ini memakai format INI karena lebih ringkas untuk inventory kecil.

Langkah Praktik

  1. Buat direktori kerja untuk seluruh file Ansible di bab ini.
    mkdir -p ~/ansible-project
    cd ~/ansible-project
  2. Buat file inventory.
    nano inventory.ini
  3. Isi dengan definisi group webservers berisi app01.
    [webservers]
    app01 ansible_host=192.168.1.40 ansible_user=sysadmin

Verifikasi dan Troubleshooting

  • Tampilkan daftar host yang terbaca dari inventory untuk memastikan formatnya valid.
    ansible-inventory -i inventory.ini --list
    Output berupa JSON, dan bagian yang perlu diperiksa adalah blok "webservers": {"hosts": ["app01"]} yang menandakan Ansible berhasil membaca group dan host sesuai isi inventory.ini.
  • Untuk inventory yang lebih besar, host bisa dikelompokkan ke banyak group sekaligus (misalnya [webservers], [dbservers]), dan group-of-groups lewat sintaks [production:children]. Bab ini sengaja memakai satu group saja agar fokus ke alur dasarnya dulu.
  • Ansible sebenarnya juga mendukung inventory dinamis yang mengambil daftar host langsung dari API cloud provider atau sistem inventaris internal, alih-alih file statis seperti inventory.ini. Topik ini berguna begitu jumlah server sudah puluhan dan berubah-ubah, tetapi berada di luar cakupan bab pengenalan ini.

36.3.2 Menguji Konektivitas dengan Ad-Hoc Command

Ad-hoc command adalah perintah Ansible satu baris yang langsung dieksekusi tanpa perlu menulis playbook, cocok untuk pengecekan cepat seperti menguji konektivitas sebelum menulis playbook sungguhan.

Langkah Praktik

  1. Jalankan module ping bawaan Ansible ke seluruh host di group webservers.
    ansible webservers -i inventory.ini -m ping

Verifikasi dan Troubleshooting

  • Output yang berhasil menampilkan app01 | SUCCESS => diikuti blok JSON berisi "ping": "pong". Module ping di sini murni menguji jalur SSH dan interpreter Python di managed node, bukan ICMP ping seperti perintah ping biasa di shell.
  • Status UNREACHABLE umumnya berarti masalah koneksi SSH, seperti IP atau port salah, atau host key belum diterima seperti dibahas di Bagian 36.2.2.
  • Status FAILED dengan pesan menyinggung python berarti interpreter Python3 tidak ditemukan di path standar pada managed node. Tambahkan variable ansible_python_interpreter=/usr/bin/python3 di baris host pada inventory.ini jika kasus ini terjadi.

36.3.3 Anatomi Playbook YAML

Playbook adalah file YAML yang mendeskripsikan satu atau lebih play, dan setiap play berisi daftar task yang dijalankan berurutan terhadap host tertentu. Setiap task pada dasarnya memanggil satu module, yaitu unit kerja Ansible yang sudah dibungkus agar idempotent, misalnya module ansible.builtin.apt untuk manajemen paket atau ansible.builtin.service untuk mengelola service systemd.

Langkah Praktik

  1. Buat playbook percobaan pertama untuk memahami strukturnya sebelum masuk ke playbook nginx yang sesungguhnya.
    nano hello.yml
  2. Isi dengan struktur minimal berikut.
    ---
    - name: Playbook percobaan pertama
      hosts: webservers
      tasks:
        - name: Tampilkan pesan sederhana
          ansible.builtin.debug:
            msg: "Ansible berhasil terhubung ke {{ inventory_hostname }}"
    Baris name di level play dan di level task hanya label deskriptif yang tercetak saat eksekusi, tidak memengaruhi logika. hosts: webservers menunjuk ke group yang didefinisikan di inventory.ini pada Bagian 36.3.1. Variable {{ inventory_hostname }} memakai sintaks Jinja2, template engine yang dipakai Ansible untuk menyisipkan nilai dinamis, dalam hal ini nama host yang sedang diproses.
  3. Jalankan playbook.
    ansible-playbook -i inventory.ini hello.yml

Verifikasi dan Troubleshooting

  • Output semestinya menampilkan blok TASK [Gathering Facts] lebih dulu, sebuah task otomatis yang selalu berjalan di awal play untuk mengumpulkan informasi sistem managed node, disusul TASK [Tampilkan pesan sederhana] yang mencetak pesan berisi app01, lalu ditutup baris PLAY RECAP berisi ringkasan app01 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0.
  • Error YAML seperti mapping values are not allowed in this context hampir selalu berarti masalah indentasi. YAML sangat sensitif terhadap spasi, dan Ansible mensyaratkan indentasi konsisten memakai spasi, bukan karakter tab.
  • Task Gathering Facts bisa dinonaktifkan lewat gather_facts: false di level play untuk mempercepat eksekusi playbook yang tidak butuh informasi sistem managed node, meski untuk playbook nginx di bagian berikutnya kita biarkan aktif seperti default.

36.4 Menjalankan Playbook Sederhana: Instalasi Nginx

Bab 12 memasang Nginx di 192.168.1.20 secara manual lewat apt install nginx yang diketik langsung di terminal server tersebut. Bagian ini menuliskan ulang proses yang sama dalam bentuk playbook, lalu menjalankannya ke app01. Perbedaannya baru terasa penuh begitu proses yang sama perlu diulang ke server kedua, ketiga, atau kesepuluh: cukup jalankan playbook yang sama, tanpa mengetik ulang urutan perintah manual di setiap server.

36.4.1 Menulis Playbook install-nginx.yml

Langkah Praktik

  1. Buat file playbook baru.
    nano install-nginx.yml
  2. Isi dengan dua task: memasang paket nginx, lalu memastikan service-nya aktif dan enabled.
    ---
    - name: Instalasi dan menjalankan Nginx
      hosts: webservers
      become: true
      tasks:
        - name: Pasang paket nginx
          ansible.builtin.apt:
            name: nginx
            state: present
            update_cache: true
    
        - name: Pastikan service nginx aktif dan enabled saat boot
          ansible.builtin.service:
            name: nginx
            state: started
            enabled: true
    become: true di level play membuat seluruh task di bawahnya dijalankan lewat privilege escalation (setara sudo) di managed node, sejalan dengan pengecekan akses sudo yang sudah dilakukan di Bagian 36.2.2. Parameter update_cache: true pada module ansible.builtin.apt setara menjalankan apt update sebelum instalasi, sedangkan state: present berarti "pastikan paket ini terpasang", tidak masalah apakah sudah ada sebelumnya atau belum, konsisten dengan prinsip idempotent di Bagian 36.1.2. Module ansible.builtin.service pada task kedua setara kombinasi systemctl start nginx dan systemctl enable nginx yang sudah dipraktikkan manual di Bab 5.
  3. Periksa sintaks playbook sebelum benar-benar dijalankan.
    ansible-playbook -i inventory.ini install-nginx.yml --syntax-check

Verifikasi dan Troubleshooting

  • Perintah --syntax-check hanya memvalidasi struktur YAML dan nama module, tidak benar-benar menghubungi managed node maupun mengubah apa pun. Output playbook: install-nginx.yml tanpa pesan error berarti sintaksnya sudah valid.
  • Nama module ditulis lengkap dengan prefix ansible.builtin., mengikuti konvensi Fully Qualified Collection Name (FQCN) yang direkomendasikan Ansible sejak versi 2.10 ke atas untuk menghindari ambiguitas ketika ada collection pihak ketiga yang kebetulan memakai nama module sama.

36.4.2 Menjalankan dan Memverifikasi Idempotency Playbook

Langkah Praktik

  1. Jalankan playbook untuk pertama kalinya. Tambahkan flag --ask-become-pass (bisa disingkat -K) jika user di app01 masih diminta password saat sudo pada pengecekan Bagian 36.2.2.
    ansible-playbook -i inventory.ini install-nginx.yml
  2. Jalankan ulang playbook yang persis sama tanpa mengubah apa pun, untuk membuktikan sifat idempotent yang dibahas di Bagian 36.1.2.
    ansible-playbook -i inventory.ini install-nginx.yml

Verifikasi dan Troubleshooting

  • Pada eksekusi pertama, baris PLAY RECAP semestinya menampilkan app01 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0, dengan changed=2 menandakan task pasang paket dan task aktifkan service sama-sama benar-benar mengubah kondisi app01.
  • Pada eksekusi kedua, angka changed semestinya turun jadi 0 sementara ok tetap 3, karena Ansible mendeteksi paket nginx sudah terpasang dan service sudah berjalan, sehingga tidak ada tindakan yang perlu diulang. Inilah bukti nyata sifat idempotent yang secara teori sudah dijelaskan di Bagian 36.1.2. Parameter update_cache: true tidak mengubah kesimpulan ini; Ansible tetap menjalankan apt update di balik layar pada kedua eksekusi, tetapi status changed pada module ansible.builtin.apt murni mengikuti ada tidaknya perubahan pada paket itu sendiri, bukan dari pembaruan cache-nya.
  • Konfirmasikan dari luar bahwa Nginx benar-benar berjalan di app01, memakai pola curl yang sama seperti Bagian 12.1.
    curl http://192.168.1.40
    Halaman Welcome to nginx! bawaan yang muncul menandakan instalasi lewat playbook sudah berhasil menghasilkan kondisi akhir yang sama seperti instalasi manual di Bab 12.
  • Kegagalan dengan pesan menyinggung Missing sudo password berarti flag --ask-become-pass pada langkah pertama terlewat, padahal user di managed node belum dikonfigurasi NOPASSWD di sudoers.
  • Untuk audit cepat sebelum benar-benar mengubah kondisi server produksi, flag --check menjalankan playbook dalam mode simulasi mirip dry-run yang sudah dikenal dari Bagian 35.2.2, melaporkan task mana saja yang akan changed tanpa benar-benar mengeksekusinya. Kebiasaan ini layak dijadikan standar sebelum menjalankan playbook baru ke server produksi yang belum pernah diuji.

Sampai di sini, kita sudah punya alur kerja Ansible yang utuh meski masih sederhana: satu control node, satu managed node terdaftar di inventory, dan satu playbook yang terbukti idempotent saat dijalankan berulang. Playbook install-nginx.yml ini juga bisa langsung dijalankan ke lebih dari satu host sekaligus hanya dengan menambah baris baru di inventory.ini, tanpa mengubah satu baris pun di playbook itu sendiri, persis kemampuan yang tidak dimiliki script bash manual di Bab 35. Bab 37 melangkah ke tahap sebelumnya dalam siklus hidup server, yaitu cloud-init, yang mengotomasi provisioning awal seperti pembuatan user dan pemasangan SSH key sejak detik pertama VM menyala, sebelum Ansible sempat masuk mengambil alih konfigurasi lanjutan seperti yang sudah kita praktikkan di bab ini.