Penyebab CrashLoopBackOff pada Bootstrap Nuxt 3

Status CrashLoopBackOff pada Kubernetes menunjukkan bahwa container Nuxt 3 gagal mempertahankan siklus hidup prosesnya sesaat setelah dimulai. Kubelet mencoba merestart container secara berulang dengan jeda eksponensial (back-off delay) karena proses Node.js langsung keluar (exit) dengan kode non-zero.

Pada arsitektur Nuxt 3 yang berjalan di atas engine Nitro, insiden startup crash umumnya bersumber dari dua faktor utama:

  • Fatal Exception pada Server Plugin: Berkas di dalam direktori server/plugins/ dieksekusi tepat saat Nitro engine diinisialisasi. Jika terdapat asynchronous task tanpa error handling yang memadai (misalnya inisialisasi koneksi database atau Redis client yang gagal tersambung), Promise rejection yang tidak tertangani akan memicu process.exit(1).
  • Ketidakcocokan Nilai runtimeConfig: Akses ke variabel environment kritis yang tidak terdefinisi (undefined) saat proses bootstrap. Kesalahan ketik nama variabel atau absennya secret di ConfigMap/Secret Kubernetes menyebabkan pemanggilan method pada objek null (contoh: config.apiSecret.trim()) yang langsung menghentikan runtime sebelum server HTTP Nitro sempat membuka port listening.

Diagnostik dan Observability Container

Sebelum mengambil tindakan, identifikasi akar masalah melalui diagnostik terarah pada workload Kubernetes.

1. Periksa State dan Exit Code

Jalankan perintah berikut untuk memeriksa status detail pod yang mengalami kegagalan:

kubectl describe pod <pod-name> -n <namespace>

Fokuskan audit pada blok Last State di bagian Containers:

  • Exit Code 1: Terjadi fatal JavaScript error atau uncaught exception yang menghentikan proses Node.js.
  • Exit Code 137: Container dihentikan paksa oleh Linux OOM-Killer (Out of Memory) atau menerima sinyal SIGKILL karena melampaui batas memory limit pod.
  • Exit Code 143: Container menerima sinyal SIGTERM, sering kali disebabkan oleh kegagalan liveness probe yang memicu kubelet mematikan container.

2. Audit Log Container Sebelum Restart

Gunakan flag --previous untuk membaca output log dari instance container yang mati sebelum restart terakhir:

kubectl logs <pod-name> --previous --container=<container-name>

Periksa baris terakhir output log. Jika crash terjadi akibat plugin Nitro, stack trace error Node.js akan tercetak jelas sebelum sinyal pemutusan diterima.

Implementasi Health Probe pada Nitro Engine

Menggunakan satu endpoint root (/) untuk probe Kubernetes pada aplikasi Nuxt SSR adalah kesalahan umum. Pemanggilan halaman root memicu kompilasi template SSR, rendering komponen Vue, dan data fetching upstream yang memperlambat respons dan menghasilkan false positive. Pisahkan probe menjadi Liveness dan Readiness menggunakan handler Nitro.

1. Endpoint Liveness (/api/healthz)

Liveness probe memastikan event loop Node.js berjalan dan proses Nitro responsif. Endpoint ini harus mengeksekusi operasi seringan mungkin tanpa dependensi eksternal.

// server/api/healthz.get.ts
export default defineEventHandler(() => {
  return {
    status: 'ok',
    uptime: process.uptime(),
    timestamp: Date.now()
  }
})

2. Endpoint Readiness (/api/readyz)

Readiness probe memastikan aplikasi siap menerima traffic publik. Jika backend upstream atau database cache belum terhubung, endpoint ini harus mengembalikan HTTP status 503 agar kubelet menghapus pod dari daftar endpoint Service tanpa merestart pod.

// server/api/readyz.get.ts
export default defineEventHandler((event) => {
  // Evaluasi dependensi kritis (contoh: status koneksi service internal)
  const isDependenciesReady = checkInternalDependencies()

  if (!isDependenciesReady) {
    setResponseStatus(event, 503)
    return { status: 'unready', reason: 'Internal dependencies not initialized' }
  }

  return { status: 'ready' }
})

function checkInternalDependencies(): boolean {
  // ponytail: validasi koneksi lokal; naikkan ke health check pool saat multi-db
  return true
}

