Deployment aman dengan manifest rilis bertujuan membuat proses rilis bisa diprediksi, mudah diaudit, dan cepat dipulihkan saat terjadi kegagalan. Intinya bukan sekadar “bisa deploy”, tetapi memastikan setiap perubahan memiliki identitas jelas, transisi state yang kecil, commit yang atomik, serta jalur rollback yang deterministik.

Pendekatan ini relevan untuk backend dan web service yang ingin mengurangi risiko deploy gagal, mismatch konfigurasi, atau rollback yang justru memperparah kondisi. Prinsipnya dapat diinspirasi dari desain littlefs: state kecil, copy-on-write, commit atomik, dan recovery setelah kegagalan. Pada pipeline deploy, prinsip tersebut diterjemahkan menjadi artefak immutable, manifest rilis yang lengkap, promosi bertahap, dan keputusan rollback berbasis sinyal operasional yang terukur.

Mengapa manifest rilis penting

Banyak kegagalan deployment bukan disebabkan oleh aplikasi yang sepenuhnya rusak, melainkan karena tidak ada representasi tunggal tentang “rilis ini sebenarnya apa”. Tim sering hanya mengandalkan tag Git, image container, atau catatan manual. Akibatnya, saat perlu rollback, tidak jelas kombinasi image, konfigurasi, migrasi, dan feature flag mana yang sebelumnya sehat.

Manifest rilis adalah dokumen mesin-baca yang mendeskripsikan satu unit rilis secara lengkap. Manifest ini menjadi sumber kebenaran untuk:

  • artefak yang akan dijalankan,
  • konfigurasi yang melekat pada rilis,
  • langkah migrasi yang diizinkan,
  • strategi rollout,
  • kriteria health check,
  • serta prosedur rollback.

Dengan manifest, pipeline tidak lagi menyusun state target secara implisit dari banyak tempat. Ia tinggal membaca satu deklarasi yang jelas, lalu mengeksekusi transisi dengan aturan yang konsisten.

Prinsip desain: littlefs untuk pipeline deploy

1. State kecil

Semakin banyak state yang berubah sekaligus, semakin sulit memvalidasi dan memulihkannya. Dalam deployment, ini berarti:

  • pisahkan perubahan kode, konfigurasi, dan skema data bila memungkinkan,
  • hindari deploy besar yang mencampur refactor, migrasi berisiko, dan perubahan perilaku produk sekaligus,
  • simpan metadata rilis sesederhana mungkin agar mudah diaudit.

State kecil mempermudah analisis insiden karena permukaan perubahan lebih sempit.

2. Copy-on-write

Jangan mengubah artefak aktif “di tempat”. Bangun artefak baru, validasi, lalu alihkan traffic. Dalam praktik:

  • image container bersifat immutable,
  • konfigurasi rilis dibuat sebagai snapshot baru, bukan ditimpa sembarangan,
  • slot deploy, target group, atau ReplicaSet baru dibuat lebih dulu sebelum traffic dipindahkan.

Model ini mengurangi risiko state separuh berubah ketika pipeline terputus di tengah jalan.

3. Commit atomik

Deployment harus memiliki titik commit yang jelas: sebelum commit, rilis belum aktif; setelah commit, rilis aktif untuk scope tertentu. Contohnya:

  • switch symlink ke direktori rilis baru,
  • mengubah selector/route load balancer ke versi baru,
  • menaikkan persentase canary setelah health gate lolos.

Tanpa titik commit yang eksplisit, rollback sering berubah menjadi rangkaian tindakan manual yang rentan salah.

4. Recovery setelah kegagalan

Pipeline harus mengasumsikan kegagalan bisa terjadi di mana saja: image gagal start, migrasi lambat, readiness tidak pernah hijau, error rate naik, atau dependensi eksternal tidak kompatibel. Karena itu, setiap tahap perlu:

  • checkpoint state terakhir yang valid,
  • batas waktu yang jelas,
  • jalur rollback otomatis atau semi-otomatis,
  • catatan audit yang menunjukkan aksi terakhir pipeline.

Apa isi manifest rilis

