L
Kubernetes & CI/CD • Literally Web ID

Arsitektur Zero-Downtime Deployment Menggunakan Kubernetes dan CI/CD Pipeline

⏱️ 15 menit baca • 📅 15 Oct 2026 • 👁️ 1 views
Arsitektur Zero-Downtime Deployment Menggunakan Kubernetes dan CI/CD Pipeline

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap pengembangan perangkat lunak modern, kebutuhan akan Zero-Downtime Deployment bukan lagi sekadar kemewahan, melainkan keharusan mutlak bagi infrastruktur tingkat enterprise. Sistem e-commerce, perbankan digital, layanan SaaS, dan aplikasi berbasis cloud-native berbeban tinggi dituntut untuk tetap beroperasi 24/7 tanpa adanya gangguan layanan, bahkan saat pembaruan kode atau infrastruktur sedang berjalan. Secara tradisional, pembaruan aplikasi dilakukan dengan menghentikan proses yang sedang berjalan (stop process), memperbarui biner atau direktori rilis, lalu memulai ulang layanan (restart service). Pendekatan ini menghasilkan window of downtime yang, meskipun hanya beberapa detik, dapat menyebabkan kegagalan transaksi, hilangnya pendapatan, dan merusak pengalaman pengguna.

Bottleneck performa dan keamanan yang sering ditemui di dunia nyata meliputi:

  1. Koneksi Database yang Terputus Tiba-tiba: Ketika backend web (Node.js, PHP-FPM, Go) dimatikan secara mendadak saat proses pembaruan, koneksi aktif ke database (MySQL/MariaDB) atau cache (Redis) terputus di tengah jalan (abrupt termination), meninggalkan transaksi dalam status menggantung (orphan connections atau deadlocks).
  2. Ketiadaan Health Check yang Komprehensif: Layanan web server (Nginx/Caddy) meneruskan traffic ke pod atau server yang baru saja menyala sebelum aplikasi benar-benar siap melayani permintaan (misalnya, belum selesai melakukan pemanasan cache (cache warming) atau inisialisasi koneksi kolam (connection pool)).
  3. Konflik Skema Database: Pembaruan kode yang mengasumsikan struktur tabel baru sedangkan instance lama masih berjalan, menyebabkan error SQL syntax atau column not found pada instance lama.

Perbandingan antara kondisi Sebelum dan Sesudah penerapan arsitektur Zero-Downtime Deployment berbasis Kubernetes dan CI/CD:

Aspek Sebelum (Deployment Tradisional / Manual) Sesudah (Kubernetes + CI/CD Otomatis)
Downtime 30 detik hingga 10 menit per rilis 0 detik (Seamless transition)
Metode Rollback Manual, rentan human error, memakan waktu lama Otomatis via ArgoCD / Kubernetes native rollback
Skalabilitas Terbatas pada kapasitas satu atau beberapa VPS Dinamis, otomatis menyesuaikan beban traffic (HPA)
Konsistensi Lingkungan Sering terjadi isu "di laptop saya berjalan, di server error" Terstandarisasi penuh menggunakan container dan Helm

2. Konsep Inti & Deep Dive Arsitektur

Arsitektur Zero-Downtime Deployment mengandalkan orkestrasi kontainer yang cerdas untuk memastikan selalu ada instance aplikasi yang sehat (healthy) dan siap menangani traffic sebelum instance lama dihentikan. Di dalam Kubernetes, mekanisme ini dicapai melalui kombinasi strategi Rolling Update, Liveness, Readiness, and Startup Probes, serta pemisahan Ingress Controller (seperti Nginx Ingress atau Traefik) yang terintegrasi dengan service discovery secara real-time.

Berikut adalah visualisasi alur eksekusi arsitektur Zero-Downtime di dalam klaster Kubernetes:

[ Client / Browser ]
         │
         ▼
┌────────────────────────────────────────┐
│      Cloudflare Edge / CDN / WAF       │
└────────────────────┬───────────────────┘
                     │
                     ▼
┌────────────────────────────────────────┐
│       Kubernetes Ingress Controller    │
└────────────────────┬───────────────────┘
                     │
         ┌───────────┴───────────┐
         ▼                       ▼
┌───────────────────┐   ┌───────────────────┐
│ Pod A (v1 - Active)│   │ Pod B (v2 - New)  │
│ (Ready & Serving) │   │ (Readiness Probe) │
└───────────────────┘   └───────────────────┘
         │                       │
         └───────────┬───────────┘
                     │
                     ▼
┌────────────────────────────────────────┐
│         Database & Redis Cluster       │
└────────────────────────────────────────┘

