Deploy aman di server tua bukan soal memakai tool paling baru, tetapi soal mengurangi risiko pada mesin yang CPU, RAM, dan I/O-nya terbatas. Pendekatan yang paling aman biasanya sederhana: kirim artifact kecil, validasi lingkungan sebelum switch traffic, aktifkan release lewat symlink, dan siapkan rollback yang bisa dilakukan dalam hitungan detik.

Pada server lama, kesalahan kecil saat deploy sering berdampak besar: proses build memakan RAM, migrasi membuat disk penuh, restart service memicu cold start lama, atau log berlebihan menekan I/O. Karena itu, strategi deployment harus dirancang untuk meminimalkan kerja di server target, bukan memindahkan seluruh beban build ke sana. Di sisi lain, observability minimum wajib ada agar tim tahu kapan deploy menyebabkan CPU naik, latency memburuk, atau error rate melonjak.

Mengapa server tua butuh strategi deploy yang berbeda

Server tua sering memiliki karakteristik berikut:

  • CPU terbatas: kompilasi, bundling aset, atau startup aplikasi bisa lama.
  • RAM sempit: proses build, cache besar, dan terlalu banyak worker mudah memicu OOM.
  • Disk lambat atau kecil: ekstraksi artifact besar, rotasi log buruk, dan file sementara cepat menjadi masalah.
  • Tidak ada shared filesystem: beberapa server berdiri sendiri, sehingga rollback harus bisa dilakukan per-node.

Konsekuensinya, pola deploy yang aman adalah:

  1. Build dilakukan di luar server target, misalnya di CI atau mesin build terpisah.
  2. Artifact yang dikirim sekecil mungkin dan sudah siap jalan.
  3. Release baru ditempatkan di direktori terpisah, lalu diaktifkan dengan mengganti symlink.
  4. Health check dipakai untuk memutuskan apakah release layak menerima traffic.
  5. Rollback cukup dengan mengembalikan symlink ke release sebelumnya.

Pola ini bekerja karena memisahkan persiapan release dari aktivasi release. Pada mesin lemah, pemisahan ini sangat penting: mengekstrak file dan memeriksa dependensi boleh memakan waktu, tetapi pergantian release aktif harus nyaris instan.

Arsitektur deploy ringan yang cocok untuk resource terbatas

Struktur direktori release

Gunakan struktur sederhana seperti berikut:

/srv/myapp/
├── releases/
│   ├── 20260807-101500/
│   └── 20260807-114200/
├── current -> /srv/myapp/releases/20260807-114200
├── shared/
│   ├── logs/
│   ├── tmp/
│   └── config/
└── bin/
    └── deploy.sh

Prinsip dasarnya:

  • releases/ berisi artifact versi berbeda, immutable setelah diekstrak.
  • current adalah symlink ke release aktif.
  • shared/ untuk data yang harus bertahan antar release, misalnya file konfigurasi lokal atau direktori log.

Jangan salah paham: artikel ini menekankan rollback cepat tanpa shared filesystem, bukan tanpa direktori shared lokal. Maksudnya, Anda tidak mengandalkan storage bersama antar server. Setiap server menyimpan release-nya sendiri, sehingga rollback tetap bisa dilakukan walau node lain bermasalah.

Build artifact kecil

Server tua sebaiknya tidak melakukan:

  • npm install atau bundling frontend berat.
  • composer install atau kompilasi dependency besar di production.
  • proses test atau asset optimization yang menghabiskan CPU.

Lakukan semua itu di CI, lalu kirim artifact yang sudah siap pakai. Artifact yang baik biasanya:

  • hanya berisi file runtime yang diperlukan,
  • tidak membawa cache development, dokumentasi, source map yang tidak dipakai di server, atau file test,
  • sudah terkompresi agar transfer lebih cepat, tetapi tidak terlalu besar saat diekstrak.

Trade-off: artifact yang sangat kecil mengurangi beban server, tetapi pipeline CI menjadi lebih penting. Jika CI gagal membangun artifact yang benar, server production tidak punya kemampuan untuk “memperbaiki” sendiri dengan install ulang dependency.

Symlink release untuk switch cepat

Alih-alih menimpa file aplikasi yang sedang aktif, ekstrak release baru ke folder baru, lalu ubah symlink current. Pergantian symlink cepat dan umumnya atomik pada filesystem lokal. Ini membuat rollback sederhana: kembalikan symlink ke release sebelumnya.

Pola ini aman karena file release lama tetap utuh. Jika startup release baru gagal, Anda tidak perlu menyalin ulang file; cukup balik arah symlink dan restart service jika diperlukan.