Manifest rilis sebaiknya cukup kaya untuk menggerakkan pipeline, tetapi tidak terlalu kompleks hingga sulit dipelihara. Struktur tepatnya bisa berbeda, namun elemen berikut umumnya berguna.

Contoh manifest rilis

release_id: 2026-07-29.1
service: billing-api
git:
  commit: a1b2c3d4
  branch: main
artifact:
  image: registry.example.com/billing-api@sha256:9f3...
  sbom_ref: sbom/billing-api-a1b2c3d4.json
runtime:
  replicas: 6
  resources:
    cpu: "500m"
    memory: "512Mi"
config:
  env_ref: config/prod/billing-api/2026-07-29.1.env
  secrets_ref: vault://prod/billing-api
schema:
  migration_plan: expand-contract
  backward_compatible: true
  rollback_safe: true
traffic:
  strategy: canary
  steps:
    - percent: 5
      hold: 5m
    - percent: 25
      hold: 10m
    - percent: 100
health:
  startup_grace: 60s
  readiness:
    path: /ready
    success_codes: [200]
  liveness:
    path: /live
    success_codes: [200]
  slo_gates:
    max_error_rate: "1%"
    max_p95_latency_ms: 400
feature_flags:
  - name: invoice_v2
    default: off
rollback:
  target_release: 2026-07-21.3
  automated: true
  conditions:
    - readiness_failed
    - error_budget_burn_high
observability:
  dashboard_ref: grafana/billing-api-release
  logs_query_ref: loki/billing-api-release
  trace_service_name: billing-api
approvals:
  required:
    - tech_lead
    - oncall

Elemen yang sebaiknya ada

  • Identitas rilis: release_id, service, commit Git, branch.
  • Artefak immutable: digest image, checksum paket, referensi SBOM bila tersedia.
  • Konfigurasi: referensi file env, secret path, parameter runtime.
  • Kontrak skema data: jenis migrasi, kompatibilitas mundur, keamanan rollback.
  • Strategi traffic: blue/green, canary, rolling, beserta step dan hold time.
  • Health gate: readiness, liveness, startup grace period, SLO/SLI minimum.
  • Feature flag: flag yang relevan untuk rilis itu.
  • Rollback plan: target rollback, prasyarat, dan kapan rollback otomatis diizinkan.
  • Observability: dashboard, query log, nama service tracing, korelasi release_id.
  • Approval dan audit: siapa yang menyetujui, kapan dipromosikan.

Kesalahan umum adalah membuat manifest hanya berisi nama image. Itu belum cukup untuk rollback yang deterministik karena deployment nyata juga bergantung pada konfigurasi, migrasi, flag, dan aturan traffic.

Membangun rollback deterministik

Rollback deterministik berarti tim tahu persis target pemulihan dan efek sampingnya. Bukan “coba turunkan versinya dulu, nanti lihat”. Ini penting terutama jika ada perubahan database atau feature flag yang ikut bergerak.

Prinsip rollback yang aman

  1. Rollback ke release manifest sebelumnya yang diketahui sehat, bukan ke commit Git acak.
  2. Pastikan artefak lama masih tersedia di registry atau artefact store.
  3. Gunakan migrasi yang kompatibel mundur agar versi lama masih bisa membaca data baru selama jendela rollback.
  4. Bedakan rollback kode dan rollback data. Rollback kode bisa cepat; rollback data sering berisiko tinggi dan sebaiknya dihindari kecuali sangat terencana.
  5. Simpan snapshot konfigurasi per rilis agar rollback tidak memakai env terbaru yang belum kompatibel.

Expand-contract untuk skema database

Rollback paling sering gagal karena migrasi database tidak dirancang untuk dua versi aplikasi yang berjalan bersamaan. Strategi yang relatif aman adalah expand-contract:

  • Expand: tambahkan kolom/tabel/index baru tanpa menghapus yang lama.
  • Deploy aplikasi yang bisa membaca format lama dan baru.
  • Aktifkan perilaku baru lewat feature flag jika perlu.
  • Setelah stabil, baru lakukan contract: hapus field lama di rilis terpisah.

Dengan pola ini, rollback aplikasi tidak langsung bentrok dengan skema yang baru ditambahkan.

Contoh alur rollback

