Init Container #

Init container adalah container khusus yang berjalan sebelum container utama dalam Pod dimulai. Ia harus selesai dengan sukses sebelum container berikutnya dijalankan — menjadikannya mekanisme yang tepat untuk semua pekerjaan persiapan yang harus selesai sebelum aplikasi bisa berjalan. Memahami kapan dan bagaimana menggunakan init container menghindarkan banyak race condition dan masalah startup yang umum terjadi.

Cara Kerja Init Container #

Urutan eksekusi dalam Pod dengan init container sangat deterministik:

Urutan eksekusi Pod:

  Init Container 1
      │ (harus exit 0)
      ▼
  Init Container 2
      │ (harus exit 0)
      ▼
  Init Container 3
      │ (harus exit 0)
      ▼
  Container Utama 1 ─┐
  Container Utama 2 ─┤ (berjalan bersamaan)
  Container Utama 3 ─┘

Beberapa karakteristik penting init container:

  • Berjalan secara serial — satu per satu, bukan paralel
  • Jika satu init container gagal (exit code != 0), Kubernetes me-restart Pod dari init container pertama
  • Container utama tidak akan pernah dimulai sampai semua init container berhasil
  • Init container bisa menggunakan image yang berbeda dari container utama — berguna untuk tooling khusus tanpa harus memasukkannya ke image produksi

Perbedaan dengan Container Biasa #

Init Container:
  ✓ Berjalan serial, satu per satu
  ✓ Harus selesai (exit 0) sebelum lanjut
  ✓ Tidak mendukung lifecycle hooks (postStart, preStop)
  ✓ Tidak mendukung liveness atau readiness probe
  ✓ Boleh punya resource yang berbeda dari container utama

Container Biasa:
  ✓ Berjalan paralel (semua sekaligus)
  ✓ Diharapkan berjalan terus (long-running)
  ✓ Mendukung semua probe dan lifecycle hooks
  ✓ Di-restart jika crash (sesuai restartPolicy)

Use Case: Menunggu Dependency Siap #

Ini adalah use case paling umum. Aplikasi sering bergantung pada service lain — database, message queue, external API — yang mungkin belum siap saat Pod pertama kali dijalankan.

apiVersion: v1
kind: Pod
metadata:
  name: api-server
spec:
  initContainers:

  # Init 1: tunggu database siap menerima koneksi
  - name: wait-for-postgres
    image: busybox:1.35
    command:
    - sh
    - -c
    - |
      echo "Waiting for PostgreSQL..."
      until nc -z postgres-service 5432; do
        echo "PostgreSQL not ready, retrying in 3 seconds..."
        sleep 3
      done
      echo "PostgreSQL is ready!"      

  # Init 2: tunggu Redis siap
  - name: wait-for-redis
    image: redis:7-alpine
    command:
    - sh
    - -c
    - |
      until redis-cli -h redis-service ping | grep -q PONG; do
        echo "Redis not ready, retrying..."
        sleep 2
      done
      echo "Redis is ready!"      

  containers:
  - name: api
    image: my-api:v2
    # Baru jalan setelah PostgreSQL DAN Redis siap

Use Case: Database Migration #

Menjalankan database migration sebelum aplikasi dimulai adalah pola yang sangat umum dan tepat untuk init container. Ini memastikan schema selalu up-to-date sebelum ada traffic masuk.

  initContainers:

  - name: run-migrations
    image: my-api:v2          # gunakan image yang sama dengan aplikasi
    command:
    - sh
    - -c
    - |
      echo "Running database migrations..."
      /app/migrate up
      echo "Migrations completed successfully"      
    env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: DATABASE_URL

  containers:
  - name: api
    image: my-api:v2
    # Aplikasi baru jalan setelah migration selesai
Pola migration di init container bekerja dengan baik untuk deployment single-replica atau ketika migration bersifat backward-compatible. Jika kamu punya banyak replica yang di-rolling update, beberapa Pod lama mungkin masih berjalan dengan schema baru. Pastikan migration selalu backward-compatible dengan versi aplikasi sebelumnya.