Alur kerja transisi saat deployment baru (v2) digulirkan:

  1. CI/CD Pipeline (GitLab Runner) memicu build citra Docker baru, mendorongnya ke container registry, lalu memperbarui tag citra pada repositori Git konfigurasi (GitOps).
  2. ArgoCD mendeteksi perubahan pada repositori Git dan menyinkronkan manifes Kubernetes ke klaster.
  3. Kubernetes Deployment membuat pod baru versi v2. Pada saat ini, pod v2 menjalankan Startup Probe untuk memastikan proses inisialisasi aplikasi selesai.
  4. Setelah Startup Probe lolos, Kubernetes menjalankan Readiness Probe. Pod v2 belum dimasukkan ke dalam daftar endpoint Service sampai Readiness Probe mengembalikan status HTTP 200 OK secara konsisten.
  5. Setelah pod v2 dinyatakan Ready, Kubernetes mulai mengarahkah traffic baru ke pod v2, sementara pod v1 mulai menerima sinyal SIGTERM untuk menghentikan proses secara anggun (graceful shutdown).
  6. Pod v1 memproses sisa koneksi aktif (drain connections), menutup koneksi database dengan aman, lalu terminasi pod selesai.

3. Perbandingan Komparatif / Analisis Pendekatan

Dalam membangun sistem tanpa henti, terdapat tiga pendekatan utama yang sering dipertimbangkan oleh arsitek infrastruktur:

Parameter Perbandingan Rolling Update Blue-Green Deployment Canary Deployment
Konsumsi Sumber Daya Rendah (Hanya butuh ekstra 25-50% kapasitas) Tinggi (Butuh 2x lipat kapasitas infrastruktur) Rendah hingga Sedang
Kompleksitas Konfigurasi Rendah (Bawaan Kubernetes) Sedang (Membutuhkan modifikasi Service/Router) Tinggi (Butuh traffic shaping / Service Mesh)
Kecepatan Rollback Cepat (Kubernetes native) Sangat Cepat (Alihkan router ke environment lama) Cepat (Kurangi bobot traffic canary)
Risiko Dampak Bug Menyeluruh secara bertahap ke semua pengguna Rendah (Jika hijau gagal, biru tetap aman) Sangat Rendah (Hanya berdampak pada x% pengguna)
Latensi Jaringan Minimal Minimal Membutuhkan extra hop / proxy cerdas

[!TIP]
Untuk aplikasi enterprise skala menengah ke atas dengan optimasi biaya infrastruktur yang ketat, Rolling Update dengan parameter maxSurge: 1 dan maxUnavailable: 0 adalah pilihan paling seimbang dan efisien dari segi penggunaan RAM dan CPU.


4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum mengimplementasikan pipeline dan konfigurasi Kubernetes, pastikan lingkungan Anda memenuhi spesifikasi berikut:

  • Klaster Kubernetes: Versi 1.25 atau yang lebih baru.
  • Tooling CLI yang Diperlukan: kubectl, helm, argocd, dan git terpasang pada mesin administrator atau runner.
  • Domain & DNS: Domain aktif yang terhubung ke Cloudflare.
  • Storage & Database: Akses ke Managed Database (MySQL/MariaDB) dan Redis untuk manajemen sesi dan antrean.
  • Hak Akses (RBAC): Akun service account dengan hak akses cluster-admin untuk GitLab Runner dan ArgoCD.

Verifikasi kesiapan klaster dengan perintah berikut:

kubectl cluster-info
kubectl get nodes -o wide

5. Panduan Implementasi Langkah demi Langkah

Langkah 1: Konfigurasi Helm Chart untuk Aplikasi Web Enterprise

Buat struktur direktori Helm chart Anda dengan file values.yaml dan templat Kubernetes yang mendukung rolling update secara presisi.

# charts/enterprise-app/values.yaml
replicaCount: 3

image:
  repository: registry.enterprise.internal/core/webapp
  tag: "v1.0.0"
  pullPolicy: IfNotPresent

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

service:
  type: ClusterIP
  port: 80
  targetPort: 8080

ingress:
  enabled: true
  className: "nginx"
  annotations:
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  hosts:
    - host: app.enterprise.com
      paths:
        - path: /
          pathType: Prefix

resources:
  limits:
    cpu: "1"
    memory: 1024Mi
  requests:
    cpu: "200m"
    memory: 256Mi

probes:
  livenessProbe:
    httpGet:
      path: /healthz
      port: 8080
    initialDelaySeconds: 15
    periodSeconds: 10
    failureThreshold: 3
  readinessProbe:
    httpGet:
      path: /ready
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    failureThreshold: 3

