Cluster Maintenance #
Mengelola kluster Kubernetes di lingkungan produksi membutuhkan perhatian ekstra terhadap aspek keandalan dan ketersediaan layanan. Infrastruktur yang berjalan tidak bersifat statis; kita harus secara rutin melakukan pemeliharaan (maintenance) seperti pembaruan sistem operasi node, peningkatan (upgrade) versi Kubernetes, serta pencadangan (backup) berkala pada database etcd. Melakukan tugas-tugas pemeliharaan ini secara manual pada puluhan atau ratusan node tidak hanya melelahkan, tetapi juga meningkatkan risiko kesalahan konfigurasi manusia (human error) yang dapat akibat downtime. Dengan memanfaatkan Ansible, kita dapat menyusun alur kerja pemeliharaan yang terorkestrasi, konsisten, terdokumentasi, dan dapat diulang dengan aman tanpa mengorbankan stabilitas aplikasi yang sedang berjalan.
Manajemen Siklus Hidup Node: Cordon dan Drain #
Sebelum kita menyentuh server fisik atau mesin virtual yang bertindak sebagai worker node untuk melakukan pemeliharaan seperti pembaruan kernel atau penggantian perangkat keras, kita harus memastikan bahwa tidak ada beban kerja (workload) yang terganggu. Proses pemindahan beban kerja ini di dalam Kubernetes dikenal dengan istilah cordon (menandai node agar tidak menerima Pod baru) dan drain (mengeluarkan Pod yang sedang berjalan secara ramah ke node lain).
Jika kita langsung mematikan atau men-reboot server tanpa melakukan proses ini, aplikasi yang berjalan di dalamnya akan mengalami pemutusan koneksi secara mendadak. Pod yang mati membutuhkan waktu untuk dideteksi oleh control plane sebelum akhirnya dijadwalkan ulang di node lain. Selama jeda waktu tersebut, pengguna akan mengalami gangguan layanan.
Mengapa Cordon dan Drain Harus Berurutan? #
Proses pemeliharaan node harus mengikuti urutan logis yang ketat. Pertama, kita menandai node sebagai unschedulable (cordon). Hal ini mencegah scheduler Kubernetes menempatkan Pod baru di node tersebut saat proses pemindahan Pod lama sedang berlangsung. Kedua, kita melakukan pengosongan node (drain) yang akan mengevakuasi semua Pod aktif ke node worker lain yang masih sehat.
Berikut adalah visualisasi alur kerja manajemen pemeliharaan node yang aman:
flowchart TD
A["Mulai Maintenance Node"] --> B["Cordon Node (spec.unschedulable)"]
B --> C["Drain Node (Eviction)"]
C --> D{"Apakah ada DaemonSet / emptyDir?"}
D -- "Ya" --> E["Gunakan --ignore-daemonsets & --delete-emptydir-data"]
D -- "Tidak" --> F["Evakuasi Pod Selesai"]
E --> F
F --> G["Lakukan Update OS / Package (Kubeadm, Kubelet)"]
G --> H["Reboot Node (Jika Dibutuhkan)"]
H --> I["Uncordon Node"]
I --> J["Verifikasi Node Ready"]
J --> K["Selesai"]
Anti-Pattern vs Solusi Otomasi Cordon-Drain #
Mari kita pelajari contoh kesalahan umum dalam pemeliharaan node dan bagaimana solusi yang tepat menggunakan modul Ansible.
# ANTI-PATTERN: Melakukan pemeliharaan node langsung dengan reboot atau tanpa drain terpadu
- name: Reboot langsung worker node
hosts: worker_nodes
become: true
tasks:
- name: Restart server langsung
reboot:
reboot_timeout: 300
# JANGAN lakukan ini! Pod akan mati mendadak, traffic akan drop,
# dan scheduler memerlukan waktu hingga 5 menit (pod-eviction-timeout)
# untuk menjadwalkan ulang Pod ke node lain.
# BENAR: Menggunakan koordinasi terpadu untuk cordon dan drain secara anggun
- name: Cordon dan drain node secara anggun sebelum maintenance
hosts: localhost
vars:
target_node: "k8s-worker-01"
tasks:
- name: Tandai node sebagai unschedulable (Cordon)
kubernetes.core.k8s:
kubeconfig: "~/.kube/config"
state: present
definition:
apiVersion: v1
kind: Node
metadata:
name: "{{ target_node }}"
spec:
unschedulable: true
- name: Evakuasi beban kerja dari node (Drain)
command: >
kubectl drain {{ target_node }}
--ignore-daemonsets
--delete-emptydir-data
--grace-period=60
--timeout=300s
--kubeconfig ~/.kube/config
register: drain_result
changed_when: true
Dalam contoh solusi di atas, kita menggunakan modul kubernetes.core.k8s untuk memanipulasi spesifikasi node secara langsung guna mengaktifkan status unschedulable. Setelah itu, kita menggunakan perintah kubectl drain yang dibungkus dalam modul command karena modul native k8s belum menyediakan pembungkus khusus untuk perintah drain yang seandel CLI bawaan. Parameter --ignore-daemonsets wajib kita sertakan karena Pod yang dikelola oleh DaemonSet berjalan di setiap node dan tidak dapat dipindahkan. Parameter --delete-emptydir-data memastikan Pod yang menggunakan penyimpanan lokal sementara (emptyDir) tetap dapat dievakuasi meskipun datanya akan terhapus.
Mengatasi Hambatan Drain (DaemonSets, Local Storage, dan Grace Period) #
Saat kita menjalankan proses drain, terkadang kita menemui kegagalan akibat adanya Pod yang tidak dikelola oleh Controller (seperti Deployment, StatefulSet, atau ReplicaSet), atau adanya Pod yang menggunakan penyimpanan lokal. Kita harus menangani kasus ini dengan parameter tambahan.
Jika terdapat Pod mandiri (standalone Pod) yang dibuat langsung tanpa controller, Kubernetes secara default akan menolak proses drain untuk menghindari kehilangan data secara permanen. Jika kita yakin Pod tersebut aman untuk dihapus, kita bisa menambahkan parameter --force pada perintah drain kita. Selain itu, parameter --grace-period=60 memberikan waktu bagi aplikasi di dalam Pod untuk menyelesaikan sisa proses atau koneksi aktif (graceful shutdown) sebelum sistem mengirimkan sinyal SIGKILL.
Setelah tugas pemeliharaan selesai, kita harus mengembalikan node agar dapat menerima Pod kembali. Proses ini dinamakan uncordon. Berikut adalah playbook Ansible untuk mengembalikan fungsionalitas penjadwalan node:
- name: Kembalikan node ke status aktif (Uncordon)
hosts: localhost
vars:
target_node: "k8s-worker-01"
tasks:
- name: Jadwalkan kembali Pod ke node (Uncordon)
kubernetes.core.k8s:
kubeconfig: "~/.kube/config"
state: present
definition:
apiVersion: v1
kind: Node
metadata:
name: "{{ target_node }}"
spec:
unschedulable: false
- name: Tunggu status node menjadi Ready
kubernetes.core.k8s_info:
kubeconfig: "~/.kube/config"
kind: Node
name: "{{ target_node }}"
register: node_info
until: >
node_info.resources[0].status.conditions
| selectattr('type', 'equalto', 'Ready')
| map(attribute='status')
| first == 'True'
retries: 20
delay: 10
Dengan alur ini, kita menjamin bahwa transisi node sebelum dan sesudah pemeliharaan terpantau secara penuh oleh sistem monitoring Ansible kita.
Strategi Upgrade Komponen Kubernetes (Kubeadm, Kubelet, dan Kubectl) #
Proses peningkatan versi (upgrade) kluster Kubernetes adalah tugas rutin yang wajib dijalankan untuk memastikan kita mendapatkan pembaruan keamanan, perbaikan bug, dan fitur-fitur terbaru. Kubernetes merekomendasikan agar kita melakukan upgrade maksimal satu versi minor dalam satu waktu (misalnya dari versi 1.28 ke 1.29, bukan melompat langsung dari 1.28 ke 1.30).
Proses upgrade harus dimulai dari control plane terlebih dahulu sebelum dilanjutkan ke worker node. Komponen pertama yang di-upgrade adalah kubeadm, kemudian konfigurasi control plane, diikuti oleh kubelet dan kubectl pada node control plane, baru setelah itu kita memperbarui worker node satu per satu.
Prosedur Upgrade Control Plane secara Terorkestrasi #
Mari kita buat playbook Ansible yang aman untuk memproses peningkatan komponen pada control plane. Playbook ini akan memperbarui repositori paket, melakukan instalasi kubeadm versi baru, menerapkan konfigurasi upgrade Kubernetes, dan memperbarui kubelet.
# playbooks/upgrade-control-plane.yml
---
- name: Peningkatan Versi Kubernetes Control Plane
hosts: control_plane
become: true
serial: 1
vars:
target_version: "1.29.2"
debian_version: "1.29.2-1.1" # Sesuaikan dengan format penamaan paket distribusi
tasks:
- name: Perbarui cache repositori paket apt
apt:
update_cache: true
- name: Hapus proteksi hold pada kubeadm
dpkg_selections:
name: kubeadm
selection: install
- name: Install kubeadm versi target
apt:
name: "kubeadm={{ debian_version }}"
state: present
update_cache: true
- name: Pasang kembali proteksi hold pada kubeadm
dpkg_selections:
name: kubeadm
selection: hold
- name: Jalankan simulasi verifikasi upgrade (Upgrade Plan)
command: "kubeadm upgrade plan v{{ target_version }}"
register: upgrade_plan
changed_when: false
- name: Tampilkan hasil simulasi upgrade
debug:
var: upgrade_plan.stdout_lines
- name: Terapkan upgrade control plane
command: "kubeadm upgrade apply v{{ target_version }} --yes"
register: upgrade_apply_result
changed_when: "'Upgrade complete!' in upgrade_apply_result.stdout"
- name: Hapus proteksi hold pada kubelet dan kubectl
dpkg_selections:
name: "{{ item }}"
selection: install
loop:
- kubelet
- kubectl
- name: Upgrade kubelet dan kubectl
apt:
name:
- "kubelet={{ debian_version }}"
- "kubectl={{ debian_version }}"
state: present
- name: Terapkan kembali proteksi hold pada kubelet dan kubectl
dpkg_selections:
name: "{{ item }}"
selection: hold
loop:
- kubelet
- kubectl
- name: Muat ulang daemon systemd
systemd:
daemon_reload: true
- name: Restart layanan kubelet
systemd:
name: kubelet
state: restarted
enabled: true
Playbook di atas memanfaatkan perintah dpkg_selections untuk melepas sementara status hold pada paket APT. Status hold ini sangat penting di lingkungan produksi agar paket-paket sistem Kubernetes tidak ter-upgrade secara tidak sengaja saat administrator menjalankan perintah apt-get upgrade harian. Setelah kita memasang versi yang sesuai, kita wajib mengembalikan status hold tersebut.
Orkestrasi Rolling Upgrade Node Worker #
Setelah control plane berhasil ditingkatkan, kita dapat meningkatkan versi paket pada seluruh worker node. Kita tidak boleh memperbarui semua worker node sekaligus karena akan menyebabkan kehabisan kapasitas kluster dan downtime aplikasi. Kita harus mengorkestrasinya secara bergantian (rolling upgrade) menggunakan parameter serial: 1 pada level play.
Berikut adalah playbook untuk melakukan rolling upgrade pada seluruh worker node:
# playbooks/upgrade-worker-nodes.yml
---
- name: Rolling Upgrade Paket Worker Nodes
hosts: worker_nodes
become: true
serial: 1 # Memproses node satu per satu untuk mencegah downtime
vars:
target_version: "1.29.2"
debian_version: "1.29.2-1.1"
kubeconfig_path: "/home/ansible/.kube/config"
tasks:
- name: Drain worker node dari kontrol lokal (Control Node)
delegate_to: localhost
become: false
command: >
kubectl drain {{ inventory_hostname }}
--ignore-daemonsets
--delete-emptydir-data
--grace-period=60
--timeout=300s
--kubeconfig {{ kubeconfig_path }}
changed_when: true
- name: Hapus proteksi hold pada komponen node
dpkg_selections:
name: "{{ item }}"
selection: install
loop:
- kubeadm
- kubelet
- kubectl
- name: Upgrade kubeadm di worker node
apt:
name: "kubeadm={{ debian_version }}"
state: present
update_cache: true
- name: Jalankan konfigurasi upgrade worker node
command: kubeadm upgrade node
register: node_upgrade_result
changed_when: "'Successfully upgraded' in node_upgrade_result.stdout"
- name: Upgrade kubelet dan kubectl di worker node
apt:
name:
- "kubelet={{ debian_version }}"
- "kubectl={{ debian_version }}"
state: present
- name: Kembalikan status hold pada komponen node
dpkg_selections:
name: "{{ item }}"
selection: hold
loop:
- kubeadm
- kubelet
- kubectl
- name: Muat ulang konfigurasi systemd
systemd:
daemon_reload: true
- name: Restart layanan kubelet
systemd:
name: kubelet
state: restarted
- name: Kembalikan node agar dapat dijadwalkan kembali (Uncordon)
delegate_to: localhost
become: false
command: >
kubectl uncordon {{ inventory_hostname }}
--kubeconfig {{ kubeconfig_path }}
changed_when: true
- name: Verifikasi kestabilan node
delegate_to: localhost
become: false
kubernetes.core.k8s_info:
kubeconfig: "{{ kubeconfig_path }}"
kind: Node
name: "{{ inventory_hostname }}"
register: node_status
until: >
node_status.resources[0].status.conditions
| selectattr('type', 'equalto', 'Ready')
| map(attribute='status')
| first == 'True'
retries: 15
delay: 10
Dalam playbook ini, teknik delegate_to: localhost digunakan untuk menjalankan perintah administratif kubectl langsung dari control node (mesin tempat Ansible dijalankan) yang memiliki otorisasi file kubeconfig. Hal ini menghindarkan kita dari keharusan menyalin file sensitif kubeconfig ke seluruh worker node. Langkah ini meningkatkan postur keamanan infrastruktur kita secara signifikan.
Backup dan Pemulihan etcd secara Terdistribusi #
Komponen etcd adalah pilar utama dari kluster Kubernetes yang bertindak sebagai penyimpanan data key-value yang konsisten dan terdistribusi. Seluruh definisi objek Kubernetes, status kluster, konfigurasi jaringan, dan rahasia aplikasi (Secrets) disimpan di dalam etcd. Jika terjadi kegagalan fatal pada data etcd tanpa adanya backup, kluster kita tidak akan bisa diselamatkan. Oleh karena itu, menyusun sistem pencadangan etcd otomatis adalah kewajiban mutlak bagi tim operasi.
Cara Kerja Snapshot etcd #
Pencadangan etcd dilakukan dengan membuat snapshot point-in-time dari data store menggunakan perintah etcdctl. Karena etcd dalam kluster produksi biasanya dikonfigurasi menggunakan TLS untuk enkripsi lalu lintas data, proses backup memerlukan akses ke sertifikat enkripsi kluster seperti Certificate Authority (CA) root, sertifikat server, dan private key-nya.
Berikut adalah visualisasi alur pencadangan etcd terdistribusi menggunakan kontroler otomatis:
flowchart TD
A["Trigger Backup Scheduler"] --> B["Dapatkan Credential Cert/Key etcd"]
B --> C["Jalankan etcdctl snapshot save"]
C --> D{"Verifikasi Integritas?"}
D -- "Ya (Valid)" --> E["Salin Snapshot ke Control Node (Fetch)"]
D -- "Tidak (Gagal)" --> F["Kirim Notifikasi Alert"]
E --> G["Terapkan Retention Policy (Hapus Backup >7 Hari)"]
G --> H["Selesai"]
Playbook Ansible untuk Backup etcd secara Otomatis #
Mari kita buat playbook Ansible yang melakukan eksekusi backup etcd secara berkala pada node control plane, memverifikasi integritas file cadangan tersebut, mengunduhnya ke tempat penyimpanan terpusat, dan menerapkan kebijakan retensi penyimpanan.
# playbooks/backup-etcd.yml
---
- name: Backup Database etcd Kubernetes
hosts: control_plane[0] # Cukup jalankan di salah satu node control plane
become: true
vars:
etcd_backup_dir: "/var/backups/etcd"
etcd_certs_dir: "/etc/kubernetes/pki/etcd"
local_backup_dest: "/opt/backup-center/k8s-etcd"
tasks:
- name: Buat direktori penyimpanan backup lokal di target host
file:
path: "{{ etcd_backup_dir }}"
state: directory
mode: '0700'
owner: root
group: root
- name: Dapatkan cap waktu untuk nama file unik
set_fact:
backup_timestamp: "{{ lookup('pipe', 'date +%Y%m%d-%H%M%S') }}"
- name: Jalankan snapshot etcdctl
command: >
etcdctl snapshot save {{ etcd_backup_dir }}/etcd-snap-{{ backup_timestamp }}.db
--endpoints=https://127.0.0.1:2379
--cacert={{ etcd_certs_dir }}/ca.crt
--cert={{ etcd_certs_dir }}/server.crt
--key={{ etcd_certs_dir }}/server.key
environment:
ETCDCTL_API: "3"
register: etcd_backup_result
- name: Verifikasi integritas file snapshot yang baru dibuat
command: >
etcdctl snapshot status {{ etcd_backup_dir }}/etcd-snap-{{ backup_timestamp }}.db
--write-out=table
environment:
ETCDCTL_API: "3"
register: etcd_status_result
changed_when: false
- name: Pastikan file backup valid sebelum diproses lebih lanjut
assert:
that:
- "'total size' in etcd_status_result.stdout"
fail_msg: "File snapshot etcd mengalami kerusakan atau tidak valid!"
- name: Buat direktori backup di mesin Ansible Control
delegate_to: localhost
become: false
file:
path: "{{ local_backup_dest }}"
state: directory
mode: '0750'
- name: Ambil file backup ke penyimpanan terpusat (Ansible Control Node)
fetch:
src: "{{ etcd_backup_dir }}/etcd-snap-{{ backup_timestamp }}.db"
dest: "{{ local_backup_dest }}/etcd-snap-{{ inventory_hostname }}-{{ backup_timestamp }}.db"
flat: true
- name: Cari cadangan etcd yang lebih lama dari 7 hari di target host
find:
paths: "{{ etcd_backup_dir }}"
age: "7d"
patterns: "etcd-snap-*.db"
register: old_backups
- name: Hapus cadangan etcd yang sudah kedaluwarsa di target host
file:
path: "{{ item.path }}"
state: absent
loop: "{{ old_backups.files }}"
Prosedur Pemulihan (Restore) etcd dalam Kondisi Darurat #
Ketika kluster kita mengalami kerusakan data total, etcd harus dipulihkan sebelum API server Kubernetes dapat berjalan kembali. Proses pemulihan ini harus dijalankan dengan sangat hati-hati karena etcd harus dihentikan sepenuhnya di semua node control plane terlebih dahulu untuk mencegah konflik sinkronisasi status.
Langkah-langkah pemulihan etcd adalah sebagai berikut:
- Hentikan semua manifest static pod
kube-apiserverdanetcddengan memindahkan file definisinya dari direktori manifest/etc/kubernetes/manifestsagar systemd/kubelet mematikan container tersebut. - Hapus direktori data etcd lama yang rusak di
/var/lib/etcd. - Jalankan perintah
etcdctl snapshot restoredengan parameter nama node, alamat IP peer, dan daftar inisialisasi kluster etcd yang sesuai. - Pindahkan kembali manifest static pod ke direktori semula agar kubelet menyalakan kembali API server dan etcd.
Berikut adalah contoh skrip pemulihan etcd yang diotomatiskan dengan Ansible:
# playbooks/restore-etcd.yml
---
- name: Pemulihan etcd Kluster Kubernetes dari Backup
hosts: control_plane
become: true
vars:
etcd_data_dir: "/var/lib/etcd"
manifest_dir: "/etc/kubernetes/manifests"
backup_file_path: "/tmp/etcd-snap-restore.db" # Pastikan file backup sudah disalin ke direktori ini
etcd_certs_dir: "/etc/kubernetes/pki/etcd"
cluster_token: "etcd-k8s-cluster"
tasks:
- name: Periksa ketersediaan file backup di host
stat:
path: "{{ backup_file_path }}"
register: backup_file_status
- name: Gagalkan jika file backup tidak ditemukan
fail:
msg: "File backup tidak ditemukan di {{ backup_file_path }}!"
when: not backup_file_status.stat.exists
- name: Nonaktifkan API Server dan etcd dengan memindahkan manifes static pod
file:
path: "{{ manifest_dir }}/{{ item }}"
state: absent
loop:
- kube-apiserver.yaml
- etcd.yaml
# Langkah ini penting agar kubelet mematikan pod apiserver dan etcd saat ini.
- name: Beri jeda agar container benar-benar berhenti
pause:
seconds: 15
- name: Hapus direktori data etcd yang lama (Backup data lama terlebih dahulu jika perlu)
file:
path: "{{ etcd_data_dir }}"
state: absent
- name: Jalankan restorasi etcd snapshot lokal
command: >
etcdctl snapshot restore {{ backup_file_path }}
--name={{ inventory_hostname }}
--initial-cluster={{ inventory_hostname }}=https://{{ ansible_default_ipv4.address }}:2380
--initial-cluster-token={{ cluster_token }}
--initial-advertise-peer-urls=https://{{ ansible_default_ipv4.address }}:2380
--data-dir={{ etcd_data_dir }}
environment:
ETCDCTL_API: "3"
- name: Pastikan hak kepemilikan direktori data etcd baru sesuai
file:
path: "{{ etcd_data_dir }}"
state: directory
owner: root
group: root
recurse: true
- name: Aktifkan kembali API Server dan etcd dengan memulihkan manifes static pod
# Kita bisa menyalinnya kembali dari direktori backup aman
copy:
src: "/etc/kubernetes/manifests-backup/{{ item }}"
dest: "{{ manifest_dir }}/{{ item }}"
remote_src: true
loop:
- etcd.yaml
- kube-apiserver.yaml
Proses pemulihan ini harus disesuaikan dengan konfigurasi jaringan kluster masing-masing. Sangat penting bagi kita untuk menguji skrip pemulihan ini di kluster staging secara berkala agar saat terjadi kegagalan nyata di produksi, tim operasional dapat bertindak dengan tenang dan terarah.
Penanganan Node Bermasalah dan Pemulihan Otomatis #
Selain tugas pemeliharaan terjadwal, kluster Kubernetes seringkali menghadapi situasi darurat di mana node tiba-tiba berganti status menjadi NotReady atau mengalami tekanan sumber daya (resource pressure). Faktor penyebabnya bisa beragam, mulai dari kehabisan memori (OOM), kegagalan disk, hingga crash pada daemon container runtime seperti Docker atau Containerd.
Sebagai administrator, kita dapat memanfaatkan Ansible untuk melakukan deteksi dini (drift detection / health check) dan melakukan tindakan pemulihan mandiri (self-healing) secara otomatis tanpa menunggu tiket keluhan masuk ke meja bantuan TI.
Memahami Kondisi Status Node #
Kubernetes mengekspos beberapa kondisi kesehatan node. Kita dapat memantau kondisi ini secara terperinci menggunakan modul Ansible. Berikut adalah ringkasan indikator kondisi utama pada node dan tindakan remediasi yang bisa kita ambil melalui skrip Ansible:
| Kondisi Node | Deskripsi Masalah | Tindakan Pemulihan dengan Ansible |
|---|---|---|
| Ready | Node dalam kondisi sehat dan dapat menerima Pod. | Tidak ada tindakan yang diperlukan. |
| DiskPressure | Kapasitas penyimpanan lokal menipis (<10%). | Jalankan pembersihan cache docker, hapus image yang tidak terpakai, dan bersihkan direktori log. |
| MemoryPressure | Kapasitas RAM menipis, berisiko terjadi OOM. | Identifikasi Pod non-essential dengan konsumsi RAM tinggi, pindahkan beban kerja secara rolling. |
| PIDPressure | Terlalu banyak proses berjalan pada node. | Periksa limitasi max PID di systemd, restart proses zombie, batasi thread container. |
| NetworkUnavailable | Konfigurasi jaringan node terganggu. | Restart daemon CNI (seperti Calico/Cilium), periksa tabel routing, muat ulang modul jaringan kernel. |
Playbook Remediasi Otomatis untuk Node Bermasalah #
Mari kita buat playbook Ansible defensif yang memantau status keaktifan layanan runtime kontainer (containerd) dan agen kubelet pada setiap node worker. Jika layanan tersebut mati, Ansible akan mendeteksi dan mencoba menghidupkannya kembali, lalu memverifikasi pemulihannya.
# playbooks/node-remediation.yml
---
- name: Deteksi dan Remediasi Otomatis Layanan Node Worker
hosts: worker_nodes
become: true
tasks:
- name: Cek status keaktifan runtime containerd
ansible.builtin.systemd:
name: containerd
register: containerd_status
- name: Cek status keaktifan agen kubelet
ansible.builtin.systemd:
name: kubelet
register: kubelet_status
- name: Lakukan tindakan pemulihan jika containerd mati
ansible.builtin.systemd:
name: containerd
state: restarted
when: containerd_status.status.ActiveState != 'active'
register: containerd_remediation
- name: Beri jeda 10 detik agar containerd menginisialisasi soket
pause:
seconds: 10
when: containerd_remediation.changed
- name: Lakukan tindakan pemulihan jika kubelet mati
ansible.builtin.systemd:
name: kubelet
state: restarted
when: kubelet_status.status.ActiveState != 'active'
- name: Bersihkan cache gambar tidak terpakai jika DiskPressure terjadi
block:
- name: Dapatkan informasi disk space root
ansible.builtin.setup:
filter: "ansible_mounts"
- name: Hitung persentase penggunaan disk root
set_fact:
root_disk: "{{ ansible_mounts | selectattr('mount', 'equalto', '/') | first }}"
- name: Jalankan pembersihan docker/containerd cache jika penggunaan disk > 85%
command: crictl rmi --prune
when: "((root_disk.size_total - root_disk.size_available) / root_disk.size_total * 100) > 85"
changed_when: true
register: prune_result
- name: Tampilkan log pembersihan disk
debug:
var: prune_result.stdout_lines
when: prune_result.changed
rescue:
- name: Peringatan jika proses pembersihan disk gagal
debug:
msg: "Gagal mendeteksi disk space atau crictl rmi tidak tersedia pada node."
Playbook di atas merupakan contoh implementasi pemulihan mandiri (self-healing) sederhana. Kita dapat memperluas logika ini dengan mengintegrasikan sistem alert seperti Prometheus Alertmanager untuk memicu Ansible playbook secara otomatis menggunakan webhook ketika mendeteksi masalah pada kluster Kubernetes kita.
Ringkasan #
- Orkestrasi Cordon & Drain secara Berurutan — Selalu lakukan cordon untuk menandai node agar tidak menerima Pod baru sebelum menjalankan perintah drain untuk memindahkan beban kerja secara ramah.
- Konfigurasi Drain yang Kuat — Gunakan opsi
--ignore-daemonsetsuntuk mengabaikan daemon sistem dan--delete-emptydir-datauntuk menyetujui penghapusan data lokal sementara saat mengevakuasi Pod.- Peningkatan Bertahap Versi Minor — Jalankan proses upgrade Kubernetes secara berurutan satu versi minor sekaligus. Mulai upgrade dari node control plane baru dilanjutkan ke worker node.
- Proteksi Paket dengan APT Hold — Kunci versi paket
kubeadm,kubelet, dankubectlmenggunakan status hold agar tidak ter-upgrade secara tidak sengaja oleh pemeliharaan harian OS.- Pencadangan etcd dengan Enkripsi TLS — Lakukan backup etcd secara teratur menggunakan perintah
etcdctl snapshot savedengan menyertakan sertifikat enkripsi TLS lengkap yang valid.- Penyimpanan Snapshot Terpusat — Manfaatkan modul
fetchpada Ansible untuk menarik file snapshot etcd ke mesin Ansible control node yang aman untuk mempermudah manajemen pemulihan bencana.- Remediasi Otomatis Node Bermasalah — Buat playbook pemantauan mandiri untuk mendeteksi matinya runtime kontainer atau kehabisan ruang disk, lalu terapkan tindakan pemulihan instan seperti restart layanan dan pembersihan cache.