Use Case: Menyiapkan Konfigurasi Dinamis #

Init container bisa menghasilkan konfigurasi yang dibutuhkan container utama, berdasarkan informasi yang baru diketahui saat runtime:

  volumes:
  - name: config-volume
    emptyDir: {}

  initContainers:
  - name: generate-config
    image: my-config-generator:v1
    command:
    - sh
    - -c
    - |
      # Ambil konfigurasi dari Vault atau secret manager
      # Generate file konfigurasi berdasarkan environment
      /app/generate-config \
        --env production \
        --region $(curl -s http://169.254.169.254/latest/meta-data/placement/region) \
        --output /etc/config/app.yaml      
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config

  containers:
  - name: app
    image: my-app:v1
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config    # baca config yang sudah digenerate
      readOnly: true

Use Case: Clone Repository atau Asset #

Untuk kasus di mana container utama butuh data yang perlu diambil dari tempat lain:

  volumes:
  - name: workdir
    emptyDir: {}

  initContainers:
  - name: clone-repo
    image: alpine/git:2.40
    command:
    - git
    - clone
    - https://github.com/myorg/config-repo.git
    - /work
    volumeMounts:
    - name: workdir
      mountPath: /work

  containers:
  - name: app
    image: my-app:v1
    volumeMounts:
    - name: workdir
      mountPath: /app/config
      readOnly: true

Resource untuk Init Container #

Init container dan container utama punya resource yang dihitung secara berbeda oleh Kubernetes:

  initContainers:
  - name: heavy-migration
    image: my-migrator:v1
    resources:
      requests:
        cpu: "1000m"      # migration butuh lebih banyak resource
        memory: "512Mi"
      limits:
        cpu: "2000m"
        memory: "1Gi"

  containers:
  - name: api
    resources:
      requests:
        cpu: "250m"       # aplikasi normal butuh lebih sedikit
        memory: "128Mi"

Resource efektif yang di-request Pod untuk scheduling adalah maximum dari: (requests semua init container) dan (jumlah requests semua container utama). Init container berjalan bergantian, jadi tidak dijumlah — hanya diambil nilai terbesarnya.

Contoh perhitungan:

Init container A: request 500m CPU
Init container B: request 300m CPU
Container utama:  request 250m CPU

Effective request = max(500m, 300m, 250m) = 500m CPU

Debugging Init Container #

Ketika init container gagal, Pod akan terus me-restart dalam loop. Cara mendiagnosis:

# Lihat status Pod — perhatikan INIT kolom
kubectl get pods

# Output jika init container masih berjalan:
# NAME          READY   STATUS     RESTARTS   AGE
# api-server    0/1     Init:0/2   0          30s

# Output jika init container gagal:
# NAME          READY   STATUS       RESTARTS   AGE
# api-server    0/1     Init:Error   3          2m

# Lihat log dari init container yang gagal
kubectl logs api-server -c wait-for-postgres

# Lihat log dari init container sebelumnya (setelah restart)
kubectl logs api-server -c wait-for-postgres --previous

# Detail event untuk melihat alasan kegagalan
kubectl describe pod api-server

Ringkasan #

  • Serial dan blocking — init container berjalan satu per satu; container utama tidak dimulai sampai semua init container exit 0.
  • Dependency wait yang andal — pola yang tepat untuk menunggu database, message queue, atau service lain siap sebelum aplikasi dimulai.
  • Database migration yang aman — jalankan migration di init container untuk memastikan schema sudah benar sebelum ada traffic masuk; pastikan migration backward-compatible untuk rolling deployment.
  • Gunakan image yang ringan — init container untuk wait-for-dependency tidak perlu image besar; busybox atau alpine sudah cukup.
  • Resource dihitung berbeda — scheduler menggunakan nilai maksimum antara init container dan container utama, bukan penjumlahan.
  • Debug dengan -c nama-init-container — log init container bisa dilihat dengan flag -c diikuti nama init container spesifik.

← Sebelumnya: Single & Multi Container   Berikutnya: Sidecar Pattern →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact