Laravel zero-downtime deploy bukan berarti tidak pernah ada gangguan sama sekali, tetapi merancang proses rilis agar perpindahan versi aplikasi terjadi secepat mungkin, dapat dipantau, dan mudah dibatalkan jika ada masalah. Untuk mayoritas proyek Laravel di server Linux/VPS atau container sederhana, target realistisnya adalah downtime sangat kecil, perubahan yang terukur, dan rollback yang cepat.
Masalah paling umum saat deploy Laravel biasanya bukan pada perintah git pull itu sendiri, melainkan pada langkah pendukung: migrasi database yang memutus kompatibilitas, queue worker yang masih menjalankan kode lama, cache yang tidak sinkron, symlink storage yang berubah, atau health check yang tidak pernah diverifikasi. Artikel ini membahas alur deploy yang aman dan umum diterapkan tanpa bergantung pada platform tertentu.
Mengapa deploy Laravel sering gagal saat trafik nyata
Pada lingkungan pengembangan, deploy tampak sederhana. Namun di produksi, aplikasi sedang menerima request, worker sedang memproses job, dan database dipakai oleh versi aplikasi yang sedang aktif. Begitu versi baru dirilis, semua komponen itu harus tetap konsisten.
- Kode baru butuh skema database baru, tetapi migrasi belum selesai.
- Worker queue masih hidup dan menjalankan kode lama terhadap data yang sudah berubah.
- Cache konfigurasi atau route masih berasal dari rilis sebelumnya.
- Dependency atau asset belum lengkap saat request pertama masuk.
- Tidak ada health check, jadi aplikasi dianggap sehat hanya karena proses web server masih berjalan.
Prinsip utama deploy minim downtime adalah: siapkan rilis baru secara terpisah, aktifkan dengan perpindahan atomik atau cepat, verifikasi kesehatan aplikasi, lalu rollback segera jika indikator memburuk.
Checklist pra-deploy yang wajib ada
Sebelum menyentuh server produksi, pastikan beberapa hal berikut jelas. Checklist ini lebih penting daripada script deploy yang tampak canggih.
1. Pastikan rilis bisa direproduksi
- Commit yang akan dirilis sudah final dan dapat ditelusuri.
- Dependency PHP dan frontend terkunci melalui lock file.
- Environment production tidak bergantung pada file lokal yang dibuat manual.
2. Tinjau perubahan database
Ini bagian paling berisiko. Usahakan migrasi bersifat backward compatible selama masa transisi deploy.
- Tambah kolom baru biasanya lebih aman daripada mengganti atau menghapus kolom yang dipakai kode lama.
- Jika perlu rename atau drop kolom, lakukan bertahap dalam dua rilis.
- Hindari migrasi berat di jam sibuk jika berpotensi mengunci tabel lama.
Praktik aman: expand and contract. Rilis pertama menambah struktur baru tanpa merusak yang lama. Setelah aplikasi stabil dan data dipindahkan, rilis berikutnya baru menghapus struktur lama.
3. Pastikan queue dan scheduler dipahami dampaknya
- Worker queue perlu diminta restart agar memuat kode baru.
- Job yang lama mungkin masih diproses beberapa detik atau menit setelah deploy.
- Jika payload job berubah format, pastikan worker lama masih bisa menangani transisi.
4. Siapkan observability minimum
- Log Laravel dapat diakses.
- Log web server atau reverse proxy dapat diakses.
- Ada cara melihat lonjakan error HTTP 5xx dan peningkatan latensi.
5. Siapkan rollback sebelum deploy dimulai
Rollback bukan langkah improvisasi. Anda perlu tahu:
- Rilis sebelumnya ada di mana.
- Bagaimana mengembalikan symlink atau image container ke versi lama.
- Apakah migrasi yang baru dijalankan aman terhadap versi lama.
Struktur rilis yang aman di Linux/VPS atau container sederhana
Pola umum yang cukup andal di server Linux adalah memisahkan direktori release dari direktori aktif. Misalnya:
/var/www/myapp/
├── current -> /var/www/myapp/releases/20240610-101500
├── releases/
│ ├── 20240609-221000
│ └── 20240610-101500
└── shared/
├── .env
└── storage/Rilis baru disiapkan di folder baru, dependency diinstal, cache dibangun, lalu current dipindahkan ke release baru. Dengan pendekatan ini, waktu perpindahan versi menjadi sangat singkat karena bukan menyalin file satu per satu ke direktori aktif.
Di container sederhana, prinsipnya sama: bangun image baru lebih dulu, jalankan instance baru, lakukan health check, lalu alihkan trafik. Detail teknisnya bisa berbeda, tetapi konsep prepare first, switch later, verify immediately tetap sama.
Script deploy sederhana untuk Laravel
Contoh berikut bukan framework deploy lengkap, tetapi cukup menunjukkan urutan yang aman. Sesuaikan path, user, dan perintah service di server Anda.
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="/var/www/myapp"
RELEASES_DIR="$APP_DIR/releases"
SHARED_DIR="$APP_DIR/shared"
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
NEW_RELEASE="$RELEASES_DIR/$TIMESTAMP"
PHP_BIN="php"
COMPOSER_BIN="composer"
mkdir -p "$NEW_RELEASE"
git clone --depth=1 [email protected]:myapp.git "$NEW_RELEASE"
cd "$NEW_RELEASE"
$COMPOSER_BIN install --no-dev --prefer-dist --no-interaction --optimize-autoloader
ln -sfn "$SHARED_DIR/.env" .env
rm -rf storage
ln -sfn "$SHARED_DIR/storage" storage
$PHP_BIN artisan config:clear
$PHP_BIN artisan route:clear
$PHP_BIN artisan view:clear
$PHP_BIN artisan cache:clear
# Jalankan migrasi setelah kode siap, tetapi sebelum switch trafik jika kompatibel.
$PHP_BIN artisan migrate --force
$PHP_BIN artisan config:cache
$PHP_BIN artisan route:cache
$PHP_BIN artisan view:cache
ln -sfn "$NEW_RELEASE" "$APP_DIR/current"
cd "$APP_DIR/current"
$PHP_BIN artisan queue:restart
$PHP_BIN artisan optimize:clear
$PHP_BIN artisan config:cache
$PHP_BIN artisan route:cache
$PHP_BIN artisan view:cacheAda beberapa hal penting dari urutan di atas:
- Dependency dan file release disiapkan dulu, sehingga aplikasi lama tetap melayani trafik.
- Shared storage dan .env dipisahkan dari release agar tidak hilang saat ganti versi.
- Migrasi dijalankan dengan
--forceuntuk mode non-interaktif di production. queue:restartdipanggil setelah release aktif agar worker berhenti secara terkontrol dan memuat kode baru.
Jika migrasi Anda tidak backward compatible, menjalankannya sebelum switch release bisa membuat kode lama gagal. Dalam kondisi itu, desain migrasinya yang perlu diperbaiki, bukan hanya urutan script-nya.
Maintenance mode: kapan perlu, kapan tidak
Untuk deploy Laravel minim downtime, maintenance mode tidak selalu perlu. Jika rilis hanya mengganti kode aplikasi dan migrasi aman, Anda bisa menghindari maintenance mode penuh. Namun maintenance mode tetap berguna pada situasi tertentu:
- Perubahan data besar yang harus konsisten total.
- Operasi satu kali yang tidak aman jika request tetap masuk.
- Insiden deploy yang butuh menghentikan write sementara.
Jika harus dipakai, buat durasinya singkat dan terukur. Jangan jadikan maintenance mode sebagai solusi default untuk menutupi proses deploy yang lambat.
php artisan down
# lakukan langkah kritikal secepat mungkin
php artisan upJika aplikasi berada di belakang load balancer atau reverse proxy, maintenance yang terlalu lama justru memperbesar dampak terhadap pengguna. Lebih baik memperbaiki desain deploy daripada sering mengandalkan mode down.
Migrasi database yang aman saat deploy
Prinsip dasar
Migrasi paling aman adalah migrasi yang tetap kompatibel dengan kode lama dan kode baru selama masa transisi. Contoh aman:
- Menambah kolom nullable.
- Menambah tabel baru tanpa mengubah alur lama.
- Menambah index untuk kebutuhan performa.
Contoh yang perlu hati-hati:
- Rename kolom yang masih dibaca kode lama.
- Mengubah tipe data pada tabel besar.
- Drop kolom yang masih dipakai job queue lama.
Pola dua tahap
- Rilis 1: tambah kolom/tabel baru, aplikasi menulis ke format lama dan baru jika perlu.
- Backfill: pindahkan data lama ke struktur baru secara bertahap.
- Rilis 2: aplikasi membaca dari struktur baru saja.
- Rilis 3: hapus struktur lama setelah benar-benar tidak dipakai.
Pola ini memang lebih lambat dibanding migrasi sekali jalan, tetapi jauh lebih aman untuk aplikasi yang melayani trafik nyata.
Queue worker, scheduler, dan proses latar belakang
Salah satu kesalahan umum pada deploy Laravel adalah menganggap web request sudah menggunakan kode baru, padahal worker queue masih memakai proses lama di memori. Akibatnya, bug hanya muncul pada job async, bukan pada request biasa.
Restart worker setelah release aktif
php artisan queue:restartPerintah ini memberi sinyal kepada worker agar berhenti setelah job yang sedang berjalan selesai, lalu supervisor atau process manager akan menjalankannya kembali dengan kode baru.
Hal yang perlu diperhatikan:
- Jika ada job sangat lama, worker mungkin baru restart beberapa menit kemudian.
- Pastikan process manager benar-benar menjalankan ulang worker.
- Jika struktur payload job berubah, pikirkan kompatibilitas antarversi.
Scheduler
Scheduler biasanya memanggil schedule:run secara periodik. Pastikan command yang dijadwalkan tidak bergantung pada file sementara dari release lama, dan gunakan path current agar cron selalu mengarah ke rilis aktif.
Cache Laravel: apa yang perlu dibangun ulang
Cache bisa mempercepat boot aplikasi, tetapi juga bisa menjadi sumber deploy gagal jika tidak dikelola dengan benar.
- config cache: penting jika production memuat banyak konfigurasi.
- route cache: berguna untuk route yang stabil.
- view cache: aman untuk dibangun ulang saat release.
Urutan umum yang aman adalah membersihkan cache lama pada release baru, lalu membangun cache setelah file dan dependency siap.
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan view:cacheKesalahan umum:
- Mem-cache konfigurasi sebelum
.envtersedia. - Mengira perubahan environment langsung terbaca padahal config cache masih lama.
- Mengaktifkan route cache padahal ada definisi route yang tidak kompatibel dengan mekanisme caching.
Health check aplikasi dan smoke test pascadeploy
Deploy belum selesai ketika symlink sudah berpindah. Anda perlu memverifikasi bahwa aplikasi benar-benar sehat, bukan sekadar memberi respons HTTP.
Endpoint health check sederhana
Buat endpoint yang ringan dan tidak mahal. Minimal bisa memeriksa bahwa aplikasi berhasil bootstrap. Jika ingin lebih ketat, tambahkan pengecekan koneksi database atau cache, tetapi jangan membuat endpoint ini terlalu berat.
// routes/web.php atau routes/api.php
Route::get('/health', function () {
return response()->json(['status' => 'ok'], 200);
});Untuk kebutuhan produksi, sering lebih baik memisahkan:
- liveness: proses aplikasi masih hidup.
- readiness: aplikasi siap menerima trafik dengan dependency penting tersedia.
Jika semua pemeriksaan ditumpuk ke satu endpoint, false alarm bisa meningkat atau endpoint menjadi lambat.
Contoh smoke test pascadeploy
curl -fsS http://127.0.0.1/health
curl -I -fsS https://app.example.com/
curl -I -fsS https://app.example.com/loginSmoke test sebaiknya memeriksa jalur yang paling kritikal:
- Homepage atau landing route utama.
- Halaman login atau endpoint autentikasi.
- Satu endpoint API penting.
- Jika relevan, enqueue satu job kecil dan pastikan worker memprosesnya.
Jika health check sukses tetapi error 500 meningkat pada endpoint bisnis utama, deploy tetap harus dianggap gagal. Health check hanya sinyal awal, bukan bukti final bahwa semua baik-baik saja.
Kapan harus rollback
Rollback yang baik dilakukan cepat, berbasis indikator, dan tidak menunggu insiden membesar. Beberapa tanda kuat untuk rollback:
- Lonjakan error 5xx segera setelah release aktif.
- Latensi naik tajam pada endpoint penting.
- Worker queue gagal memproses job dan backlog terus bertambah.
- Error database baru muncul dan berkaitan dengan skema atau query versi baru.
- Smoke test gagal pada jalur kritikal.
Jangan menunda rollback hanya karena deploy “hampir benar”. Jika pengguna sudah terdampak dan akar masalah belum jelas, mengembalikan layanan ke versi stabil biasanya lebih bijak.
Cara rollback cepat
Jika Anda memakai struktur release + symlink, rollback biasanya hanya memindahkan current ke release sebelumnya.
PREVIOUS_RELEASE="/var/www/myapp/releases/20240609-221000"
ln -sfn "$PREVIOUS_RELEASE" /var/www/myapp/current
cd /var/www/myapp/current
php artisan queue:restart
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan view:cacheNamun rollback kode tidak selalu berarti rollback database. Ini sebabnya migrasi backward compatible sangat penting. Jika release baru sudah menjalankan migrasi yang merusak kompatibilitas, maka rollback kode saja bisa gagal total.
Di lingkungan container, rollback setara dengan mengalihkan trafik kembali ke image atau revision sebelumnya yang sudah diketahui stabil.
Kesalahan umum saat rollback
- Tidak menyimpan beberapa release sebelumnya.
- Lupa restart worker setelah rollback.
- Menghapus release lama terlalu cepat.
- Menganggap rollback database itu aman dan instan, padahal bisa lebih berisiko daripada masalah awal.
Observability dasar: log Laravel, web server log, dan metrik error/latensi
Tanpa observability, deploy berubah menjadi tebak-tebakan. Minimum yang perlu tersedia adalah log aplikasi, log akses/error dari web server, dan gambaran sederhana tentang error rate serta latensi.
Log Laravel
Periksa log aplikasi segera setelah deploy, terutama beberapa menit pertama.
tail -f storage/logs/laravel.logYang dicari:
- Exception berulang.
- Error koneksi database, Redis, atau filesystem.
- Class atau config yang tidak ditemukan.
- Error job queue setelah restart worker.
Log web server atau reverse proxy
Log ini membantu melihat apakah error berasal dari aplikasi atau dari lapisan HTTP di depannya.
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.logPath log tergantung setup Anda. Intinya, cocokkan timestamp antara error aplikasi dan lonjakan 502/504/500 dari web server.
Metrik minimum yang sebaiknya dipantau
- Error rate: persentase 5xx atau jumlah exception per menit.
- Latency: respons endpoint penting melambat atau timeout.
- Queue backlog: jumlah job menumpuk setelah deploy.
- Resource host: CPU, memori, disk, dan I/O jika deploy melibatkan kompilasi atau cache besar.
Anda tidak harus punya sistem observability besar untuk mulai disiplin. Bahkan kombinasi log, beberapa endpoint health, dan pengecekan metrik sederhana sudah jauh lebih baik daripada deploy tanpa umpan balik.
Urutan deploy yang praktis dan aman
- Validasi commit yang akan dirilis dan hasil test dasar.
- Siapkan release baru di direktori terpisah atau image baru.
- Install dependency dan pasang symlink ke
.envsertastorage. - Clear cache lama pada release baru.
- Jalankan migrasi yang aman dengan
php artisan migrate --force. - Bangun cache config, route, dan view.
- Alihkan release aktif.
- Restart queue worker.
- Jalankan health check dan smoke test.
- Pantau log, error rate, latensi, dan queue backlog.
- Rollback segera jika indikator memburuk dan penyebab belum dapat diperbaiki cepat.
Debugging cepat saat deploy bermasalah
Gejala: 500 segera setelah switch release
- Periksa
laravel.log. - Pastikan
.envtersambung ke release baru. - Clear lalu build ulang config cache.
- Pastikan permission pada
storagedanbootstrap/cachebenar.
Gejala: request normal sehat, tapi job queue gagal
- Pastikan
queue:restartsudah dipanggil. - Periksa process manager benar-benar memulai worker baru.
- Lihat apakah payload job lama tidak kompatibel dengan kode baru.
Gejala: endpoint lambat setelah deploy
- Periksa query baru yang berat.
- Lihat apakah cache belum dibangun.
- Cocokkan lonjakan latensi dengan migrasi atau lock database.
Postmortem ringan setelah insiden deploy
Jika deploy sempat menyebabkan gangguan, jangan berhenti di rollback. Buat postmortem singkat agar masalah serupa tidak berulang. Tidak perlu panjang, tetapi harus spesifik.
Format sederhana
- Apa yang berubah? Commit, migrasi, config, atau dependency apa yang dirilis.
- Apa dampaknya? Endpoint mana gagal, berapa lama, siapa terdampak.
- Bagaimana terdeteksi? Health check, log, alarm, atau laporan pengguna.
- Akar masalah? Misalnya migrasi tidak kompatibel, worker tidak restart, atau config cache stale.
- Perbaikan langsung? Rollback, hotfix, atau pembatasan trafik.
- Tindakan pencegahan? Tambah smoke test, ubah pola migrasi, otomatisasi restart worker, atau tambah alert.
Tindakan pencegahan yang paling bernilai
- Wajibkan review khusus untuk migrasi database.
- Tambahkan smoke test minimal pada jalur bisnis kritikal.
- Buat endpoint health check yang benar-benar dipakai saat deploy.
- Simpan beberapa release terakhir untuk rollback cepat.
- Pastikan cron, worker, dan script operasional selalu menunjuk ke path
current. - Jangan gabungkan terlalu banyak perubahan besar dalam satu deploy.
Penutup
Laravel zero-downtime deploy yang efektif tidak bergantung pada tool tertentu, melainkan pada disiplin alur rilis: siapkan release terpisah, desain migrasi yang aman, restart worker dengan benar, bangun cache secara tepat, verifikasi health check dan smoke test, lalu pantau log serta metrik sesudah rilis. Jika ada masalah, rollback harus bisa dilakukan dalam hitungan menit, bukan jam.
Untuk banyak proyek Laravel di VPS atau container sederhana, kombinasi release terpisah + migrasi kompatibel + observability dasar sudah cukup untuk memangkas risiko deploy secara signifikan. Mulailah dari alur yang sederhana tetapi konsisten, lalu tingkatkan otomatisasi setelah proses dasarnya benar.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!