# 1) Lihat rilis aktif dan kandidat rollback
releasectl current billing-api
releasectl history billing-api

# 2) Rollback ke rilis terakhir yang sehat
releasectl rollback billing-api --to 2026-07-21.3

# 3) Verifikasi setelah rollback
releasectl status billing-api
curl -fsS https://billing.example.com/ready

Nama tool di atas hanya ilustrasi. Yang penting adalah model kerjanya: target rollback harus berbasis release_id, bukan sekadar “tag sebelumnya”.

Health check yang benar-benar berguna

Health check yang terlalu dangkal sering memberi rasa aman palsu. Endpoint yang hanya mengembalikan 200 tanpa memeriksa dependency penting tidak cukup untuk deployment kritikal.

Jenis health check

  • Liveness: proses hidup dan tidak deadlock. Jangan masukkan validasi dependency yang rapuh ke sini, karena bisa memicu restart berulang.
  • Readiness: instance siap menerima traffic. Di sini Anda boleh memeriksa konektivitas yang memang wajib, seperti database utama atau cache yang bersifat hard dependency.
  • Startup: memberi waktu bootstrap agar container lambat start tidak dianggap gagal terlalu cepat.

Apa yang sebaiknya diuji oleh readiness

  • koneksi ke dependency wajib,
  • migrasi minimum sudah kompatibel dengan versi aplikasi aktif,
  • cache warming penting sudah cukup,
  • worker internal yang diperlukan untuk request sinkron tersedia.

Hindari readiness yang terlalu mahal, misalnya query berat ke database setiap hit. Gunakan cek ringan dengan timeout pendek dan cache internal bila perlu.

Health gate saat canary

Sebelum menaikkan traffic dari 5% ke 25% lalu ke 100%, evaluasi minimal:

  • error rate HTTP 5xx,
  • latensi p95 atau p99 pada endpoint utama,
  • timeout ke dependency kritikal,
  • restart container/pod,
  • anomali log error.

Jika sinyal tidak sehat, pipeline harus berhenti di step saat ini dan menunggu keputusan rollback atau investigasi.

Feature flag untuk mengurangi blast radius

Feature flag bukan pengganti deployment yang aman, tetapi alat untuk memisahkan delivery dari activation. Anda bisa mengirim kode ke produksi dalam keadaan dorman, lalu mengaktifkannya untuk subset user setelah instance baru terbukti stabil.

Kapan feature flag membantu

  • fitur baru mengubah perilaku bisnis yang belum pasti,
  • migrasi bertahap dari jalur lama ke jalur baru,
  • butuh kill switch tanpa redeploy,
  • uji canary berbasis tenant, region, atau cohort user.

Kesalahan umum pada feature flag

  • Flag permanen yang tidak pernah dibersihkan, membuat kode sulit dipahami.
  • Konfigurasi flag tidak terversi sehingga sulit mengetahui state saat insiden.
  • Flag mengontrol perubahan skema yang tidak kompatibel, padahal rollback kode masih harus aman tanpa bergantung pada flag.

Sebaiknya manifest rilis mencantumkan flag yang relevan dan default state-nya. Ini penting untuk audit dan reproduksi kondisi saat insiden.

Canary bertahap dan kapan menghentikannya

Canary bertahap adalah cara praktis menerapkan prinsip state kecil dan commit atomik. Anda memindahkan traffic sedikit demi sedikit sambil mengamati sinyal kesehatan. Jika gagal, dampaknya masih terbatas.

Contoh strategi canary

  1. Deploy versi baru tanpa traffic.
  2. Jalankan startup check dan readiness.
  3. Arahkan 5% traffic selama 5 menit.
  4. Jika sehat, naikkan ke 25% selama 10 menit.
  5. Jika tetap sehat, promosi ke 100%.
  6. Pertahankan rilis lama untuk jendela rollback singkat.

Indikator menghentikan canary

  • error rate naik konsisten dibanding baseline,
  • latensi tail meningkat pada endpoint kritikal,
  • CPU/memori naik tidak wajar,
  • retry ke dependency melonjak,
  • terjadi error fungsional pada alur bisnis utama meski health endpoint hijau.