Berikut adalah file template Deployment utama (charts/enterprise-app/templates/deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "enterprise-app.fullname" . }}
  labels:
    {{- include "enterprise-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  strategy:
    type: {{ .Values.strategy.type }}
    rollingUpdate:
      maxSurge: {{ .Values.strategy.rollingUpdate.maxSurge }}
      maxUnavailable: {{ .Values.strategy.rollingUpdate.maxUnavailable }}
  selector:
    matchLabels:
      {{- include "enterprise-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "enterprise-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.targetPort }}
              name: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          livenessProbe:
            httpGet:
              path: {{ .Values.probes.livenessProbe.httpGet.path }}
              port: {{ .Values.probes.livenessProbe.httpGet.port }}
            initialDelaySeconds: {{ .Values.probes.livenessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.probes.livenessProbe.periodSeconds }}
            failureThreshold: {{ .Values.probes.livenessProbe.failureThreshold }}
          readinessProbe:
            httpGet:
              path: {{ .Values.probes.readinessProbe.httpGet.path }}
              port: {{ .Values.probes.readinessProbe.httpGet.port }}
            initialDelaySeconds: {{ .Values.probes.readinessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.probes.readinessProbe.periodSeconds }}
            successThreshold: {{ .Values.probes.readinessProbe.successThreshold }}
            failureThreshold: {{ .Values.probes.readinessProbe.failureThreshold }}
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 10"]

Langkah 2: Konfigurasi Pipeline CI/CD dengan GitLab Runner

Buat file .gitlab-ci.yml di akar repositori aplikasi untuk melakukan otomatisasi build dan pembaruan tag pada repositori GitOps.

stages:
  - build
  - gitops-update

variables:
  CONTAINER_IMAGE: registry.enterprise.internal/core/webapp
  GITOPS_REPO: git@gitlab.com:enterprise/gitops-infra.git

build_image:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $CONTAINER_IMAGE:$CI_COMMIT_SHA -t $CONTAINER_IMAGE:latest .
    - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA
    - docker push $CONTAINER_IMAGE:latest
  only:
    - main

update_gitops:
  stage: gitops-update
  image: alpine/git:v2.40.1
  before_script:
    - eval $(ssh-agent -s)
    - echo "$GITOPS_SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
  script:
    - git config --global user.name "GitLab CI/CD Bot"
    - git config --global user.email "ci-bot@enterprise.com"
    - git clone $GITOPS_REPO
    - cd gitops-infra
    - sed -i "s/tag: .*/tag: \"$CI_COMMIT_SHA\"/g" apps/webapp/values.yaml
    - git commit -am "chore(webapp): update image tag to $CI_COMMIT_SHA"
    - git push origin main
  only:
    - main

Langkah 3: Konfigurasi ArgoCD Application

Terapkan manifes ArgoCD untuk memantau repositori GitOps dan menyinkronkan perubahan ke klaster Kubernetes secara otomatis.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: enterprise-webapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: 'git@gitlab.com:enterprise/gitops-infra.git'
    targetRevision: HEAD
    path: apps/webapp
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=true

Terapkan manifes ArgoCD ke klaster:

kubectl apply -f argocd-app.yaml

6. Bedah Kode & Penjelasan Detail Baris Kunci

  • maxSurge: 1 dan maxUnavailable: 0: Kombinasi ini sangat krusial. maxSurge: 1 mengizinkan Kubernetes membuat 1 pod tambahan di atas kapasitas normal selama proses rolling update. maxUnavailable: 0 melarang Kubernetes mematikan pod lama sebelum pod baru benar-benar siap. Hal ini menjamin kapasitas layanan tidak pernah berkurang 1% pun selama rilis.
  • lifecycle.preStop dengan sleep 10: Perintah ini memberikan jeda waktu 10 detik sebelum Kubernetes mengirimkan sinyal SIGTERM ke kontainer. Jeda ini sangat penting agar Nginx Ingress Controller memiliki waktu yang cukup untuk memperbarui daftar endpoint (deregister endpoint) dari daftar load balancer internal sebelum aplikasi berhenti menerima permintaan.
  • readinessProbe vs livenessProbe: livenessProbe mendeteksi apakah aplikasi mengalami kebuntuan (deadlock) dan perlu di-restart. Sebaliknya, readinessProbe menentukan apakah aplikasi sudah siap menerima traffic dari luar. Jika readiness gagal, pod tidak di-restart, melainkan hanya dikeluarkan dari rotasi load balancer.

7. Skenario Produksi & Studi Kasus Dunia Nyata

Bayangkan sebuah platform e-commerce dengan traffic puncak mencapai 50.000 requests per second (RPS) saat kampanye belanja bulanan. Tim teknik perlu merilis perbaikan bug kritis di tengah lonjakan traffic tersebut tanpa mengganggu transaksi pembayaran.

Langkah Mitigasi Operasional:

  1. Konfigurasi Horizontal Pod Autoscaler (HPA) diatur agar skala minimum pod adalah 10 dan maksimum 50 berdasarkan utilisasi CPU 70%.
  2. Sebelum rilis dilakukan, tim menjalankan pemanasan cache (cache warming) pada Redis melalui job Kubernetes terpisah.
  3. Saat pipeline CI/CD memicu pembaruan citra, ArgoCD melakukan rolling update secara perlahan (maxSurge: 2).
  4. Karena maxUnavailable: 0 diterapkan, kapasitas selalu berada di atas 10 pod aktif. Ingress Controller secara mulus membagi beban antara pod versi lama dan pod versi baru tanpa lonjakan latensi (latency spike) yang signifikan pada metrik Prometheus/Grafana.

8. Common Pitfalls, Anti-Patterns & Solusi

  1. Anti-Pattern: Tidak Menggunakan preStop Hook.

    • Dampak: Terjadi lonjakan error HTTP 502 Bad Gateway sesaat setelah deployment dimulai karena pod lama langsung dimatikan sementara Ingress masih mengirimkan paket data ke IP pod tersebut.
    • Solusi: Selalu tambahkan preStop hook dengan jeda waktu minimal 5 hingga 10 detik.
  2. Anti-Pattern: livenessProbe Terlalu Agresif.

    • Dampak: Aplikasi mengalami lonjakan penggunaan memori sesaat akibat Garbage Collection, namun livenessProbe langsung menganggap aplikasi mati dan melakukan restart beruntun (crash loop backoff).
    • Solusi: Atur initialDelaySeconds yang memadai dan tetapkan failureThreshold minimal 3.
  3. Anti-Pattern: Migrasi Skema Database yang Merusak Kompatibilitas Belakang (Backward Incompatible Migration).

    • Dampak: Kolom database dihapus pada migrasi, padahal instance aplikasi versi lama yang masih berjalan masih membutuhkan kolom tersebut.
    • Solusi: Gunakan pola Expand and Contract (perluas dulu skema, deploy aplikasi baru, lalu hapus kolom lama pada rilis berikutnya).

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk memvalidasi bahwa arsitektur Zero-Downtime berjalan sempurna tanpa gangguan koneksi, lakukan pengujian beban menggunakan k6 secara bersamaan saat deployment berlangsung.

Buat skrip pengujian beban load-test.js:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 500 },
    { duration: '5m', target: 500 },
    { duration: '2m', target: 0 },
  ],
};

