Kamal Proxy, proksi HTTP minimal untuk deployment tanpa downtime
(github.com/basecamp)- Kamal Proxy adalah proksi HTTP kecil yang berjalan di depan aplikasi web, dirancang untuk mengalihkan deployment ke instance baru tanpa memutus trafik yang sedang berlangsung
- Instance baru didaftarkan dengan
kamal-proxy deploy, dan proksi merutekan trafik baru ke instance tersebut hanya setelah lolos HTTP health check - Perintah deployment menunggu hingga semua trafik pada instance lama selesai, sehingga setelah berhasil kembali, instance lama dapat dihapus tanpa menghentikan request yang sedang berlangsung
- Untuk menjalankan beberapa aplikasi pada satu proksi, tersedia routing berbasis host, routing berbasis path, TLS otomatis, serta kemampuan menentukan sertifikat TLS manual
- Kamal Proxy dirancang sebagai bagian dari alat deployment Kamal, tetapi juga dapat digunakan secara mandiri atau sebagai komponen alat deployment lain
Apa yang dilakukan Kamal Proxy
- Kamal Proxy adalah proksi HTTP kecil untuk mempermudah koordinasi deployment tanpa downtime
- Dengan menjalankan aplikasi web di belakang Kamal Proxy, perubahan dapat dideploy tanpa menghentikan trafik yang sedang berlangsung
- Tidak diperlukan kerja sama khusus dari sisi aplikasi untuk perilaku ini
- Kamal Proxy dirancang untuk berjalan sebagai bagian dari Kamal, yang mencakup packaging container dan provisioning
- Juga dapat digunakan secara mandiri atau sebagai bagian dari alat deployment lain
Alur menjalankan dan deployment
- Instance proksi dijalankan dengan perintah
kamal-proxy run - Tidak ada file konfigurasi; opsi dapat ditentukan ketika nilai default tidak sesuai untuk aplikasi
- Port HTTP default adalah
80 - Untuk menjalankan di port lain, gunakan
kamal-proxy run --http-port 8080 - Opsi lengkap dapat dilihat di
kamal-proxy help run
- Port HTTP default adalah
- Untuk mengirim trafik ke aplikasi web, instance aplikasi di-deploy ke proksi
- Instance target deployment ditentukan dalam format
hostname:port- Contoh:
kamal-proxy deploy service1 --target web-1:3000 - Perintah ini mendaftarkan
web-1:3000dengan nama layananservice1
- Contoh:
Cara peralihan tanpa downtime
- Saat instance baru didaftarkan, Kamal Proxy langsung menjalankan HTTP health check untuk memeriksa apakah instance dapat diakses dan berfungsi
- Jika health check berhasil, proksi mulai merutekan trafik baru ke instance baru
- Jika instance baru tidak menjadi healthy dalam waktu yang sesuai, perintah
deploymenghentikan deployment dan mengembalikan kode keluar non-nol - Setiap deployment memindahkan seluruh trafik dari instance yang sebelumnya dideploy ke instance baru
- Perintah
deploymenunggu hingga semua trafik keluar dari instance lama, lalu kembali- Setelah perintah berhasil kembali, instance lama dapat dihapus tanpa memutus request yang sedang berlangsung
- Karena instance baru hanya menerima trafik saat dalam status healthy, dan instance lama dihapus setelah sepenuhnya di-drain, deployment berjalan dengan tanpa downtime
Pengaturan health check
- Health check default mengirim request
GETke/upsekali per detik untuk setiap layanan - Respons
200dianggap sebagai status healthy - Untuk mengubah health check agar sesuai dengan aplikasi, gunakan flag
deploy--health-check-path--health-check-port--health-check-timeout--health-check-interval
- Contoh mengubah path health check:
kamal-proxy deploy service1 --target web-1:3000 --health-check-path web/index.html
- Jika endpoint health diekspos pada port yang berbeda dari layanan utama:
kamal-proxy deploy service1 --target web-1:3000 --health-check-port 8080
Fitur routing
-
Routing berbasis host
- Routing berbasis host memungkinkan satu instance Kamal Proxy merutekan trafik ke beberapa aplikasi pada server yang sama
- Host tertentu dapat ditentukan saat deployment
kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com- Instance yang dideploy dengan cara ini hanya menerima trafik untuk host yang ditentukan
- Dengan menentukan host terpisah untuk setiap aplikasi, beberapa aplikasi dapat berjalan di server yang sama tanpa konflik port
- Satu host tertentu hanya dapat dirutekan ke satu layanan pada satu waktu
- Jika
service1sudah menggunakanapp1.example.com, error akan dikembalikan saatservice2dideploy dengan host yang sama - Setelah
service1dihapus,service2dapat dideploy ke host yang sama
-
Routing berbasis path
- Routing berbasis path digunakan untuk aplikasi yang membagi trafik ke layanan berbeda berdasarkan path request
- Layanan dapat di-mount di bawah prefiks path yang berbeda
- Contoh mengirim request yang dimulai dengan
/apikeweb-1:kamal-proxy deploy service1 --target web-1:3000 --path-prefix=/api - Contoh mengirim sisanya ke
web-2:kamal-proxy deploy service2 --target web-2:3000 - Secara default, prefiks path dihapus sebelum diteruskan ke upstream
- Request
/api/users/123diteruskan keweb-1sebagai/users/123 - Untuk meneruskan path asli apa adanya, tentukan
--strip-path-prefix=false
Dukungan TLS
- Kamal Proxy dapat memperoleh dan memperbarui sertifikat TLS untuk aplikasi secara otomatis
- TLS otomatis diaktifkan dengan menambahkan flag
--tlssaat deploymentkamal-proxy deploy service1 --target web-1:3000 --host app1.example.com --tls
- TLS otomatis memerlukan host yang ditentukan
- Ini adalah syarat untuk mencegah permintaan sertifikat secara berbahaya untuk nama host sembarang
- Pada routing berbasis path, opsi TLS harus diatur pada path root
- Layanan yang dideploy pada path lain di host yang sama menggunakan pengaturan TLS yang ditentukan pada path root
- Jika perlu memasang sertifikat TLS yang diperoleh secara manual, certificate authority sendiri, atau Cloudflare origin certificate, path file sertifikat dan private key dapat ditentukan langsung
--tls-certificate-path cert.pem--tls-private-key-path key.pem
Variabel lingkungan dan build
- Dalam lingkungan seperti menjalankan container Docker, opsi
rundapat ditentukan sebagai variabel lingkungan kamal-proxy runmembaca nilai setiap opsi dari variabel lingkungan jika variabel tersebut disetelkamal-proxy run --http-port 8080HTTP_PORT=8080 kamal-proxy run
- Jika nama variabel lingkungan bertabrakan dengan lingkungan yang sudah ada, prefiks
KAMAL_PROXY_dapat ditambahkan untuk membedakannyaKAMAL_PROXY_HTTP_PORT=8080 kamal-proxy run
- Build lokal dilakukan dengan
makepada lingkungan Go yang berfungsi - Untuk build dengan container Docker, gunakan
make docker - Konfigurasi Docker Compose untuk mencoba perintah proksi tersedia di folder
example
1 komentar
Komentar Hacker News
Agak aneh memilih deploy sebagai nama operasinya
Itu sudah istilah yang terlalu sarat makna, jadi terasa bisa menimbulkan kebingungan seperti “aplikasinya yang di-deploy? atau ke proxy yang di-deploy?”
Padahal bisa saja memakai kata seperti
bind,intercept, atau cukupproxy, jadi kurang paham kenapa harusdeploySekarang ini zero-downtime deployment juga bisa dilakukan dengan mudah lewat server lain, jadi menarik bahwa ini dijadikan satu aplikasi terpisah
Misalnya, aplikasi + web proxy yang mendukung Unix socket bisa melakukan ini tanpa downtime hanya dengan memindahkan file
Sifatnya atomik, dan permintaan pemanasan juga bisa dikirim dengan
curlMembangun sampai sistem registrasi terasa berlebihan
Kamal adalah alat deployment yang dipakai untuk pindah dari cloud ke hardware sendiri dan menghemat jutaan dolar(https://basecamp.com/cloud-exit)
Kalau ada tulisan rujukan, saya ingin mempelajarinya lebih jauh
Ini tampaknya terutama berusaha menangani masalah mendasar putusnya trafik saat mengganti container layanan di Docker Swarm
Kami mengalami masalah yang sama saat membuat server JAMStack di Cloud 66, dan memakai Caddy alih-alih proxy buatan sendiri; Traefik juga sepertinya akan cukup cocok
Saya tidak tahu kenapa Kamal memilih Swarm alih-alih k8s atau k3s, tetapi kompleksitas pasti harus ditempatkan di suatu tempat dan tidak bisa disembunyikan, jadi pada akhirnya tampaknya mereka memilih proxy buatan sendiri
Saya belum mencobanya sendiri, tetapi cukup skeptis karena rasanya akan terus dikejar-kejar dukungan untuk WebSockets, SSE, HTTP/3, berbagai kompresi, dan enkripsi
Ini terlihat seperti contoh reverse proxy yang awalnya sederhana tetapi akhirnya terus menyerap kompleksitas yang tadinya ingin dihindari
Saya pikir sistem eksekusi yang luas dan dapat diperluas memang perlu pesaing, tetapi Kamal tampak seperti pekerjaan mundur ke arah kompleksitas yang justru ingin dihindarinya
Itu malah semakin menonjolkan kemampuan dan fleksibilitas Kubernetes sebagai kerangka kerja manajemen desired state
Anda tetap bisa terus memakai Docker sambil menggunakan Caddy, Traefik, atau Envoy sebagai proxy
Kubernetes pada akhirnya juga sering memakai mereka sebagai ingress controller
Dari yang saya lihat, sepertinya tidak memakai Swarm
docker runbiasa, dan tidak ada Swarm maupun orkestrasiPada dasarnya ini alat sederhana pengganti Capistrano
Dasar dari layanan orkestrasi container adalah menangani koneksi dan deployment biru/hijau lewat ingress controller
Lebih tepatnya, nama peran yang diberikan kepada banyak reverse proxy yang sudah menangani kasus penggunaan ini selama bertahun-tahun, bahkan puluhan tahun, adalah ingress controller
Akan bagus kalau ada yang bisa menjelaskan secara singkat bagaimana zero-downtime deployment biasanya bekerja
Saya menduga strukturnya adalah dua versi aplikasi berjalan bersamaan dan trafik baru diarahkan ke versi baru
Tetapi jika memakai satu database yang sama dan versi aplikasi baru membawa perubahan skema, skrip migrasi saat startup akan mengubah skema itu sementara versi aplikasi lama masih mengharapkan skema lama
Saya penasaran bagaimana ini biasanya ditangani
Banyak framework menjalankan migrasi saat deployment kode, tetapi dalam praktiknya lebih baik mengendalikan waktunya secara manual
Setiap versi kode harus bisa berjalan baik dengan skema saat ini maupun skema setelah migrasi di masa depan, sehingga pada dasarnya menjadi kode yang kompatibel ke belakang
Alurnya menjadi “deploy kode baru yang bekerja dengan skema saat ini/masa depan → verifikasi → jalankan migrasi → verifikasi → bersihkan kode yang menangani skema yang sudah hilang”
Ini biaya tambahan yang harus dibayar untuk zero-downtime deployment atau rolling deployment, dan perusahaan besar umumnya memang melakukannya seperti ini
Apalagi jika penggunanya berada dalam satu wilayah tertentu dan Anda bisa memilih jam yang sepi untuk deployment
Dua versi aplikasi bisa berjalan bersamaan
https://xata.io/blog/multi-version-schema-migrations
Load balancer mulai menerima koneksi di Server2 dan berhenti menerima koneksi baru di Server1
Setelah semua koneksi di Server1 tertutup, barulah Server1 diputus
Ini bisa berupa server yang berbeda, atau beberapa worker dalam satu server
Selama periode itu, seperti jawaban-jawaban lain jelaskan, migrasi harus kompatibel ke belakang
Kamal 2 saat ini masih RC(https://github.com/basecamp/kamal/releases), dan tampaknya akan mendukung SSL otomatis, jadi saya menantikan kemudahan menjalankan beberapa aplikasi dengan Kamal di satu server
autocert, tetapi ini terasa seperti implementasi yang sangat minimalRentan, dan karena batas penerbitan Let's Encrypt serta batas sertifikat bersamaan, sulit untuk melakukan scale-out horizontal pada instance proxy
Caddy/Certmagic menyelesaikan masalah ini dengan menulis data ke penyimpanan bersama, sehingga hanya satu sertifikat yang diterbitkan dan semua instance dapat menggunakan ulang serta berkoordinasi lewat penyimpanan itu
Tidak ada pengganti issuer, penghindaran batas penerbitan, atau dukungan ARI
Soal menahan request sampai upstream siap juga ditangani dengan baik oleh Caddy jika mengatur
try_durationdantry_intervalpadareverse_proxyPenanganan header proxy juga tidak mempertimbangkan IP tepercaya, jadi jika diaktifkan, seseorang bisa memalsukan IP dengan menetapkan
X-Forwarded-ForUntungnya default-nya nonaktif, tetapi juga tidak ada peringatannya
Saya paham tujuannya adalah kesederhanaan, tetapi dalam kondisi sekarang rasanya belum matang, dan ada terlalu banyak pilihan yang lebih baik sehingga saya tidak ingin memakainya di dunia nyata
Saya tidak begitu paham cara memakai ini dan rasanya ada yang saya lewatkan
Contohnya memulai 4 replika layanan
webJika kita bisa membuat layanan dengan men-deploy ke satu replika seperti
example-web-1, saya tidak paham tiga replika lainnya dipakai untuk apaUntuk memperbarui
webagar deployment tanpa downtime bisa dilakukan, sepertinya kita harus menjalankan perintah build pada layananweb, lalu menyalakan layanan ini dengan suatu cara, kemudian menjalankan deploy terhadap target baruTetapi jika menjalankan
docker compose up --build --force-recreate web, replika lama akan dimatikan sehingga semuanya jadi tidak berartiSaya belum mengecek apakah proxy ini menyeimbangkan beban ke beberapa record yang dikembalikan dari request DNS, tetapi setidaknya kalau load balancing berbasis VIP, seharusnya bekerja seperti yang diharapkan
Bagian pembaruan kedua kurang jelas
Mungkin yang diharapkan adalah menjalankan layanan dengan nama berbeda di jaringan yang sama lalu melakukan
kamal-proxy deployBisa saja nama layanannya menyertakan nomor versi, dan jika ingin rollback cepat, masuk akal juga menjaga versi sebelumnya tetap hangat
[0]: https://docs.docker.com/reference/compose-file/deploy/#endpo...
k8s rollout restart deploymentAtau cukup alihkan DNS atau router antara dua backend
Saya penasaran apakah ini mengimplementasikan pola traffic pausing
Proxy pada dasarnya menghentikan lalu lintas selama beberapa detik, sehingga request yang masuk terlihat memakan waktu beberapa detik lebih lama dari biasanya, tetapi selesai setelah jeda singkat
Dalam beberapa detik itu, Anda bisa menjalankan migrasi DB kecil atau perubahan infrastruktur yang lebih rumit namun bersifat blocking selama masih bisa selesai dalam 5 detik
Terdengar cukup berisiko, dan walau saya sudah beberapa tahun bekerja di perusahaan app server, ini pertama kalinya saya mendengar pola ini
Meski begitu, kalau ini datang dari salah satu pendiri Django, sulit juga untuk langsung mengabaikannya
Saya ingat pernah membicarakan topik ini sebelumnya
Saya penasaran di mana dijelaskan alasan memilih membuat proxy sendiri alih-alih memakai Traefik atau alat lain yang sudah terbukti
Ada konteks di PR tentang kenapa mereka mengubahnya dan memutuskan membuat implementasi sendiri
https://github.com/basecamp/kamal/pull/940
Tetapi sepertinya belum pernah ada perbandingan resmi dengan opsi lain selain Traefik
Saya penasaran apakah ada cara untuk mengatur timeout
https://github.com/basecamp/kamal-proxy/blob/main/internal/s...
https://github.com/basecamp/kamal-proxy/blob/main/internal/s...
https://blog.cloudflare.com/exposing-go-on-the-internet/
Ini NIH. Tidak ada lagi yang perlu ditambahkan