Langkah deploy aman: preflight check, health check, dan rollback

1) Preflight check sebelum aktivasi

Preflight check adalah validasi lingkungan sebelum release baru dijadikan aktif. Pada server tua, ini penting karena kegagalan sering bukan di kode, tetapi di kapasitas mesin.

Checklist preflight minimum:

  • Direktori release baru berhasil diekstrak.
  • Permission file dan owner benar.
  • Konfigurasi wajib tersedia.
  • Ruang disk masih aman untuk ekstraksi, log, dan file sementara.
  • Port layanan tidak bentrok.
  • Koneksi ke dependensi penting tersedia bila relevan: database, cache, message broker.
  • Proses startup kering (dry validation) lulus, misalnya validasi config atau syntax check jika runtime mendukung.

Contoh shell script preflight sederhana:

#!/usr/bin/env sh
set -eu

APP_ROOT=/srv/myapp
RELEASE_DIR="$1"
MIN_FREE_MB=500

free_mb=$(df -Pm "$APP_ROOT" | awk 'NR==2 {print $4}')
if [ "$free_mb" -lt "$MIN_FREE_MB" ]; then
  echo "Preflight gagal: disk tersisa ${free_mb}MB"
  exit 1
fi

if [ ! -f "$RELEASE_DIR/config/app.env" ]; then
  echo "Preflight gagal: config/app.env tidak ditemukan"
  exit 1
fi

if ! test -x "$RELEASE_DIR/bin/start"; then
  echo "Preflight gagal: bin/start tidak executable"
  exit 1
fi

echo "Preflight OK"

Mengapa ini efektif: banyak insiden deploy di server tua sebenarnya dapat dicegah sebelum switch traffic. Disk penuh, file tidak executable, atau konfigurasi hilang adalah kegagalan murah yang seharusnya tertangkap lebih awal.

2) Aktivasi release dengan symlink

Setelah preflight lulus, aktivasi release bisa dilakukan seperti ini:

ln -sfn /srv/myapp/releases/20260807-114200 /srv/myapp/current
systemctl restart myapp

Jika aplikasi mendukung reload yang lebih ringan daripada restart penuh, itu lebih baik untuk server lama. Namun jangan memaksakan zero-downtime palsu jika runtime Anda tetap melakukan cold start berat. Pada mesin terbatas, restart singkat yang terkontrol sering lebih aman daripada reload rumit yang sulit diprediksi.

3) Health check setelah aktivasi

Setelah release aktif, lakukan health check dari luar proses startup. Health check minimal harus menjawab pertanyaan: “Apakah aplikasi benar-benar siap melayani request?”

Jangan hanya cek bahwa proses hidup. Proses bisa hidup tetapi gagal konek database, deadlock saat warmup, atau merespons terlalu lambat. Endpoint health yang berguna biasanya memeriksa:

  • proses web merespons HTTP,
  • dependency kritis tersedia bila memang wajib untuk melayani traffic,
  • waktu respons masih masuk batas aman.

Contoh endpoint sederhana:

GET /healthz
200 OK
{
  "status": "ok"
}

Untuk server tua, health check sebaiknya ringan. Jangan melakukan query berat atau memeriksa terlalu banyak komponen dalam satu request health. Pisahkan jika perlu:

  • /livez: proses hidup.
  • /readyz: siap menerima traffic.

4) Rollback cepat tanpa shared filesystem

Jika health check gagal atau metrik memburuk setelah deploy, rollback idealnya seperti ini:

  1. hentikan rollout ke node lain,
  2. ubah symlink current ke release sebelumnya di node terdampak,
  3. restart atau reload service,
  4. verifikasi health check dan metrik dasar.
ln -sfn /srv/myapp/releases/20260807-101500 /srv/myapp/current
systemctl restart myapp

Tanpa shared filesystem, setiap node menyimpan release historinya sendiri. Artinya rollback tidak bergantung pada NFS, object store mount, atau volume bersama yang bisa menjadi bottleneck atau single point of failure. Kelemahannya, Anda harus memastikan artifact release yang sama berhasil dikirim ke setiap node dan ada mekanisme retensi agar disk tidak penuh.

Observability minimum yang wajib ada

Pada server tua, observability tidak harus rumit, tetapi harus cukup untuk menjawab: apakah deploy baru meningkatkan error, memperlambat respons, atau menghabiskan resource?

1) Log terstruktur

Gunakan log terstruktur, minimal dalam format key-value atau JSON. Tujuannya bukan gaya, tetapi agar Anda bisa memfilter berdasarkan release, severity, path, status code, dan request ID.