export default function () {
  const res = http.get('https://app.enterprise.com/healthz');
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 200ms': (r) => r.timings.duration < 200,
  });
  sleep(0.1);
}

Jalankan pengujian di terminal:

k6 run load-test.js

Interpretasi Hasil & Tuning Lanjutan:

  • Pastikan metrik http_req_failed bernilai 0.00% selama proses deployment berlangsung.
  • Jika ditemukan lonjakan latensi, tingkatkan parameter alokasi sumber daya CPU/Memory pada file values.yaml atau sesuaikan parameter kernel sysctl pada node pekerja klaster Kubernetes (net.core.somaxconn dan net.ipv4.tcp_tw_reuse).

10. Checklist Penerapan Produksi & Kesimpulan

Sebelum meluncurkan arsitektur Zero-Downtime Deployment ke lingkungan produksi klaster enterprise Anda, pastikan seluruh item dalam checklist berikut telah terpenuhi:

  • Konfigurasi strategy.type diset ke RollingUpdate dengan maxUnavailable: 0.
  • LivenessProbe, ReadinessProbe, dan StartupProbe telah didefinisikan dengan parameter waktu yang akurat.
  • Hook preStop terpasang untuk memastikan graceful shutdown koneksi jaringan.
  • GitLab Runner dan ArgoCD terintegrasi melalui protokol SSH yang aman dan kredensial terenkripsi.
  • Uji beban (load testing) bersamaan dengan deployment telah diverifikasi menghasilkan tingkat kegagalan 0% (http_req_failed == 0).
  • Strategi migrasi database menggunakan pola Expand and Contract.

Dengan menerapkan seluruh kerangka kerja, konfigurasi file manifes, dan otomatisasi CI/CD di atas, organisasi Anda kini memiliki fondasi infrastruktur web modern yang tangguh, andal, dan siap menghadapi skala enterprise tanpa pernah mengalami downtime sedetik pun.

🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server