Artikel

Baseline produksi untuk workload Kubernetes

Request, probe, disruption budget, shutdown yang tertib, dan keamanan pod: pengaturan yang seharusnya dimiliki Deployment produksi sebelum insiden pertamanya.

Contoh-contohnya bersifat umum dan ilustratif. Tidak diambil dari lingkungan klien mana pun: sesuaikan ambang batas dan pengaturan dengan sistem Anda sendiri.

Mengapa perlu baseline

Kubernetes menjalankan hampir apa saja dengan hampir tanpa konfigurasi, dan justru di situ masalahnya: nilai bawaannya dipilih untuk memulai, bukan untuk tetap berjalan. Pengaturan di bawah murah ditambahkan di hari pertama dan mahal jika baru ditemukan saat gangguan. Ini berlaku untuk Deployment stateless; workload stateful membutuhkan lebih banyak.

Request dan limit

Scheduler menempatkan pod berdasarkan request-nya, dan Horizontal Pod Autoscaler mengukur pemakaian terhadapnya. Pod tanpa request ditempatkan secara buta dan tidak bisa di-autoscale berdasarkan CPU.

Memori tidak bisa dimampatkan: container yang melampaui limit memorinya akan dihentikan. Tetapkan limit memori sama dengan atau mendekati request, agar pod tidak pernah dijadwalkan pada memori yang tidak bisa dipertahankannya. CPU berbeda — container di atas limit CPU akan di-throttle, yang muncul sebagai latensi. Banyak tim menetapkan request CPU dan meniadakan limit CPU untuk layanan yang sensitif terhadap latensi; apa pun pilihan Anda, ukurlah throttling-nya.

Tiga probe, tiga tugas

  • Readiness menentukan apakah pod menerima lalu lintas. Hati-hati dengan dependensi bersama: jika semua pod gagal readiness bersamaan, layanan tidak punya endpoint sama sekali.
  • Liveness menentukan apakah container di-restart. Batasi pada prosesnya sendiri: jika ia memeriksa basis data, gangguan basis data akan me-restart semua pod sekaligus.
  • Startup menahan probe lain selama aplikasi yang lambat sedang menyala, alih-alih memperpanjang jeda liveness.

Bertahan saat node di-drain dan zona gagal

Upgrade node dan autoscaling terus-menerus mengusir pod. PodDisruptionBudget membatasi berapa replika yang boleh dimatikan sekaligus oleh gangguan sukarela, dan topology spread constraints menempatkan replika di zona berbeda, agar kegagalan satu zona tidak membawa seluruh layanan.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api
spec:
  maxUnavailable: 1
  selector:
    matchLabels: { app: api }

Shutdown yang tertib

Saat pod dihapus, pengeluarannya dari endpoint layanan dan penghentian container-nya (hook preStop, lalu SIGTERM) dimulai bersamaan. Aplikasi yang langsung berhenti akan kehilangan permintaan yang masih diarahkan kepadanya. Tambahkan jeda preStop singkat agar load balancer sempat menyesuaikan, tangani SIGTERM dengan menyelesaikan pekerjaan yang sedang berjalan, dan pastikan terminationGracePeriodSeconds lebih panjang dari jeda ditambah waktu drain.

Security context dan image

Jalankan sebagai pengguna non-root, hapus semua Linux capabilities, blokir eskalasi hak akses, dan mount root filesystem sebagai hanya-baca; Pod Security Standard restricted memberlakukan sebagian besar hal ini per namespace. Rujuk image dengan digest, bukan tag yang bisa berubah, agar yang berjalan persis sama dengan yang diuji.

Menyatukan semuanya

Sebuah Deployment dengan baseline yang sudah diterapkan. Nilainya hanya contoh: tentukan request dari pemakaian yang terukur, bukan dari contoh ini.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels: { app: api }
  template:
    metadata:
      labels: { app: api }
    spec:
      terminationGracePeriodSeconds: 45
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels: { app: api }
      securityContext:
        runAsNonRoot: true
        seccompProfile: { type: RuntimeDefault }
      containers:
        - name: api
          image: registry.example.com/api@sha256:<digest>
          resources:
            requests: { cpu: 250m, memory: 256Mi }
            limits: { memory: 256Mi }
          readinessProbe:
            httpGet: { path: /ready, port: 8080 }
            periodSeconds: 5
          livenessProbe:
            httpGet: { path: /live, port: 8080 }
            periodSeconds: 10
            failureThreshold: 3
          startupProbe:
            httpGet: { path: /live, port: 8080 }
            periodSeconds: 5
            failureThreshold: 30
          lifecycle:
            preStop:
              sleep: { seconds: 5 }   # native sleep action, Kubernetes 1.30+
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities: { drop: ["ALL"] }
Kontak

Butuh pendapat kedua tentang setup Anda?

Kirim deskripsi singkat sistem Anda. Engineer senior membalas secara tertulis dalam satu hari kerja.

Diskusikan infrastruktur Anda