Field minimum yang berguna:

  • timestamp
  • level
  • service
  • release
  • request_id
  • method dan path
  • status
  • latency_ms
  • error atau ringkasan exception

Contoh log JSON:

{
  "timestamp": "2026-08-07T11:45:12Z",
  "level": "error",
  "service": "myapp",
  "release": "20260807-114200",
  "request_id": "9f2c1e",
  "method": "GET",
  "path": "/api/orders",
  "status": 500,
  "latency_ms": 842,
  "error": "database timeout"
}

Kesalahan umum: log terlalu verbose di server dengan disk lambat. Solusinya bukan mematikan log penting, melainkan batasi level debug di production, aktifkan rotasi log, dan kirim ringkasan ke sistem pusat jika memungkinkan.

2) Metrik host: CPU, RAM, disk

Minimal, pantau:

  • CPU usage: apakah deploy baru memicu proses startup atau GC yang berat?
  • Memory usage: apakah ada kebocoran memori atau jumlah worker terlalu banyak?
  • Disk usage: apakah release menambah konsumsi disk secara terus-menerus?
  • Disk I/O bila tersedia: penting pada server tua dengan storage lambat.

Jika stack Anda sederhana, exporter host dasar dan dashboard minimal sudah cukup. Jangan mengejar puluhan panel lebih dulu. Untuk deploy aman, tiga sinyal pertama biasanya paling berguna.

3) Metrik aplikasi: latency dan error rate

Dua metrik paling praktis setelah deploy adalah:

  • Latency: median atau percentile tinggi bisa menunjukkan bottleneck baru.
  • Error rate: lonjakan 5xx, timeout, atau kegagalan job background.

Tambahkan label release pada metrik atau setidaknya cantumkan release dalam log. Tanpa ini, Anda akan sulit menjawab apakah masalah mulai muncul tepat setelah versi tertentu aktif.

4) Alert sederhana yang realistis

Alert minimum tidak perlu canggih. Yang penting actionable. Contoh:

  • CPU tinggi terus-menerus setelah deploy.
  • Memori mendekati batas aman atau OOM restart terdeteksi.
  • Disk tersisa di bawah ambang tertentu.
  • Error rate meningkat signifikan dibanding baseline singkat sebelum deploy.
  • Latency endpoint utama naik tajam setelah release baru aktif.

Alert yang baik harus punya tindak lanjut jelas. Jika notifikasi berbunyi tetapi tim tidak tahu langkah pertama, alert tersebut belum cukup baik.

Contoh alur deploy praktis

Berikut alur yang cocok untuk aplikasi web sederhana di beberapa server lama:

  1. CI build artifact yang sudah siap jalan.
  2. Artifact diunggah ke tiap node, misalnya lewat SCP atau agent deploy.
  3. Artifact diekstrak ke releases/<id>.
  4. Preflight check dijalankan di node target.
  5. Node pertama diaktifkan sebagai canary kecil.
  6. Health check, log, CPU/RAM, latency, dan error rate diamati beberapa menit.
  7. Jika aman, lanjutkan ke node berikutnya bertahap.
  8. Jika bermasalah, rollback node yang terdampak, hentikan rollout, dan investigasi.

Mengapa canary berguna di server tua: mesin lemah sering menunjukkan masalah lebih cepat daripada server modern, misalnya lonjakan startup time atau memory pressure. Satu node canary dapat mengungkap masalah sebelum seluruh fleet terkena.

Checklist deploy

  • Artifact sudah dibangun di luar production.
  • Ukuran artifact dan kebutuhan ekstraksi masuk akal untuk disk target.
  • Release ID unik dan dapat ditelusuri.
  • Preflight check lulus.
  • Health endpoint tersedia dan ringan.
  • Log menyertakan release ID.
  • Metrik CPU, RAM, disk, latency, dan error rate terlihat.
  • Rollback command sudah diuji sebelumnya.
  • Retensi release lama diatur agar disk tidak penuh.

Runbook insiden singkat: deploy memicu lonjakan resource

Misalkan setelah deploy, CPU dan RAM melonjak, latency naik, dan sebagian request timeout. Runbook singkat berikut cukup realistis untuk tim kecil.

Gejala

  • CPU di atas kebiasaan normal setelah release aktif.
  • RAM naik cepat atau proses restart karena OOM.
  • Latency endpoint utama meningkat.
  • Error rate 5xx atau timeout bertambah.

