Kamal 2: Deploy Docker Tanpa Downtime, Tanpa Kubernetes

Foto oleh roger4336 on flickr
Kamal 2 adalah tool deployment dari Basecamp yang men-deploy container Docker ke server mana pun lewat SSH, tanpa control plane, etcd, atau networking cluster. Kamal menyasar ruang antara menjalankan satu perintah docker secara manual dan mengoperasikan cluster Kubernetes penuh, memberi tim kecil deploy tanpa downtime tanpa beban operasional sebesar itu.
Kamal 2 memakai reverse proxy khusus bernama kamal-proxy. Saat deploy, container baru dijalankan berdampingan dengan container lama, endpoint health check dipantau sampai container baru dinyatakan sehat, lalu traffic dialihkan secara atomik ke container itu dan request yang masih berjalan di container lama dikeringkan sebelum dihentikan.
Bisa, lewat fitur bernama accessory. Accessory dideklarasikan di file config/deploy.yml yang sama dengan aplikasi Anda tetapi dikelola secara terpisah lewat perintah kamal accessory. Accessory tidak mendapat rollout tanpa downtime, sehingga merestart accessory database menyebabkan koneksi terputus sebentar dan harus dijadwalkan dengan hati-hati.
Jalankan kamal app containers -q untuk melihat daftar tag image yang pernah dideploy dan masih tersimpan di server, lalu jalankan kamal rollback dengan tag yang ingin dikembalikan. Karena image sudah tersimpan lokal, rollback hampir secepat pergantian traffic saat deploy awal dan tidak memerlukan build ulang atau pull dari registry.
Kamal membaca nilai secret dari file lokal .kamal/secrets yang dikecualikan dari version control, dan hanya nama secret yang muncul di config/deploy.yml di bawah env.secret. File khusus destinasi seperti .kamal/secrets.production memungkinkan environment berbeda memakai nilai berbeda sambil menjaga nilai secret sepenuhnya di luar repository.

