我使用的 VPS 部署神器 Kamal2 入門指南

現在,我使用的全端框架主要是 Next.js 16 和 Rails 8。透過使用 Rails,我接觸到了官方推薦的部署工具 Kamal。平時用它在 RN 和阿里雲伺服器上部署專案。用起來很順手和簡單,現在我想給大家也介紹一下 Kamal2 的概念和入門使用方法。
這篇文章不會一開始就講太複雜的內容。我更想先把 Kamal2 最核心的東西講清楚:它到底是什麼、能幫我們做什麼、最基本怎麼上手,以及平時最常用的操作有哪些。最後,我會給一個 Next.js 的使用案例,幫助你把前面的概念落到具體專案裡。
Kamal2 是什麼
如果用一句話概括,Kamal2 就是一個透過 SSH + Docker 來完成應用部署的工具。它不提供像 Heroku 那樣的完整平台能力,也不是 Kubernetes 這種重量級編排系統;它更像是把「部署一組 Docker 容器」這件事整理成一套可重複執行的命令和配置。
Kamal 的核心思路其實很直白:
本地有一個標準 Dockerfile。
用
config/deploy.yml描述部署目標和映像資訊。透過 SSH 連到伺服器,在伺服器上準備 Docker 環境。
本地建構映像並推送到映像倉庫,再讓伺服器去拉取並執行。
用
kamal-proxy接住 80 和 443 埠,在新容器健康檢查通過後切流量。
這也是我比較喜歡 Kamal 的地方。它沒有引入太多額外抽象,你大概知道它在做什麼,所以出了問題也比較容易排查。
Kamal2 適合什麼場景
我覺得 Kamal 特別適合下面這種情況:
你已經在用 Docker 打包應用。
你有一台或幾台自己的 Linux 伺服器。
你希望部署流程盡量簡單,不想維護一套複雜平台。
你希望 Rails、Next.js、甚至別的 Web 服務都能用同一套部署方式。
換句話說,Kamal 不是幫你「取代 Docker」,而是幫你把 Docker 部署變得更順手。
先理解幾個基本概念
正式開始之前,我建議先記住 Kamal 裡最重要的幾個概念。
config/deploy.yml
這是 Kamal 的主配置文件,部署配置就是從這裡讀取的。你可以把它理解為「這次部署的說明書」:服務名、映像名、伺服器列表、映像倉庫、環境變數、builder、proxy 等內容都寫在這裡。
.kamal/secrets
這是 secrets 檔案的預設位置,Kamal 會從這裡讀取敏感變數。比如映像倉庫密碼,或者 Rails 的 RAILS_MASTER_KEY,通常都不會直接硬編碼在 deploy.yml 裡,而是透過 .kamal/secrets 來注入。
kamal setup
這是首次部署最重要的一條命令。文件裡寫得很清楚,它會連線伺服器、安裝 Docker(如果沒有)、登入映像倉庫、建構映像、推送映像、拉取映像、啟動 kamal-proxy、啟動新容器,並在 GET /up 返回 200 OK 後切換流量。
kamal deploy
這是後續發版最常用的命令。首次 setup 跑通之後,後面的部署通常就用 kamal deploy 完成。
怎麼安裝 Kamal2
如果你本地已經有 Ruby 環境,最直接的安裝方式就是:
gem install kamal這是官方文件給出的標準安裝方式。如果沒有 Ruby,也可以跑容器化的 Kamal,但官方明確提到這種方式會有一些限制,所以入門階段我更推薦直接用 gem 安裝。
安裝完成之後,可以先看下版本:
kamal version初始化一個專案
進入你的專案目錄後,執行:
kamal init這條命令會幫你初始化 Kamal 所需的基本檔案,最重要的就是 config/deploy.yml 和 .kamal/secrets。
如果你的專案本身已經有 Dockerfile,那其實就已經具備了很關鍵的前置條件。Kamal 的部署流程預設就是圍繞專案根目錄下的標準 Dockerfile 來建構映像。
最小可用配置
我建議入門時先從一個很小的 config/deploy.yml 開始。官方文件給出的最小範例大概是這樣:
service: myapp
image: your-registry-user/myapp
servers:
- 203.0.113.10
registry:
username: your-registry-user
password:
- KAMAL_REGISTRY_PASSWORD
builder:
arch: amd64
env:
secret:
- AUTH_SECRET這個配置裡,最值得先理解的是下面幾項:
service:必填,用作容器名前綴。image:映像名,最終會被推到 registry。servers:部署目標機器列表。registry:映像倉庫配置。env.secret:需要從 secrets 檔案裡讀入的環境變數。builder.arch:建構架構,文件範例裡直接用了amd64。
這個階段不用追求配置多完整,先保證最基本的鏈路能跑起來更重要。
配置 secrets
接下來要準備 .kamal/secrets。比如:
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
AUTH_SECRET=your-auth-secret如果是 Rails 專案,文件範例裡會從 config/master.key 讀取 RAILS_MASTER_KEY。這也是 Rails 和 Kamal 結合得很自然的原因之一:Rails 新專案本身就比較容易接上這套部署方式。
第一次部署會發生什麼
當配置和 secrets 都準備好之後,就可以執行:
kamal setup這條命令會做很多事,但你可以把它理解成「一次完整的首發部署」。根據官方文件,它至少會做這些動作:
透過 SSH 連到伺服器。
如果伺服器缺 Docker,就自動安裝。
在本地和遠端登入映像倉庫。
用專案根目錄裡的 Dockerfile 建構映像。
把映像推送到 registry。
讓伺服器拉取映像。
確保
kamal-proxy在 80/443 埠上工作。啟動新容器。
等待
GET /up返回200 OK。把流量切到新容器。
停掉舊容器,並清理無用映像和停止的容器。
這裡有一個非常重要的小點:健康檢查預設是 GET /up。所以你的應用最好有這樣一個輕量級健康檢查介面,不然新容器可能啟動了,但 Kamal 還是不會把流量切過去。
後續部署就簡單很多
首次 setup 成功之後,後面的更新通常只要執行:
kamal deploy文件裡已經明確把它作為後續部署命令。你可以把它理解成「正常發版入口」:重新建構映像、推送、拉取、起新容器、健康檢查、切流量、停舊容器。
所以從使用體驗上看,Kamal 最舒服的地方就是:第一次部署稍微多做一點準備,後面就會穩定很多。
常用操作
入門階段,我覺得這幾條命令最實用:
初始化
kamal init生成基礎部署檔案。
首次部署
kamal setup把伺服器、Docker、映像、代理和應用第一次整體跑起來。
後續發版
kamal deploy日常最常用的一條命令。
多環境部署
如果你後面開始區分 staging 和 production,Kamal 支援用 -d 指定 destination,比如:
kamal deploy -d staging官方文件說明,這時 Kamal 會把 config/deploy.staging.yml 和基礎配置一起合併使用。
這個能力很實用,不過如果你只是剛入門,可以先知道它的存在,不急著馬上用上。
為什麼它和 Rails 很搭
Rails 8 新專案通常已經自帶 Dockerfile,而 Kamal 的部署流程正是圍繞 Dockerfile 展開的。再加上 Rails 生態裡本來就比較自然地接受 Ruby gem 工具鏈,所以從 Rails 接觸到 Kamal,幾乎是順理成章的一件事。
對我自己來說,正是因為先在 Rails 專案裡看到這套方式,我才開始認真把它當成一個長期可用的部署方案看待。
一個 Next.js 的入門使用案例
最後給一個更貼近我日常的例子:如果我要用 Kamal 部署一個 Next.js 專案,我通常會把它做成一個標準 Docker 應用,再交給 Kamal 去發布。
第一步:讓 Next.js 輸出為 standalone
Next.js 文件說明,開啟 output: 'standalone' 後,建構產物會生成 .next/standalone,裡面包含部署執行所需的最小檔案和一個 server.js。這非常適合 Docker 部署,因為它不需要把完整開發環境原樣搬進去。 [nextjs](https://nextjs.org/docs/pages/api-reference/config/next-config-js/output)
在 next.config.js 裡可以這樣寫:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfig需要注意的是,Next.js 文件提到,output: 'standalone' 的執行方式更適合直接使用生成的 server.js,而不是繼續用 next start。 [nextjs](https://nextjs.org/docs/14/app/api-reference/next-config-js/output)
第二步:準備 Dockerfile
一個簡單的 Next.js Dockerfile 可以像這樣:
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD [\"node\", \"server.js\"]這裡的重點不是 Docker 技巧本身,而是思路:先把 Next.js 做成一個標準、可執行的容器,再讓 Kamal 接管部署。
第三步:寫 Kamal 配置
例如:
service: my-next-app
image: your-registry-user/my-next-app
servers:
- 203.0.113.10
registry:
username: your-registry-user
password:
- KAMAL_REGISTRY_PASSWORD
builder:
arch: amd64
env:
clear:
PORT: 3000
NODE_ENV: production這份配置的邏輯很簡單:
Kamal 知道服務名是什麼。
Kamal 知道映像應該推到哪裡。
Kamal 知道應該部署到哪台伺服器。
容器啟動後,應用監聽 3000 埠,由 proxy 對外接流量。
第四步:補一個健康檢查介面
因為 Kamal 預設會檢查 GET /up,所以在 Next.js 裡我會加一個最簡單的路由,例如 App Router 下:
export async function GET() {
return Response.json({ ok: true })
}把它放到比如 app/up/route.ts,這樣 /up 就能返回一個簡單成功響應。這個介面越輕越好,目的只是告訴 Kamal:容器已經可以接流量了。
第五步:部署
最後就回到 Kamal 的標準流程:
kamal setup後續更新:
kamal deploy如果這套流程能在 Next.js 專案裡穩定跑起來,那麼你會發現:Kamal 其實並不在乎你是不是 Rails,它真正關心的是你能不能提供一個標準 Docker 映像,以及一個可檢查健康狀態的 Web 服務。
這篇先到這裡
如果你是像我一樣,從 Rails 8 接觸到 Kamal,再逐漸把這套方式遷移到 Next.js 16 專案裡,那麼 Kamal2 的定位其實很好理解:它不是平台,而是一個把自託管 Docker 部署變得更有秩序的工具。
入門階段,先掌握這些就夠了:
安裝 Kamal。
初始化配置檔案。
理解
deploy.yml和.kamal/secrets。會用
kamal setup做首次部署。會用
kamal deploy做後續更新。知道健康檢查預設依賴
GET /up。
等這些東西跑順了,再去了解多環境、accessories、hooks、複雜代理配置,會更自然一些。
在 Google 上持續關注
把 HeyBinyang 加入 Google 首選來源
如果你希望之後在 Google 上更容易看到我的更新,可以把這個站點加入 preferred source,讓它在相關閱讀情境裡更容易被找到。