3. Konfigurasi Probe Manifest Kubernetes

Petakan kedua endpoint tersebut pada manifest deployment:

spec:
  containers:
    - name: nuxt-app
      image: registry.example.com/nuxt-app:v1.2.0
      ports:
        - containerPort: 3000
      livenessProbe:
        httpGet:
          path: /api/healthz
          port: 3000
        initialDelaySeconds: 10
        periodSeconds: 10
        timeoutSeconds: 2
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: /api/readyz
          port: 3000
        initialDelaySeconds: 15
        periodSeconds: 5
        timeoutSeconds: 2
        failureThreshold: 2
Catatan: Berikan initialDelaySeconds yang memadai pada readinessProbe untuk memberikan waktu bagi Nitro engine melakukan bootstrap cold-start sebelum dievaluasi oleh kubelet.

Prosedur Fast Rollback dan Verifikasi Traffic

Saat CrashLoopBackOff terjadi di production setelah deployment baru, prioritas utama adalah mitigasi instan, bukan melakukan debugging langsung di cluster aktif.

1. Eksekusi Rollback Deployment

Batalkan revisi deployment yang gagal dan kembalikan pods ke versi stabil sebelumnya:

kubectl rollout undo deployment/nuxt-app -n <namespace>

2. Pantau Transisi Rollback

Pantau progress pengembalian replica set:

kubectl rollout status deployment/nuxt-app -n <namespace>

3. Verifikasi Pemulihan Traffic

Setelah rollback selesai, validasi bahwa traffic telah pulih dan tidak ada error HTTP 502/503 dari Ingress Controller:

kubectl get pods -l app=nuxt-app -n <namespace> -o wide
curl -I https://app.example.com/api/healthz

Pastikan semua pod baru berada dalam status Running dan kolom READY bernilai penuh (misalnya 1/1).

Pencegahan dan Postmortem: Validasi Pre-flight Env dengan Zod

Sebagian besar insiden bootstrap crash disebabkan oleh absennya environment variable yang dibutuhkan di runtime. Pencegahan permanen dilakukan dengan menerapkan prinsip fail-fast terstruktur: validasi seluruh konfigurasi lingkungan secara ketat sebelum Nitro mulai menangani request.

Implementasi Server Plugin Pre-flight

Gunakan Zod untuk mendefinisikan skema variabel runtime di dalam server plugin Nuxt 3:

// server/plugins/00.env-validator.ts
import { z } from 'zod'

const envSchema = z.object({
  DATABASE_URL: z.string().url(),
  API_SECRET_KEY: z.string().min(32),
  REDIS_HOST: z.string().default('127.0.0.1'),
  NODE_ENV: z.enum(['development', 'production', 'test']).default('production')
})

export default defineNitroPlugin(() => {
  const parseResult = envSchema.safeParse(process.env)

  if (!parseResult.success) {
    const errorDetails = JSON.stringify(parseResult.error.format(), null, 2)
    console.error('CRITICAL: Environment validation failed during bootstrap:')
    console.error(errorDetails)

    // Hentikan proses secara terukur dengan pesan log yang presisi
    process.exit(1)
  }

  console.info('Environment schema validated successfully.')
})

Dengan plugin ini, jika konfigurasi invalid, container akan tetap exit, namun log yang ditinggalkan pada kubectl logs --previous langsung mengidentifikasi field spesifik yang hilang atau salah tipe data, mengeliminasi proses debugging berbasis trial-and-error.

Template Postmortem Tindakan Korektif

Dokumentasikan temuan insiden menggunakan struktur perbaikan berikut:

  • Root Cause: Variabel API_SECRET_KEY hilang pada Secret Kubernetes rilis v1.2.0, menyebabkan null-pointer exception pada server/plugins/api-client.ts.
  • Trigger: Pipeline CI/CD men-deploy image baru tanpa memvalidasi keberadaan Secret baru di cluster target.
  • Detection: Liveness probe gagal beruntun; pod memasuki status CrashLoopBackOff dalam waktu 45 detik setelah deployment dimulai.
  • Action Items: Pasang plugin validasi Zod untuk fail-fast log terstruktur, dan tambahkan step validasi manifest Helm/Kustomize di pipeline CI sebelum perintah rollout dieksekusi.