Deploy tanpa jeda & observability produksi
Semua bagian sudah ada: graceful shutdown, health check, migrasi kompatibel dua arah. Materi ini merangkainya jadi deploy yang tidak menghasilkan satu pun respons non-200 — dan memastikan kamu tahu kalau ia gagal.
Intisari
minimumHealthyPercent: 100+maximumPercent: 200= task baru siap sebelum yang lama berhenti.- Nyalakan deployment circuit breaker dengan
rollback: true— deploy yang gagal kembali sendiri. - Rantai lengkapnya: readiness → deregistration delay →
Shutdown→stopTimeout. Semua harus selaras. - Log JSON dengan
request_idmembuat CloudWatch Logs Insights bisa dipakai sungguhan. - Delapan alarm menutup sebagian besar insiden yang bisa diperkirakan.
Konfigurasi service
{
"serviceName": "toko-server",
"desiredCount": 4,
"deploymentConfiguration": {
"minimumHealthyPercent": 100, // jangan pernah turun di bawah 4 task sehat
"maximumPercent": 200, // boleh sampai 8 task selama transisi
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true // gagal → kembali ke revisi sebelumnya
}
},
"healthCheckGracePeriodSeconds": 45,
"loadBalancers": [{
"targetGroupArn": "arn:aws:elasticloadbalancing:...",
"containerName": "server",
"containerPort": 8080
}]
}
| Setelan | Kalau salah |
|---|---|
minimumHealthyPercent: 50 | Separuh kapasitas hilang selama deploy — latensi naik saat trafik tinggi |
maximumPercent: 100 | Task lama harus mati dulu sebelum yang baru mulai — ada jeda |
| Circuit breaker mati | Deploy rusak terus mencoba sampai kamu menyadarinya |
healthCheckGracePeriod terlalu pendek | Task dibunuh saat masih memuat |
Rantai waktu shutdown
Semua angka ini harus selaras, atau permintaan akan terpotong:
Health check ALB : interval 10 dtk × ambang 2 = terdeteksi dalam 20 dtk
Jeda readiness : 10 dtk (aplikasi mulai membalas 503 di /siap)
Deregistration delay: 30 dtk (ALB menyelesaikan yang sedang berjalan)
srv.Shutdown(ctx) : 20 dtk
stopTimeout ECS : 60 dtk ← harus > 10 + 20 + margin
kalau tidak: SIGKILL
Aturannya: stopTimeout > jeda + Shutdown + penghentian worker
Semua ini sudah kamu tulis di Fase 3. Yang ditambahkan di sini cuma angkanya, dan syarat bahwa
angka di infrastruktur harus lebih longgar daripada angka di aplikasi. Kalau stopTimeout
lebih kecil, ECS mengirim SIGKILL di tengah Shutdown — dan transaksi yang belum di-commit,
pesan antrean yang belum di-ack, serta permintaan yang sedang berjalan semuanya mati begitu saja.
Log yang bisa dikueri
// Log JSON ke stdout (Fase 5), dikumpulkan driver awslogs.
log.InfoContext(ctx, "permintaan",
"metode", r.Method,
"rute", polaRute, // POLA, bukan URL mentah
"status", ww.status,
"durasi_ms", ms,
"request_id", RequestID(ctx),
"trace_id", traceID,
"pengguna_id", u.ID)
-- CloudWatch Logs Insights
-- p95 per rute
fields @timestamp, rute, durasi_ms
| filter ispresent(durasi_ms)
| stats pct(durasi_ms, 95) as p95, pct(durasi_ms, 99) as p99, count(*) as n
by rute
| sort p95 desc
-- semua baris untuk satu permintaan yang gagal
fields @timestamp, @message
| filter request_id = "01HQ8XZ4K2..."
| sort @timestamp asc
-- endpoint mana yang paling banyak menghasilkan 5xx
fields rute, status
| filter status >= 500
| stats count(*) as gagal by rute
| sort gagal desc
Kueri pertama itu tidak mungkin ditulis kalau log-mu berupa kalimat. Log terstruktur bukan soal
kerapian — ia yang membuat CloudWatch berubah dari tempat menyimpan teks jadi alat investigasi. Dan
request_id di setiap baris adalah yang membuat kueri kedua berguna saat insiden.
Delapan alarm
| Alarm | Ambang | Artinya |
|---|---|---|
HTTPCode_Target_5XX | > 1% selama 5 menit | Aplikasi gagal |
HTTPCode_ELB_5XX | > 0 selama 5 menit | Tidak ada target sehat |
TargetResponseTime p95 | > 2× baseline, 10 menit | Melambat |
UnHealthyHostCount | > 0 selama 5 menit | Task bermasalah |
| CPU / memori task | > 85% selama 10 menit | Perlu skala atau ada kebocoran |
DatabaseConnections | > 80% dari batas | Aritmetika pool salah (Fase 4) |
| Umur pesan tertua SQS | > 5 menit | Worker tertinggal (Fase 5) |
| Kedalaman DLQ | > 0 | Ada job yang gagal permanen |
Alarm yang berbunyi tanpa ada yang bisa dilakukan akan diabaikan, dan alarm yang diabaikan sama dengan tidak ada alarm. Setiap alarm butuh satu kalimat runbook: apa yang harus diperiksa pertama. Kalau sebuah alarm tidak punya jawaban untuk itu, ia belum layak jadi alarm.
Daftar periksa sebelum deploy pertama ke produksi
- Aplikasi — graceful shutdown, timeout di setiap lapisan, log JSON ke stdout, endpoint
/sehatdan/siapterpisah. - Konfigurasi — semua rahasia lewat
secrets,GOMEMLIMITtersetel, gagal-cepat saat konfigurasi kurang. - Image — multi-stage, distroless, non-root, tag SHA, dipindai.
- Database —
MaxOpenConnsdihitung untuk jumlah task maksimum,ConnMaxLifetimetersetel, migrasi sebagai langkah pipeline. - Jaringan — task di subnet privat, security group saling merujuk, TLS ke RDS.
- Deploy — OIDC tanpa access key, circuit breaker aktif, rollback pernah diuji.
- Observability — delapan alarm terpasang, dasbor p95, trace tersambung ke log.
- Cache — CloudFront di depan, header
Cache-Controlbenar untuk halaman publik dan personal.
Latihan: jalankan deploy sambil membebani aplikasimu dengan hey -z 120s -c 20 dan
hitung berapa respons non-200 yang muncul. Kalau lebih dari nol, telusuri rantai waktu shutdown di atas
dan temukan angka mana yang tidak selaras. Lalu deploy image yang sengaja rusak dan buktikan circuit
breaker mengembalikannya sendiri.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.