Kesalahan umum adalah hanya melihat metrik infrastruktur. Banyak deploy lolos karena CPU normal, padahal transaksi bisnis gagal akibat perubahan kontrak API atau data.

Observability minimum untuk deployment aman

Tanpa observability, rollback sering terlambat karena tim tidak punya bukti yang cukup. Untuk deployment aman, tidak harus mewah, tetapi ada minimum viable observability.

1. Log terstruktur

Pastikan log memuat paling tidak:

  • timestamp,
  • service name,
  • environment,
  • release_id,
  • request/correlation id,
  • severity,
  • pesan error dan konteks penting.

release_id wajib agar lonjakan error bisa langsung dikorelasikan dengan rilis tertentu.

2. Metric inti

  • request rate,
  • error rate,
  • latensi p50/p95/p99,
  • saturasi resource dasar: CPU, memori, restart,
  • metric bisnis minimum, misalnya jumlah checkout sukses atau pembayaran gagal.

3. Trace

Distributed tracing membantu saat latensi naik tetapi tidak jelas bottleneck-nya di service mana. Untuk deployment, trace sangat berguna mendeteksi apakah versi baru memperlambat panggilan ke database atau downstream API.

4. Error budget dan burn rate

Jangan menunggu dashboard “terlihat buruk”. Tentukan batas sederhana: jika burn rate error budget melonjak pada window pendek setelah deploy, canary harus berhenti atau rollback otomatis dipertimbangkan. Nilai ambang dapat berbeda per layanan, tetapi prinsipnya sama: keputusan promosi harus berbasis SLO, bukan intuisi semata.

Jika layanan belum punya SLO formal, mulai dari indikator paling praktis: error rate endpoint utama, latensi tail, dan tingkat keberhasilan transaksi bisnis inti selama jendela canary.

Checklist deployment aman

Sebelum deploy

  • Artefak immutable sudah dibangun dan bisa ditelusuri ke commit.
  • Manifest rilis lengkap dan tervalidasi.
  • Konfigurasi dan secret untuk rilis sudah siap.
  • Migrasi database dirancang kompatibel mundur.
  • Health check readiness/liveness sudah diverifikasi.
  • Dashboard log, metric, trace untuk service tersedia.
  • Feature flag baru memiliki default state yang jelas.
  • Rilis sebelumnya yang sehat masih tersedia untuk rollback.
  • On-call tahu jadwal deploy dan blast radius-nya.

Saat deploy

  • Deploy tanpa traffic terlebih dahulu jika platform mendukung.
  • Tunggu readiness hijau sebelum canary dimulai.
  • Naikkan traffic bertahap, jangan lompat ke 100% tanpa alasan kuat.
  • Pantau error rate, latensi, restart, dan metrik bisnis inti.
  • Catat waktu mulai deploy dan setiap promosi traffic.

Setelah deploy

  • Pastikan 100% traffic sudah stabil pada window observasi yang disepakati.
  • Verifikasi metric bisnis, bukan hanya health endpoint.
  • Nonaktifkan atau rapikan flag sementara jika tidak lagi diperlukan.
  • Simpan hasil deploy: durasi, issue, keputusan, dan status akhir.

Alur insiden saat deploy gagal

Berikut alur praktis yang bisa dijadikan runbook ringan.

  1. Deteksi: alarm canary, lonjakan 5xx, latensi naik, atau laporan user.
  2. Freeze promosi: hentikan kenaikan traffic ke versi baru.
  3. Triage cepat: cek apakah masalahnya infrastruktur, konfigurasi, dependency, atau bug aplikasi.
  4. Bandingkan dengan baseline: lihat perbedaan antara rilis lama dan baru pada log, metric, trace.
  5. Putuskan rollback vs hotfix.
  6. Eksekusi: rollback ke release_id terakhir yang sehat atau lakukan mitigasi terkontrol.
  7. Verifikasi pemulihan: pastikan metrik kembali normal dan transaksi bisnis pulih.
  8. Komunikasi: update status ke tim terkait dan catat timeline.