Langkah respons 10-15 menit pertama

  1. Stop rollout ke node lain.
  2. Identifikasi scope: hanya node canary atau semua node yang sudah di-update?
  3. Cek health endpoint dan log error utama.
  4. Bandingkan release: pastikan gejala mulai setelah release baru aktif.
  5. Rollback node terdampak jika layanan utama terganggu.
  6. Verifikasi pemulihan: health check OK, error rate turun, latency membaik.
  7. Simpan artefak investigasi: log 10-15 menit sebelum dan sesudah deploy, grafik CPU/RAM/latency, release ID, waktu aktivasi.

Pertanyaan diagnosis cepat

  • Apakah jumlah worker berubah dan terlalu besar untuk RAM server?
  • Apakah release baru memicu warmup cache atau migrasi berat saat startup?
  • Apakah ada query baru yang lebih lambat?
  • Apakah logging bertambah banyak sehingga menekan disk I/O?
  • Apakah ada asset atau dependency baru yang memperlama startup?

Keputusan rollback vs mitigasi sementara

Pilih rollback jika layanan utama terganggu dan penyebab belum jelas. Pilih mitigasi sementara hanya jika risikonya kecil dan tim benar-benar paham dampaknya, misalnya menurunkan jumlah worker, mematikan fitur non-esensial lewat feature flag, atau menonaktifkan endpoint yang mahal. Pada server tua, rollback biasanya lebih aman daripada tuning darurat di tengah insiden.

Postmortem ringan setelah insiden deploy

Postmortem tidak harus panjang. Yang penting membuat rilis berikutnya lebih aman.

Template singkat

  • Ringkasan: apa yang terjadi, kapan mulai, kapan pulih.
  • Dampak: layanan apa yang terganggu, gejala utama, durasi.
  • Pemicu: release atau perubahan apa yang memulai insiden.
  • Akar masalah paling mungkin: misalnya memory footprint naik, startup terlalu berat, query baru lambat.
  • Deteksi: alert mana yang muncul atau justru tidak ada.
  • Respons: siapa melakukan apa, dan apakah rollback berjalan lancar.
  • Tindakan pencegahan: perubahan pada pipeline, observability, atau kapasitas.

Tindakan pencegahan konkret

  • Tambahkan preflight disk check yang lebih ketat.
  • Uji memory footprint release di staging dengan resource mirip production.
  • Pastikan release ID masuk ke log dan metrik.
  • Buat canary duration minimum sebelum rollout penuh.
  • Kurangi jumlah worker default untuk node dengan RAM kecil.
  • Pisahkan health check ringan dari pengecekan dependency yang mahal.
  • Atur retensi release, rotasi log, dan pembersihan file sementara.

Trade-off teknis yang perlu dipahami

Symlink release vs overwrite langsung

  • Symlink release: rollback cepat, state file lebih rapi, tetapi butuh disiplin struktur direktori.
  • Overwrite langsung: sederhana di awal, tetapi sulit rollback dan rawan file campur antar versi.

Artifact sangat kecil vs artifact lengkap

  • Sangat kecil: hemat transfer dan disk, tetapi perlu pemilihan file runtime yang presisi.
  • Lebih lengkap: lebih aman dari sisi kompatibilitas file, tetapi membebani storage dan ekstraksi.

Health check sederhana vs mendalam

  • Sederhana: cepat dan murah, cocok untuk server tua.
  • Mendalam: lebih akurat mendeteksi dependency gagal, tetapi berisiko menambah beban dan false negative saat komponen non-kritis bermasalah.

Rollback cepat vs database migration

Rollback aplikasi mudah jika perubahan bersifat backward-compatible. Tantangan terbesar justru database migration. Jika skema baru tidak kompatibel dengan kode lama, rollback aplikasi saja bisa gagal. Karena itu:

  • utamakan migration yang kompatibel dua arah selama masa transisi,
  • pisahkan deploy kode dari perubahan skema yang berisiko,
  • hindari migration berat tepat saat deploy pada server resource terbatas.

Penutup

Deploy aman di server tua bisa dicapai tanpa platform rumit. Fokuslah pada empat hal: artifact kecil yang dibangun di luar production, preflight check sebelum aktivasi, health check yang benar-benar mencerminkan kesiapan layanan, dan rollback cepat berbasis symlink release. Tambahkan observability minimum berupa log terstruktur, metrik CPU/RAM/disk, latency, error rate, serta alert sederhana yang actionable.

Jika Anda hanya mengambil satu prinsip dari artikel ini, ambillah yang ini: buat proses deploy yang mengurangi kerja di server target dan mempercepat keputusan rollback. Pada mesin lama, itu biasanya lebih berharga daripada otomatisasi yang terlihat canggih tetapi justru menambah beban dan titik gagal baru.