Kodeloka
  1. Kodeloka
  2. Kelas Microservices
  3. Materi

Infrastructure · Modul 24 dari 24

Service Mesh & Deployment ke Kubernetes

Memindahkan urusan jaringan dari kode ke infrastruktur dengan sidecar proxy, mTLS otomatis, traffic splitting, serta pola deployment canary dan blue-green.

1. Masalah yang Diselesaikan Service Mesh

Pola ketahanan di modul sebelumnya — retry, timeout, circuit breaker — harus diterapkan di setiap layanan. Bila layanan Anda ditulis dalam Go, Java, Python, dan Node.js, Anda menulis dan memelihara logika yang sama empat kali, dengan perilaku yang tidak pernah benar-benar sama.

TANPA mesh:                    DENGAN mesh:
┌─────────────┐               ┌─────────────┐
│ Aplikasi    │               │ Aplikasi    │  ← hanya logika bisnis
│ + retry     │               ├─────────────┤
│ + timeout   │               │ Sidecar     │  ← retry, timeout, mTLS,
│ + mTLS      │               │ Proxy       │    circuit breaker, metrik
│ + metrik    │               └─────────────┘
└─────────────┘
Ditulis ulang di tiap bahasa  Satu konfigurasi untuk semua bahasa

2. Data Plane dan Control Plane

  • Data plane — kumpulan sidecar proxy yang benar-benar meneruskan lalu lintas. Semua paket melewatinya.
  • Control plane — otak yang menyebarkan konfigurasi, sertifikat, dan kebijakan ke seluruh proxy.
💡 Yang Anda dapatkan tanpa mengubah satu baris kode aplikasi
  • mTLS otomatis antar layanan, lengkap dengan rotasi sertifikat.
  • Retry, timeout, circuit breaker yang seragam lintas bahasa.
  • Traffic splitting berbasis persentase atau header — fondasi canary.
  • Metrik emas otomatis: rate, error, duration untuk setiap pasangan layanan.
  • Kebijakan otorisasi: "hanya Layanan Pesanan yang boleh memanggil Layanan Pembayaran".
  • Injeksi kesalahan untuk chaos engineering, tanpa menyentuh kode.

3. Harga yang Harus Dibayar

🚫 Service mesh bukan keputusan ringan
  • Latensi bertambah — setiap panggilan melewati dua proxy tambahan.
  • Sumber daya bertambah — satu sidecar per pod berarti tambahan CPU dan memori dikalikan jumlah pod.
  • Debugging jadi lebih sulit — kini ada lapisan tambahan yang bisa menjadi penyebab masalah.
  • Kurva belajar curam — model konfigurasinya sendiri sudah merupakan bidang keahlian tersendiri.
  • Beban upgrade — memutakhirkan mesh di kluster produksi adalah operasi yang menegangkan.

Untuk di bawah 10 layanan, mesh hampir selalu berlebihan. Pustaka ketahanan di dalam aplikasi sudah cukup. Pertimbangkan mesh ketika jumlah layanan sudah puluhan dan ditulis dalam banyak bahasa berbeda, atau ketika mTLS antar layanan menjadi kewajiban kepatuhan.

4. Fondasi Kubernetes untuk Microservices

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: layanan-pesanan
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0        # jangan pernah turun di bawah kapasitas
  template:
    spec:
      containers:
        - name: pesanan
          image: registry.internal/pesanan:2.4.0   # JANGAN pakai :latest
          ports:
            - containerPort: 8080

          resources:
            requests:                # dipakai penjadwal untuk menempatkan pod
              cpu: 100m
              memory: 128Mi
            limits:                  # batas keras
              memory: 512Mi
              # CPU limit sengaja TIDAK disetel -- lihat catatan di bawah

          livenessProbe:             # "haruskah pod ini dibunuh & diganti?"
            httpGet: { path: /healthz, port: 8080 }
            initialDelaySeconds: 10
            periodSeconds: 10
            failureThreshold: 3

          readinessProbe:            # "bolehkah pod ini menerima trafik?"
            httpGet: { path: /readyz, port: 8080 }
            periodSeconds: 5

          startupProbe:              # untuk aplikasi yang lambat menyala
            httpGet: { path: /healthz, port: 8080 }
            failureThreshold: 30
            periodSeconds: 5
⚠️ Liveness dan readiness sering disalahpahami

Liveness menjawab "apakah proses ini rusak dan perlu dibunuh?". Readiness menjawab "apakah pod ini siap menerima trafik sekarang?".