Kapan rollback lebih tepat daripada hotfix

  • Dampak ke user sedang atau tinggi.
  • Penyebab belum jelas dalam beberapa menit pertama.
  • Rilis baru menyentuh jalur bisnis kritikal.
  • Canary menunjukkan degradasi konsisten, bukan fluktuasi sesaat.
  • Tersedia rilis lama yang diketahui sehat dan kompatibel.

Kapan hotfix bisa dipilih

  • Masalah sangat terlokalisasi dan akar penyebab sudah jelas.
  • Mitigasi bisa dilakukan cepat tanpa memperluas risiko, misalnya mematikan feature flag atau memperbaiki konfigurasi yang salah.
  • Rollback justru lebih berisiko, misalnya karena ada ketergantungan state yang sudah terlanjur berpindah.

Aturan praktisnya: jika ragu dan blast radius membesar, rollback dulu. Hotfix saat sistem sedang tidak stabil sering memperpanjang MTTR.

Contoh keputusan operasional: rollback atau hotfix

  • Readiness gagal di semua pod baru karena env var hilang: biasanya rollback atau perbaikan konfigurasi cepat, tergantung apakah traffic sudah masuk.
  • Error 5xx naik hanya saat flag fitur aktif: matikan flag lebih dulu, lalu lanjut investigasi tanpa rollback penuh jika service inti stabil.
  • Latensi database melonjak setelah query baru dirilis: jika berdampak luas, rollback aplikasi lebih aman sambil mengkaji indeks atau query plan.
  • Migrasi schema menghapus kolom lama terlalu cepat: ini contoh desain rilis yang buruk; rollback aplikasi mungkin tidak cukup. Fokus ke pemulihan kompatibilitas dan evaluasi proses migrasi.

Postmortem ringan setelah insiden deploy

Tidak semua insiden perlu dokumen panjang. Untuk kegagalan deploy, postmortem ringan sering cukup asalkan konsisten dan dapat ditindaklanjuti.

Template singkat

  • Apa yang berubah? Release ID, commit, flag, migrasi, konfigurasi.
  • Apa gejalanya? Error, latensi, transaksi gagal, area terdampak.
  • Kapan terdeteksi dan oleh siapa?
  • Apa keputusan yang diambil? Freeze, rollback, hotfix, disable flag.
  • Akar penyebab teknis.
  • Mengapa lolos sebelum produksi? Gap pada test, review, observability, atau proses approval.
  • Tindakan pencegahan dengan pemilik dan tenggat waktu.

Hindari postmortem yang fokus menyalahkan individu. Tujuannya adalah memperbaiki sistem: pipeline, validasi, observability, dan desain rilis.

Tindakan pencegahan agar rilis berikutnya lebih aman

  • Validasi manifest di CI: cek field wajib, referensi artefak, kompatibilitas strategi rollout, dan keberadaan target rollback.
  • Gunakan artefak immutable: hindari tag image yang dapat berubah makna seperti latest.
  • Latih rollback: lakukan simulasi rollback berkala, bukan hanya menulis runbook.
  • Uji migrasi secara realistis: terutama untuk skala data dan kompatibilitas dua versi aplikasi.
  • Tambahkan release marker ke log, metric, dan trace agar analisis insiden lebih cepat.
  • Batasi perubahan per rilis: jangan menggabungkan terlalu banyak risiko dalam satu deploy.
  • Bersihkan feature flag yang sudah tidak diperlukan.
  • Definisikan gate promosi yang objektif agar keputusan tidak sepenuhnya subjektif.

Penutup

Deployment aman dengan manifest rilis bukan soal alat tertentu, melainkan desain proses yang meminimalkan state, memakai artefak immutable, melakukan commit atomik, dan menyediakan recovery yang jelas setelah kegagalan. Jika manifest mendeskripsikan satu rilis secara lengkap, rollback menjadi lebih deterministik, canary lebih terukur, dan investigasi insiden lebih cepat.

Mulailah dari hal yang paling berdampak: definisikan manifest rilis, masukkan release_id ke observability, gunakan strategi canary sederhana, dan rancang migrasi yang kompatibel untuk rollback. Bahkan tanpa platform yang rumit, empat prinsip ini sudah cukup untuk membuat pipeline deploy jauh lebih aman dan dapat diandalkan.