Foto oleh roger4336 on flickr
Kubernetes memang menyelesaikan masalah nyata, tetapi kebanyakan side project dan aplikasi produksi skala kecil tidak punya masalah sebesar itu. Yang mereka butuhkan sebenarnya hanya cara membangun image Docker, mendorongnya ke registry, dan menjalankannya di satu atau dua server tanpa downtime, tanpa perlu merawat control plane. Itulah celah yang diisi oleh Kamal 2.
Kamal adalah tool deployment dari Basecamp yang mengendalikan server yang sudah ada lewat SSH, dengan Docker biasa di baliknya. Versi 2 mengganti layer routing berbasis Traefik dengan reverse proxy khusus bernama kamal-proxy, yang akhirnya membuat rollout tanpa downtime dan rollback instan benar-benar praktis dijalankan di satu VPS. Panduan ini membahas satu siklus deployment lengkap: proxy, accessory, secrets, dan cara memulihkan rilis yang bermasalah.
Kubernetes layak dengan kompleksitasnya pada skala tertentu: banyak service, banyak tim, autoscaling di banyak node. Di bawah skala itu, control plane, etcd, dan layer networking hanya menambah beban operasional tanpa manfaat sepadan, dan kebanyakan developer solo atau tim kecil akhirnya menghabiskan lebih banyak jam belajar dialek YAML daripada merilis fitur. Kamal menyasar ruang di antara satu perintah docker run dan sebuah cluster penuh, mengambil bagian dari orkestrasi container yang benar-benar berguna untuk deployment kecil — build image, health check, dan restart yang terkoordinasi — sambil membuang bagian yang hanya bermanfaat pada skala besar.
Kamal tidak terikat pada satu framework. Dibangun untuk aplikasi Rails, tetapi bisa dipakai untuk aplikasi apa pun yang bisa dikemas jadi image Docker dan punya endpoint health check HTTP — Node, Next.js, Django, atau binary statis semuanya memenuhi syarat.
Semua yang dilakukan Kamal diatur oleh satu file YAML, config/deploy.yml, ditambah file secrets. Konfigurasi berikut menyasar satu server, membangun image, mendorongnya ke registry, dan mengatur kamal-proxy untuk mengarahkan traffic serta menjalankan health check ke aplikasi.
# config/deploy.yml
service: myapp
image: myregistry/myapp
servers:
web:
hosts:
- 203.0.113.10
labels:
traefik.http.routers.myapp.rule: Host(`myapp.example.com`)
proxy:
ssl: true
host: myapp.example.com
app_port: 3000
healthcheck:
path: /up
interval: 1
timeout: 5
registry:
server: ghcr.io
username: myuser
password:
- KAMAL_REGISTRY_PASSWORD
env:
clear:
NODE_ENV: production
secret:
- DATABASE_URL
- REDIS_URLBagian proxy adalah bagian yang paling penting. Kamal-proxy mengirim request GET ke path health check setiap satu detik, dan baru mengalihkan traffic ke container baru setelah menerima respons sukses. Traffic lama dikeringkan dari container sebelumnya sebelum dihentikan, itulah yang membuat pergantian ini tidak terasa oleh pengguna.
Menjalankan perintah deploy memicu urutan langkah yang penting dipahami, karena sebagian besar kegagalan deploy terjadi pada salah satu dari empat langkah ini, dan pesan error biasanya langsung menunjukkan langkah mana yang gagal. Membaca output Kamal baris demi baris pada beberapa deploy pertama Anda akan sangat membantu nantinya, karena Anda jadi tahu tahap mana — build, push, pull, atau health check — yang harus diperiksa saat suatu saat terjadi masalah di produksi.
| Perintah | Fungsinya | Kapan dijalankan |
|---|---|---|
| kamal setup | Menyiapkan Docker, kamal-proxy, dan direktori di server baru | Sekali saja, sebelum deploy pertama ke host baru |
| kamal deploy | Membangun, mendorong, dan merilis aplikasi tanpa downtime | Setiap kali rilis |
| kamal rollback | Mengembalikan ke tag image yang pernah dideploy sebelumnya | Segera setelah rilis bermasalah terdeteksi |
| kamal accessory boot | Menjalankan atau merestart service pendukung seperti database | Saat menyiapkan atau memperbarui container dependency |
Accessory adalah istilah Kamal untuk service pendukung yang dibutuhkan aplikasi tetapi bukan bagian dari rollout tanpa downtime — database, cache, queue. Semuanya dideklarasikan di file deploy.yml yang sama, tetapi dikelola dengan lifecycle terpisah lewat perintah kamal accessory, bukan kamal deploy. Pemisahan ini ada karena restart database secara mendasar berbeda dari restart aplikasi: Anda tidak bisa begitu saja menjalankan dua container Postgres berdampingan lalu mengalihkan traffic di antaranya seperti kamal-proxy mengalihkan antar container aplikasi, karena data itu sendiri berada di satu volume yang sama.
# config/deploy.yml
accessories:
postgres:
image: postgres:16
host: 203.0.113.10
port: "127.0.0.1:5432:5432"
env:
clear:
POSTGRES_DB: myapp
secret:
- POSTGRES_PASSWORD
directories:
- postgres-data:/var/lib/postgresql/data
redis:
image: redis:7
host: 203.0.113.10
port: "127.0.0.1:6379:6379"
directories:
- redis-data:/dataAccessory tidak mendapat update tanpa downtime. Merestart Postgres atau Redis lewat kamal accessory reboot menyebabkan koneksi terputus sebentar saat container direstart, jadi jadwalkan perubahan accessory di jam traffic rendah dan pastikan aplikasi Anda bisa mencoba ulang koneksi database yang terputus dengan baik.
Secara default Kamal membaca secrets dari file .kamal/secrets, yang sebaiknya tidak pernah dimasukkan ke git. File ini mendukung override per destinasi, jadi nilai di .kamal/secrets.production hanya berlaku saat deploy ke destinasi itu, sementara .kamal/secrets-common berlaku di semua tempat.
Setiap deploy menyisakan image container sebelumnya di server selama periode retensi tertentu, itulah yang membuat rollback cepat — tidak perlu build ulang atau pull dari registry. Cari dulu tag image yang ingin dikembalikan, lalu rollback langsung ke tag tersebut. Sebaiknya latih perintah ini di server staging sebelum benar-benar membutuhkannya di produksi, sehingga sintaks yang tepat dan tampilan daftar container sudah familiar saat insiden nyata terjadi dan setiap detik downtime sangat berarti.
# see exited containers from previous deploys
kamal app containers -q
# roll back to a specific image tag
kamal rollback abc1234
# roll a proxy restart across hosts one at a time
kamal proxy reboot --rollingKarena rollback memakai image yang sudah ditarik sebelumnya, prosesnya hampir secepat pergantian traffic saat deploy awal. Tidak ada langkah build dan tidak ada round trip ke registry, sehingga rilis bermasalah dari sepuluh menit lalu bisa dibatalkan dalam hitungan detik.
Untuk aplikasi yang berjalan di lebih dari satu host, secara default Kamal mendeploy ke semua server secara paralel, tetapi Anda bisa memilih strategi rolling agar hanya sebagian server yang diperbarui pada satu waktu, sementara sisanya tetap melayani traffic. Ini paling penting untuk maintenance level proxy, seperti merotasi sertifikat SSL atau memperbarui image proxy itu sendiri, di mana Anda ingin dampak yang benar-benar tidak terlihat meski infrastruktur di depan aplikasi Anda sedang direstart.
Mulailah dengan satu server meskipun Anda berencana scale out nanti. Format konfigurasi Kamal membuat penambahan host kedua atau ketiga hanya perubahan satu baris di daftar hosts — Anda tidak perlu merancang untuk multi server dari hari pertama.
Kamal 2 tidak akan menggantikan Kubernetes untuk platform besar dengan banyak tim, tetapi untuk sebagian besar side project, produk SaaS kecil, dan backend satu tim, ia menghilangkan satu kategori penuh kompleksitas operasional sambil tetap memberikan deploy tanpa downtime dan cerita rollback yang bersih, hal yang dulunya membutuhkan control plane untuk bisa dilakukan dengan benar. Jika Anda sudah punya VPS dan image Docker, cara tercepat untuk merasakan bedanya adalah menjalankan kamal setup sekali lalu menyaksikan deploy tanpa downtime pertama Anda selesai dalam waktu kurang dari satu menit.