Kesalahan yang sangat merusak: menjadikan liveness probe memeriksa dependensi eksternal seperti database. Ketika database sedang lambat, seluruh pod gagal liveness dan Kubernetes membunuh semuanya sekaligus — mengubah gangguan kecil menjadi pemadaman total. Liveness hanya boleh memeriksa proses itu sendiri. Ketergantungan eksternal diperiksa oleh readiness, yang cukup menghentikan trafik tanpa membunuh pod.

📌 Soal CPU limit

Menyetel limits.cpu menyebabkan CFS throttling: kontainer dipaksa berhenti meski node masih punya CPU menganggur, sehingga latensi p99 melonjak. Praktik yang banyak dianut sekarang: selalu setel memory limit (karena memori tidak bisa dikompres — kehabisan berarti OOM kill), tetapi hanya setel CPU request tanpa limit, dan andalkan request untuk pembagian yang adil.

5. Mematikan Pod dengan Anggun

Kubernetes menghapus pod:
1. Pod ditandai Terminating, dikeluarkan dari daftar endpoint Service
2. Hook preStop dijalankan (bila ada)
3. Sinyal SIGTERM dikirim ke proses
4. Menunggu terminationGracePeriodSeconds (default 30 detik)
5. SIGKILL -- dipaksa mati
lifecycle:
  preStop:
    exec:
      command: ["sleep", "5"]     # beri waktu load balancer menyadari
terminationGracePeriodSeconds: 45
⚠️ Ada jendela balapan yang menyebabkan error 502

Penghapusan endpoint dan pengiriman SIGTERM terjadi hampir bersamaan. Bila aplikasi langsung berhenti menerima koneksi, permintaan yang sudah terlanjur diarahkan ke pod itu akan gagal. Jeda preStop beberapa detik memberi waktu agar semua load balancer memperbarui daftar endpoint sebelum aplikasi benar-benar berhenti. Aplikasi juga harus menangani SIGTERM: berhenti menerima koneksi baru, selesaikan yang sedang berjalan, lalu keluar.

6. Strategi Rilis

StrategiCara kerjaPertimbangan
Rolling updateGanti pod bertahapBawaan Kubernetes; dua versi berjalan bersamaan
Blue-greenSiapkan lingkungan baru utuh, alihkan trafik sekaligusMundur seketika; butuh sumber daya dua kali lipat
CanaryAlihkan 5% trafik, amati, lalu naikkan bertahapPaling aman; perlu metrik yang baik untuk menilai
ShadowGandakan trafik ke versi baru, responsnya dibuangNol risiko bagi pengguna; hati-hati efek samping ganda
Canary lewat traffic splitting service mesh
rute:
  - tujuan: layanan-pesanan
    subset: v2.4.0
    bobot: 5           # 5% ke versi baru
  - tujuan: layanan-pesanan
    subset: v2.3.0
    bobot: 95

# Naikkan bertahap: 5% -> 25% -> 50% -> 100%
# Pada tiap tahap, bandingkan tingkat error & latensi p99
# antara kedua subset. Bila memburuk, kembalikan ke 0%.
🚫 Dua versi berjalan bersamaan adalah keadaan normal

Pada rolling update maupun canary, versi lama dan baru selalu berjalan bersamaan untuk sementara. Konsekuensinya wajib dipikirkan: perubahan skema database harus kompatibel ke belakang (tambah kolom dulu, isi datanya, baru pakai — jangan pernah menghapus kolom di rilis yang sama); format pesan di broker harus bisa dibaca kedua versi; dan API tidak boleh menghapus field yang masih dipakai versi lama.

7. Menjaga Ketersediaan Saat Pemeliharaan Kluster

PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: pdb-pesanan
spec:
  minAvailable: 2          # atau: maxUnavailable: 1
  selector:
    matchLabels:
      app: layanan-pesanan

Tanpa PDB, satu perintah kubectl drain saat memutakhirkan node bisa mengusir semua replika sekaligus dan mematikan layanan Anda. PDB memberi tahu Kubernetes berapa banyak pod yang wajib tetap hidup selama gangguan terencana.

Sebar pod ke node & zona berbeda
topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: layanan-pesanan

Tiga replika yang kebetulan dijadwalkan di satu node yang sama tidak memberi ketersediaan apa pun. Aturan penyebaran memastikan replika tersebar ke node dan zona yang berbeda.