Pernah nggak kalian ngalamin deployment aplikasi di Kubernetes yang kelihatannya sukses? Semua pod berstatus Running dengan warna hijau cantik. Tapi pengguna langsung disambut error 502 Bad Gateway pas buka aplikasi.
Atau skenario yang lebih horor. Server database lagi kelambatan sementara. Eh, tiba-tiba seluruh pod backend di-restart serentak oleh Kubernetes. Jadilah cascading failure. ๐
Masalah klasik ini hampir selalu berakar pada satu hal. Salah kaprah soal health check di Kubernetes.
Banyak developer pemula nganggep health check cukup satu endpoint /health sederhana. Padahal Kubernetes nyediain tiga mekanisme probe yang beda. Tugas dan konsekuensinya sangat berlainan. Ada startup probe, liveness probe, dan readiness probe.
Mari kita bedah cara kerja masing-masing probe. Sekalian gimana masangnya dengan benar biar aplikasi kita tangguh di production.
Poin Penting
- Tiga tipe probe di Kubernetes punya peran spesifik: startup probe buat inisialisasi awal, liveness probe buat deteksi deadlock atau crash, dan readiness probe buat nentuin kesiapan nerima traffic.
- Liveness probe yang meriksa dependensi eksternal (database/Redis) itu jebakan maut, soalnya bisa memicu restart massal alias cascading failure.
- Endpoint
/healthzbuat liveness dan/readybuat readiness sebaiknya dipisah di aplikasi backend, entah itu FastAPI, Go, atau Node.js. - Parameter
initialDelaySeconds,periodSeconds,timeoutSeconds, danfailureThresholdperlu disetel biar lonjakan CPU sesaat nggak memicu false-positive restart.
Tiga Serangkai Probe di Kubernetes
Biar gampang kebayang, bayangin aja restoran cepat saji. Ada koki, ada dapur, ada manajer. Tiap probe punya peran kayak salah satu dari mereka.
Startup probe bertugas meriksa apakah proses inisialisasi aplikasi udah selesai. Beberapa aplikasi butuh waktu lama buat beneran booting. Misalnya yang pakai framework berat kayak Java Spring Boot. Atau backend yang memuat model machine learning dan ngejalanin migrasi database. Bisa puluhan detik sampai menit, lho.
Selama startup probe belum berhasil (Success), Kubernetes menonaktifkan pemeriksaan liveness dan readiness. Tujuannya jelas. Biar aplikasi nggak keburu dibunuh liveness probe sebelum sempat selesai menyala.
Liveness probe jawab satu pertanyaan. Apakah proses aplikasi masih hidup dan sehat? Atau udah ngalami deadlock, alias hang total? Kalau liveness probe gagal (Failed) melebihi batas toleransi (failureThreshold), kubelet langsung membunuh container dan me-restart-nya. Ibaratnya gini. Kalau koki pingsan di dapur, manajer restoran bakal ganti dia dengan koki baru.
Readiness probe jawab pertanyaan yang beda lagi. Apakah aplikasi siap nerima traffic dari pengguna sekarang? Sebuah pod bisa aja masih hidup normal. Tapi sedang nggak mampu memproses request. Contohnya, cache in-memory lokal sedang di-refresh. Atau koneksi pool ke database sedang penuh. Bisa juga aplikasi sedang memproses antrean batch yang berat.
Kalau readiness probe gagal, Kubernetes nggak bakal membunuh pod itu. Kubernetes cuma mencabut pod itu dari daftar endpoint Service alias Load Balancer. Traffic pengguna nggak bakal dialirin ke pod itu sampai probe-nya kembali sukses.
Jebakan Terbesar: Meriksa Database di Liveness Probe
Ini anti-pattern paling berbahaya yang sering ketemu di lapangan:
# CONTOH SALAH BESAR UNTUK LIVENESS PROBE!
@app.get("/healthz")
async def health_check(db: Session = Depends(get_db)):
# JANGAN PERNAH LAKUKAN INI DI LIVENESS PROBE!
await db.execute(text("SELECT 1"))
return {"status": "ok"}
Bayangin kalau database PostgreSQL kalian mendadak kelebihan beban. CPU-nya 100%. Query SELECT 1 ngalami timeout lebih dari 2 detik. Apa yang terjadi kalau endpoint di atas dipasang sebagai liveness probe?
- Liveness probe di Pod 1 timeout. Kubernetes membunuh Pod 1 dan bikin ulang pod baru.
- Liveness probe di Pod 2 timeout. Kubernetes membunuh Pod 2.
- Begitu seterusnya sampai seluruh pod di-restart bersamaan!
- Pod-pod baru langsung membanjiri database dengan connection pool baru. Namanya connection spike. Database pun makin sekarat. ๐
Jadi aturan emasnya gini, nih. Liveness probe cuma periksa status internal aplikasi sendiri. Misal event loop nggak blocking, atau web server masih merespons. Jangan pernah meriksa dependensi eksternal kayak database, Redis, atau service pihak ketiga. Sementara readiness probe justru tempat yang tepat. Di situ kalian bisa memverifikasi kesiapan koneksi database sebelum nerima request bisnis pengguna.
Sebaiknya Pisahkan Endpoint Health Check
Cara paling bersih adalah memisahkan endpoint di aplikasi backend kalian:
from fastapi import FastAPI, status, Response
app = FastAPI()
is_app_ready = False
@app.on_event("startup")
async def startup_event():
# Inisialisasi koneksi, load model, warming cache...
global is_app_ready
await init_database_connection()
is_app_ready = True
# 1. Liveness: Cuma cek apakah FastAPI masih bernapas
@app.get("/healthz", status_code=status.HTTP_200_OK)
async def liveness():
return {"status": "alive"}
# 2. Readiness: Cek apakah dependensi siap menerima traffic
@app.get("/ready")
async def readiness(response: Response):
global is_app_ready
if not is_app_ready or not await check_db_health():
response.status_code = status.HTTP_503_SERVICE_UNAVAILABLE
return {"status": "unavailable"}
return {"status": "ready"}
Konfigurasi Manifest Kubernetes yang Ideal
Berikut contoh konfigurasi Deployment Kubernetes. Isinya ngegabungin ketiga probe secara harmonis. Saya tambahin selector dan label sekalian, biar manifest-nya beneran valid, ya.
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 3
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
containers:
- name: payment-api
image: payment-service:v1.2.0
ports:
- containerPort: 8000
# 1. Startup Probe: Berikan napas lega saat cold start
startupProbe:
httpGet:
path: /healthz
port: 8000
failureThreshold: 30
periodSeconds: 2 # Total waktu tunggu booting: hingga 60 detik
# 2. Liveness Probe: Bunuh container hanya jika hang total
livenessProbe:
httpGet:
path: /healthz
port: 8000
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3 # Toleransi 3x gagal berturut-turut
# 3. Readiness Probe: Cabut traffic jika aplikasi overload / DB putus
readinessProbe:
httpGet:
path: /ready
port: 8000
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
successThreshold: 1 # Langsung alirkan traffic begitu kembali sehat
Perhatiin parameter periodSeconds dan failureThreshold. Jangan pasang timeoutSeconds terlalu agresif, misal 100 ms. Soalnya saat CPU lagi spike sesaat, request probe bisa tertunda. Akhirnya memicu restart yang nggak perlu, alias false-positive restart.
Jadi, Gimana Biar Pod Nggak Mati Nerima Tamu?
Dengan memisahkan peran liveness dan readiness probe secara disiplin, tiga hal ini bakal kalian dapat. Pertama, kita terhindar dari mimpi buruk cascading restart saat infrastruktur database bermasalah. Kedua, pengguna nggak bakal dapat error 502/504. Traffic cuma dikirim ke pod yang beneran siap melayani. Ketiga, proses rolling deployment dan auto-scaling HPA (Horizontal Pod Autoscaler) jalan jauh lebih mulus tanpa downtime.
Sudahkah probe di klaster Kubernetes kalian dikonfigurasi dengan benar hari ini? Yuk, audit manifest kalian sekarang.
Selamat ber-Kubernetes ria, dan semoga pod kalian nggak pernah restart tanpa alasan! ๐