Gejala dan Deteksi Observability

Saat proses rolling deployment berjalan, Ingress Controller mendadak mencatat lonjakan HTTP 503 Service Unavailable atau 502 Bad Gateway. Lonjakan ini terjadi bersamaan dengan transisi Pod lama ke status Terminating.

Anomali ini sering mengecoh tim pengembang karena metrik aplikasi tidak mencatat galat tersebut. Metrik Micrometer (http_server_requests_seconds_count) pada Spring Boot menunjukkan respons 200 OK normal. Alasannya: trafik yang gagal belum sempat mencapai servlet container (Tomcat) aplikasi tujuan.

Kueri PromQL untuk mendeteksi disparitas trafik Ingress vs aplikasi:

# Deteksi HTTP 5xx pada NGINX Ingress per Service
sum(rate(nginx_ingress_controller_requests{status=~"50[23]", exported_service="account-service"}[1m])) 
/
sum(rate(nginx_ingress_controller_requests{exported_service="account-service"}[1m])) * 100

# Deteksi request sukses di level Micrometer
sum(rate(http_server_requests_seconds_count{status="200", app="account-service"}[1m]))

Jika metrik Ingress mencatat lonjakan 5xx sedangkan Micrometer tidak merekam error 5xx sama sekali, koneksi terputus di lapisan TCP sebelum request diproses aplikasi.

Tindakan Darurat: Mitigasi Cepat

Hentikan degradasi trafik segera dengan membatalkan deployment aktif ke versi stabil sebelumnya.

kubectl rollout undo deployment/account-service -n production
kubectl rollout status deployment/account-service -n production

Perintah ini membatalkan pergantian Pod baru dan mempertahankan Pod lama yang masih beroperasi normal, menghentikan terminasi massal yang memicu kegagalan routing.

Root Cause: Race Condition Kube-Proxy dan Pod Lifecycle

Masalah bersumber dari sifat asinkron pada siklus terminasi Pod di Kubernetes. Ketika Deployment di-update:

  1. API Server mengubah status Pod target menjadi Terminating.
  2. Pod dihapus dari daftar Endpoints / EndpointSlice service terkait.
  3. Kube-proxy di setiap node dan Ingress Controller memperbarui aturan iptables/IPVS atau tabel upstream secara asinkron.
  4. Secara simultan, Kubelet mengirim sinyal SIGTERM langsung ke container Spring Boot.

Propagasi pembaruan endpoint ke seluruh node dan Ingress membutuhkan jeda waktu antara 2 hingga 10 detik. Jika aplikasi Spring Boot langsung merespons sinyal SIGTERM dengan menutup socket HTTP Tomcat, Ingress yang masih memiliki referensi endpoint lama akan tetap mengirimkan trafik baru. Hasilnya adalah TCP connection refused atau TCP RST yang diterjemahkan Ingress sebagai HTTP 502/503.

Tindakan Pencegahan: Konfigurasi Graceful Shutdown & PreStop Hook

Penyelesaian masalah ini membutuhkan sinkronisasi antara layer Kubernetes lifecycle dan layer runtime Spring Boot.

1. Konfigurasi Spring Boot

Aktifkan graceful shutdown pada application.yml agar Tomcat menolak koneksi baru secara tertib dan menunggu in-flight request selesai sebelum proses mati.

server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

2. Konfigurasi Manifest Kubernetes

Tambahkan preStop hook berupa perintah sleep pada container spec dan perpanjang terminationGracePeriodSeconds.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: account-service
  namespace: production
spec:
  replicas: 3
  template:
    spec:
      terminationGracePeriodSeconds: 45
      containers:
      - name: account-service
        image: account-service:v1.2.0
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 15"]
        ports:
        - containerPort: 8080
Kalkulasi Waktu: Jeda sleep 15 detik pada preStop memberi waktu bagi Kube-proxy dan Ingress Controller untuk menghapus IP Pod dari upstream routing sebelum Spring Boot menerima SIGTERM. Nilai terminationGracePeriodSeconds harus lebih besar dari durasi sleep ditambah timeout-per-shutdown-phase (15s + 30s = 45s) agar proses tidak dimatikan paksa via SIGKILL.

Template Postmortem Ringkas

Gunakan format berikut untuk dokumentasi pascainsiden:

Ringkasan Insiden

  • Layanan Terdampak: Account Service
  • Durasi: 10:14 WIB - 10:22 WIB (8 Menit)
  • Dampak: 1.420 request gagal dengan kode respons HTTP 503 saat rolling update v1.1.9 ke v1.2.0.

Timeline Kejadian

  • 10:14 WIB: Eksekusi rolling deployment v1.2.0 via CI/CD pipeline.
  • 10:15 WIB: Alert PagerDuty berbunyi: Ingress HTTP 5xx Rate > 2%.
  • 10:17 WIB: Tim SRE mengidentifikasi status Pod Terminating bersamaan dengan lonjakan 503 di ingress log.
  • 10:18 WIB: Eksekusi kubectl rollout undo deployment/account-service.
  • 10:22 WIB: Rollback selesai, trafik kembali normal (error rate < 0.01%).

Akar Masalah (Root Cause)

Tomcat mematikan listener port HTTP seketika setelah menerima SIGTERM, mendahului proses deregistrasi IP Pod dari routing table Ingress Controller. Trafik yang masuk pada jendela propagasi 5-10 detik mengalami kegagalan koneksi TCP.

Rencana Tindakan (Action Items)

  1. Terapkan server.shutdown=graceful dan timeout-per-shutdown-phase=30s di seluruh base configuration Spring Boot.
  2. Pasang preStop: exec: command: ["/bin/sh", "-c", "sleep 15"] pada helm chart/manifest deployment.
  3. Uji ulang deployment pada environment staging menggunakan skenario load testing konstan untuk verifikasi eliminasi HTTP 503.