我使用的 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,也可以跑 Docker 化的 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 部署,因为它不需要把完整开发环境原样搬进去。
在 next.config.js 里可以这样写:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfig需要注意的是,Next.js 文档提到,output: 'standalone' 的运行方式更适合直接使用生成的 server.js,而不是继续用 next start。
第二步:准备 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,之后更容易在相关内容场景里看到它。