Designing Zero-Downtime High Availability Clusters with Kubernetes and MySQL
1. Konteks Industri & Analisis Akar Masalah
Dalam lanskap arsitektur web modern yang menuntut ketersediaan 99.999% (five nines), kegagalan infrastruktur bukanlah sebuah kemungkinan, melainkan kepastian waktu. Sistem web backend tradisional yang mengandalkan satu node database tunggal (Single Point of Failure atau SPOF) dan server aplikasi tanpa manajemen status otomatis sudah usang. Ketika terjadi lonjakan traffic, kegagalan disk, atau peremajaan kernel (kernel upgrade), sistem tersebut akan mengalami downtime yang merugikan secara finansial dan merusak reputasi merek.
Secara historis, administrator sistem sering mengandalkan skrip bash sederhana, pengaturan Master-Slave replikasi manual, dan penyeimbang beban konvensional berbasis HAProxy atau Nginx lokal yang rapuh. Masalah utama dari pendekatan ini adalah lambatnya proses deteksi kegagalan (failover detection), ketidakkonsistenan data akibat split-brain syndrome, serta tidak adanya orkestrasi otomatis ketika pod aplikasi kehilangan koneksi ke database mereka.
Sebelum vs Sesudah Penerapan Arsitektur Zero-Downtime
| Parameter | Arsitektur Tradisional (SPOF) | Arsitektur Kluster K8s & MySQL GR |
|---|---|---|
| Waktu Pemulihan (RTO) | Menghitung jam hingga intervensi manual | Detik (Otomatis melalui Kubernetes liveness/readiness probes) |
| Kehilangan Data (RPO) | Tinggi jika terjadi crash sebelum sync | Nol (Strong consistency via MySQL Group Replication Multi-Master/Single-Master) |
| Strategi Deployment | Rolling update manual yang menyebabkan terputusnya koneksi aktif | Rolling deployment tanpa drop packet dengan graceful termination |
| Skalabilitas | Terikat pada batas kapasitas satu server fisik/VM | Dinamis, dapat diskalakan secara horizontal via Kubernetes HPA & StatefulSets |
2. Konsep Inti & Deep Dive Arsitektur
Membangun kluster yang tahan banting memerlukan integrasi erat antara lapisan orkestrasi kontainer (Kubernetes) dan mesin basis data transaksional (MySQL). Mari kita bedah bagaimana komponen-komponen ini saling berinteraksi under the hood.
Alur Kerja Komunikasi Antar Komponen
+-------------------------------------------------------------------------+
| Kubernetes Cluster (Control Plane) |
| |
| +----------------------+ +-------------------------------------+ |
| | Ingress Controller | ---> | Headless Service (mysql-h) | |
| +----------------------+ +-------------------------------------+ |
| | | | |
| v v v |
| +--------+ +--------+ +--------+ |
| | Pod-0 | | Pod-1 | | Pod-2 | |
| | (SQL) | | (SQL) | | (SQL) | |
| +--------+ +--------+ +--------+ |
| ^ ^ ^ |
| +----+----+----+----+ |
| Group Replication |
+-------------------------------------------------------------------------+
- StatefulSets: Berbeda dengan Deployment biasa, StatefulSet memastikan penamaan pod yang deterministik (
mysql-0,mysql-1,mysql-2) dan keterikatan volume penyimpanan persisten yang stabil (PersistentVolumeClaim) meskipun pod tersebut mengalami penjadwalan ulang (rescheduling) di node Kubernetes yang berbeda. - MySQL Group Replication (MGR): Menyediakan replikasi tingkat lanjut berbasis Paxos consensus algorithm. Transaksi divalidasi di tingkat grup sebelum di-commit. Jika node primer (
mysql-0) gagal, node sekunder secara otomatis memilih pemimpin baru tanpa kehilangan urutan transaksi (GTID - Global Transaction Identifier). - Headless Service: Memungkinkan klien (seperti aplikasi backend berbasis Go, Node.js, atau PHP) untuk melakukan resolusi DNS langsung ke IP masing-masing pod di dalam kluster, memfasilitasi koneksi langsung ke node primer untuk operasi tulis dan node sekunder untuk operasi baca (Read/Write Splitting).
3. Perbandingan Komparatif / Analisis Pendekatan
Sebelum memutuskan desain akhir, kita harus mengevaluasi beberapa pendekatan arsitektur basis data di dalam Kubernetes.
| Pendekatan | Latency | Konsistensi Data | Kompleksitas Operasional | Konsumsi Sumber Daya | Rekomendasi Kasus Penggunaan |
|---|---|---|---|---|---|
| Operator Pihak Ketiga (Percona / Oracle) | Sedang | Kuat (Strong) | Tinggi | Tinggi (Operator overhead) | Perusahaan besar dengan tim DBA khusus |
| Native StatefulSet + MySQL Group Replication | Rendah | Kuat (Strong) | Menengah-Tinggi | Sedang | Enterprise production workloads dengan kontrol penuh |
| External Managed DB (AWS RDS / Google Cloud SQL) | Tinggi | Kuat (Strong) | Rendah | Rendah (Offloaded) | Tim kecil, anggaran besar, minim pengelolaan infrastruktur |
[!IMPORTANT] Penggunaan Operator pihak ketiga memang menyederhanakan day-2 operations seperti backup dan scaling, namun konfigurasi native StatefulSet memberikan fleksibilitas penuh terhadap parameter konfigurasi MySQL (
my.cnf) dan kontrol jaringan (network policies).
4. Prasyarat Sistem & Persiapan Lingkungan
Sebelum mengeksekusi manifes Kubernetes, pastikan lingkungan Anda memenuhi standar spesifikasi berikut:
- Kubernetes Cluster: Versi 1.25+ dengan Container Network Interface (CNI) yang mendukung NetworkPolicies (misal: Calico atau Cilium).
- Storage Class: Penyedia Dynamic Provisioning yang mendukung ReadWriteOnce dengan performa IOPS tinggi (misal: AWS EBS gp3, Ceph RBD, atau Local Storage untuk edge).
- Resource Node Minimum:
- CPU: 4 vCPU per node
- RAM: 8 GB per node
- Disk: 50 GB SSD NVMe
- Tooling:
kubectl,helm, dankubectxterpasang di mesin lokal administrator.
Verifikasi bahwa kluster Anda aktif dan berjalan normal:
kubectl cluster-info
kubectl get nodes -o wide
5. Panduan Implementasi Langkah demi Langkah
Kita akan membangun kluster menggunakan manifes YAML tunggal yang mencakup ConfigMap, Headless Service, StatefulSet, dan PersistentVolumeClaim.
1. Membuat Namespace Khusus
Simpan skrip ini ke dalam file 00-namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: production-db
Terapkan ke kluster:
kubectl apply -f 00-namespace.yaml
2. Konfigurasi MySQL (my.cnf) via ConfigMap
Buat file 01-configmap.yaml untuk mendefinisikan parameter replikasi grup:
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
namespace: production-db
data:
my.cnf: |
[mysqld]
default_authentication_plugin=mysql_native_password
skip-name-resolve
server-id=1
gtid_mode=ON
enforce_gtid_consistency=ON
binlog_checksum=NONE
log_slave_updates=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
read_only=ON
transaction_write_set_extraction=XXHASH64
group_replication=ON
group_replication_start_on_boot=OFF
group_replication_ssl_mode=REQUIRED
group_replication_recovery_use_ssl=1
3. Layanan Jaringan Headless dan ClusterIP
Buat file 02-service.yaml untuk mengelola lalu lintas internal dan eksternal pod:
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
namespace: production-db
labels:
app: mysql
spec:
clusterIP: None
selector:
app: mysql
ports:
- name: mysql
port: 3306
- name: mysql-replication
port: 33061
---
apiVersion: v1
kind: Service
metadata:
name: mysql-read
namespace: production-db
labels:
app: mysql
spec:
type: ClusterIP
selector:
app: mysql
ports:
- name: mysql
port: 3306
4. StatefulSet Manifes Utama
Buat file 03-statefulset.yaml:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: production-db
spec:
selector:
matchLabels:
app: mysql
serviceName: mysql-headless
replicas: 3
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: mysql:8.0.33
command:
- bash
- "-c"
- |
set -ex
# Generate server-id from pod ordinal index
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal='${BASH_REMATCH[1]}'
echo "[mysqld]" > /mnt/conf.d/server-id.cnf
echo "server-id=$((100 + ordinal))" >> /mnt/conf.d/server-id.cnf
if [[ $ordinal -eq 0 ]]; then
echo "group_replication_single_primary_mode=ON" >> /mnt/conf.d/server-id.cnf
else
echo "group_replication_single_primary_mode=OFF" >> /mnt/conf.d/server-id.cnf
fi
volumeMounts:
- name: conf-dir
mountPath: /mnt/conf.d
containers:
- name: mysql
image: mysql:8.0.33
ports:
- containerPort: 3306
name: mysql
- containerPort: 33061
name: replication
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
readinessProbe:
exec:
command: ["mysql