kamal-deploy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Kamal Deploy Expert

Kamal部署专家

Expert guidance for deploying applications with Kamal - DHH's zero-downtime deployment tool from 37signals.
为使用Kamal部署应用提供专业指导——Kamal是37signals公司DHH开发的零停机部署工具。

Step 1: Fetch Latest Documentation (MANDATORY)

步骤1:获取最新文档(必填)

BEFORE answering ANY Kamal question, you MUST use the WebFetch tool to get current documentation. The docs below may be outdated - always fetch fresh docs first.
Execute these WebFetch calls in parallel:
  1. WebFetch(url: "https://kamal-deploy.org/docs/installation/", prompt: "Extract complete installation and setup guide")
  2. WebFetch(url: "https://kamal-deploy.org/docs/configuration/overview/", prompt: "Extract all configuration options and deploy.yml structure")
  3. WebFetch(url: "https://kamal-deploy.org/docs/commands/view-all-commands/", prompt: "Extract all Kamal commands and usage")
  4. WebFetch(url: "https://kamal-deploy.org/docs/configuration/proxy/", prompt: "Extract proxy, SSL, and health check configuration")
Fetch these additional docs based on user's question:
  • Servers/roles:
    https://kamal-deploy.org/docs/configuration/servers/
  • Accessories (DB, Redis):
    https://kamal-deploy.org/docs/configuration/accessories/
  • Environment variables:
    https://kamal-deploy.org/docs/configuration/environment-variables/
  • Docker build options:
    https://kamal-deploy.org/docs/configuration/builders/
  • Deployment hooks:
    https://kamal-deploy.org/docs/hooks/overview/
  • Upgrading v1→v2:
    https://kamal-deploy.org/docs/upgrading/overview/
Only after fetching fresh docs, use the reference material below as supplementary context.
**在回答任何Kamal相关问题之前,你必须使用WebFetch工具获取当前文档。**以下文档可能已过时——务必先获取最新文档。
并行执行以下WebFetch调用:
  1. WebFetch(url: "https://kamal-deploy.org/docs/installation/", prompt: "Extract complete installation and setup guide")
  2. WebFetch(url: "https://kamal-deploy.org/docs/configuration/overview/", prompt: "Extract all configuration options and deploy.yml structure")
  3. WebFetch(url: "https://kamal-deploy.org/docs/commands/view-all-commands/", prompt: "Extract all Kamal commands and usage")
  4. WebFetch(url: "https://kamal-deploy.org/docs/configuration/proxy/", prompt: "Extract proxy, SSL, and health check configuration")
根据用户的问题获取以下额外文档:
  • 服务器/角色:
    https://kamal-deploy.org/docs/configuration/servers/
  • 附属组件(数据库、Redis):
    https://kamal-deploy.org/docs/configuration/accessories/
  • 环境变量:
    https://kamal-deploy.org/docs/configuration/environment-variables/
  • Docker构建选项:
    https://kamal-deploy.org/docs/configuration/builders/
  • 部署钩子:
    https://kamal-deploy.org/docs/hooks/overview/
  • 从v1升级到v2:
    https://kamal-deploy.org/docs/upgrading/overview/
仅在获取最新文档后,才可将以下参考资料作为补充上下文使用。

What is Kamal?

什么是Kamal?

Kamal deploys containerized apps to any server via SSH + Docker. Created by 37signals (DHH's company) to deploy Basecamp, HEY, and other apps.
Core architecture:
  • SSHs into servers, installs Docker automatically
  • Builds app into Docker container
  • Pushes to registry (Docker Hub, GHCR, etc.)
  • Pulls and runs on target servers
  • kamal-proxy handles routing, SSL (Let's Encrypt), zero-downtime
Mental model: Hetzner/DigitalOcean = the computer, Kamal = deploys your app to it
Kamal通过SSH + Docker将容器化应用部署到任意服务器。由37signals(DHH的公司)开发,用于部署Basecamp、HEY及其他应用。
核心架构:
  • 通过SSH连接到服务器,自动安装Docker
  • 将应用构建为Docker容器
  • 推送到镜像仓库(Docker Hub、GHCR等)
  • 在目标服务器上拉取并运行
  • kamal-proxy处理路由、SSL(Let's Encrypt)和零停机部署
理解模型: Hetzner/DigitalOcean = 服务器,Kamal = 将你的应用部署到该服务器

Before You Start

开始之前

Check these first to avoid common friction:
  1. Kamal version - Run
    kamal version
    . If on 1.x, upgrade with
    gem install kamal
    . Config syntax changed significantly (1.x uses
    traefik
    , 2.x uses
    proxy
    ).
  2. Local Docker situation - Ask the user if they have Docker working locally. If not (or if Docker Desktop is problematic on macOS), configure a remote builder:
    yaml
    builder:
      arch: amd64
      remote: ssh://root@SERVER_IP
    This builds on the target server and avoids local Docker entirely.
  3. 37signals open-source repos - If deploying Campfire, HEY, or other 37signals apps, immediately delete
    .env.erb
    - it uses their internal 1Password setup and will fail with
    op: command not found
    .
  4. Registry access - Confirm the user has a container registry (Docker Hub, GHCR) and knows their credentials before writing config.
请先检查以下内容,避免常见问题:
  1. Kamal版本 - 运行
    kamal version
    。如果是1.x版本,使用
    gem install kamal
    升级。配置语法有重大变化(1.x使用
    traefik
    ,2.x使用
    proxy
    )。
  2. 本地Docker环境 - 询问用户本地是否已正常运行Docker。如果没有(或macOS上Docker Desktop存在问题),配置远程构建器:
    yaml
    builder:
      arch: amd64
      remote: ssh://root@SERVER_IP
    这会在目标服务器上构建镜像,完全无需本地Docker。
  3. 37signals开源仓库 - 如果部署Campfire、HEY或其他37signals应用,请立即删除
    .env.erb
    文件——它使用的是37signals内部的1Password配置,运行时会提示
    op: command not found
    错误。
  4. 镜像仓库访问权限 - 在编写配置之前,确认用户拥有容器镜像仓库(Docker Hub、GHCR)及对应的凭据。

Quick Start

快速开始

bash
undefined
bash
undefined

Install (or upgrade)

安装(或升级)

gem install kamal
gem install kamal

Initialize in project

在项目中初始化

kamal init
kamal init

First deploy (installs Docker, proxy, deploys app)

首次部署(安装Docker、代理、部署应用)

kamal setup
kamal setup

Subsequent deploys

后续部署

kamal deploy
undefined
kamal deploy
undefined

Essential Commands

核心命令

CommandPurpose
kamal setup
First deploy - installs Docker, proxy, deploys
kamal deploy
Deploy new version
kamal rollback
Revert to previous version
kamal app logs
View application logs
kamal app exec -i bash
SSH into running container
kamal accessory boot <name>
Start accessory (db, redis)
kamal proxy reboot
Restart kamal-proxy
kamal remove
Remove everything from servers
命令用途
kamal setup
首次部署 - 安装Docker、代理、部署应用
kamal deploy
部署新版本
kamal rollback
回滚到上一个版本
kamal app logs
查看应用日志
kamal app exec -i bash
进入运行中的容器
kamal accessory boot <name>
启动附属组件(数据库、Redis)
kamal proxy reboot
重启kamal-proxy
kamal remove
移除服务器上的所有相关组件

Minimal config/deploy.yml

最简配置/deploy.yml

yaml
service: my-app
image: username/my-app

servers:
  - 123.45.67.89

registry:
  username: username
  password:
    - KAMAL_REGISTRY_PASSWORD

proxy:
  ssl: true
  host: myapp.com

env:
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL
yaml
service: my-app
image: username/my-app

servers:
  - 123.45.67.89

registry:
  username: username
  password:
    - KAMAL_REGISTRY_PASSWORD

proxy:
  ssl: true
  host: myapp.com

env:
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL

Secrets Management

密钥管理

Secrets live in
.kamal/secrets
:
bash
undefined
密钥存储在
.kamal/secrets
中:
bash
undefined

.kamal/secrets

.kamal/secrets

KAMAL_REGISTRY_PASSWORD=ghp_xxxxxxxxxxxx RAILS_MASTER_KEY=abc123def456 DATABASE_URL=postgres://user:pass@db:5432/app

Reference in deploy.yml:
```yaml
env:
  clear:
    RAILS_ENV: production
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL
KAMAL_REGISTRY_PASSWORD=ghp_xxxxxxxxxxxx RAILS_MASTER_KEY=abc123def456 DATABASE_URL=postgres://user:pass@db:5432/app

在deploy.yml中引用:
```yaml
env:
  clear:
    RAILS_ENV: production
  secret:
    - RAILS_MASTER_KEY
    - DATABASE_URL

Multi-Server with Roles

多服务器与角色配置

yaml
servers:
  web:
    hosts:
      - 123.45.67.89
      - 123.45.67.90
  workers:
    hosts:
      - 123.45.67.91
    cmd: bin/jobs
    proxy: false  # Workers don't need proxy
yaml
servers:
  web:
    hosts:
      - 123.45.67.89
      - 123.45.67.90
  workers:
    hosts:
      - 123.45.67.91
    cmd: bin/jobs
    proxy: false  # 工作节点不需要代理

Accessories (Databases, Redis)

附属组件(数据库、Redis)

yaml
accessories:
  db:
    image: postgres:16
    host: 123.45.67.89
    port: 5432
    env:
      clear:
        POSTGRES_DB: app_production
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

  redis:
    image: redis:7
    host: 123.45.67.89
    port: 6379
    directories:
      - data:/data
yaml
accessories:
  db:
    image: postgres:16
    host: 123.45.67.89
    port: 5432
    env:
      clear:
        POSTGRES_DB: app_production
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

  redis:
    image: redis:7
    host: 123.45.67.89
    port: 6379
    directories:
      - data:/data

SSL Configuration

SSL配置

Automatic (Let's Encrypt):
yaml
proxy:
  ssl: true
  host: myapp.com  # Must point to server IP
Custom certificate:
yaml
proxy:
  ssl:
    certificate_pem:
      - SSL_CERTIFICATE
    private_key_pem:
      - SSL_PRIVATE_KEY
自动配置(Let's Encrypt):
yaml
proxy:
  ssl: true
  host: myapp.com  # 必须指向服务器IP
自定义证书:
yaml
proxy:
  ssl:
    certificate_pem:
      - SSL_CERTIFICATE
    private_key_pem:
      - SSL_PRIVATE_KEY

Health Checks

健康检查

yaml
proxy:
  healthcheck:
    interval: 3
    path: /up
    timeout: 3
App must return 200 on
/up
(Rails default) or configured path.
yaml
proxy:
  healthcheck:
    interval: 3
    path: /up
    timeout: 3
应用必须在
/up
路径返回200状态码(Rails默认)或配置的自定义路径。

Destinations (Staging/Production)

部署目标(预发布/生产环境)

Create
config/deploy.staging.yml
:
yaml
servers:
  - staging.myapp.com

proxy:
  host: staging.myapp.com
Deploy:
kamal deploy -d staging
Secrets:
.kamal/secrets.staging
创建
config/deploy.staging.yml
yaml
servers:
  - staging.myapp.com

proxy:
  host: staging.myapp.com
部署命令:
kamal deploy -d staging
密钥文件:
.kamal/secrets.staging

Hooks

钩子

Place in
.kamal/hooks/
(no file extension):
Available hooks:
  • pre-connect
    ,
    pre-build
    ,
    pre-deploy
    ,
    post-deploy
  • pre-app-boot
    ,
    post-app-boot
  • pre-proxy-reboot
    ,
    post-proxy-reboot
Example
.kamal/hooks/post-deploy
:
bash
#!/bin/bash
curl -X POST "https://api.honeybadger.io/v1/deploys" \
  -d "deploy[revision]=$KAMAL_VERSION"
将钩子文件放在
.kamal/hooks/
目录下(无文件扩展名):
可用钩子:
  • pre-connect
    ,
    pre-build
    ,
    pre-deploy
    ,
    post-deploy
  • pre-app-boot
    ,
    post-app-boot
  • pre-proxy-reboot
    ,
    post-proxy-reboot
示例
.kamal/hooks/post-deploy
bash
#!/bin/bash
curl -X POST "https://api.honeybadger.io/v1/deploys" \
  -d "deploy[revision]=$KAMAL_VERSION"

Dockerfile Requirements

Dockerfile要求

Kamal needs a Dockerfile. For Rails:
dockerfile
FROM ruby:3.3-slim

WORKDIR /app
Kamal需要Dockerfile。对于Rails应用:
dockerfile
FROM ruby:3.3-slim

WORKDIR /app

Install dependencies

安装依赖

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
COPY Gemfile* ./ RUN bundle install
COPY . .
RUN bundle exec rails assets:precompile
EXPOSE 80 CMD ["bin/rails", "server", "-b", "0.0.0.0", "-p", "80"]

Note: Kamal 2.x defaults to port 80 (not 3000).
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
COPY Gemfile* ./ RUN bundle install
COPY . .
RUN bundle exec rails assets:precompile
EXPOSE 80 CMD ["bin/rails", "server", "-b", "0.0.0.0", "-p", "80"]

注意:Kamal 2.x默认使用80端口(而非3000)。

Common Issues

常见问题

"Container not healthy"
  • Check
    /up
    endpoint returns 200
  • Increase
    deploy_timeout
    if app boots slowly
  • Check logs:
    kamal app logs
"Permission denied"
  • Ensure SSH key is added:
    ssh-add ~/.ssh/id_rsa
  • Check SSH user has Docker access
Registry auth failed
  • Verify
    KAMAL_REGISTRY_PASSWORD
    in
    .kamal/secrets
  • For GHCR: use personal access token with
    write:packages
"Address already in use"
  • Another service on port 80/443
  • Run
    kamal proxy reboot
    or check
    docker ps
    on server
"容器不健康"
  • 检查
    /up
    端点是否返回200
  • 如果应用启动缓慢,增加
    deploy_timeout
  • 查看日志:
    kamal app logs
"权限被拒绝"
  • 确保已添加SSH密钥:
    ssh-add ~/.ssh/id_rsa
  • 检查SSH用户是否拥有Docker访问权限
"镜像仓库认证失败"
  • 验证
    .kamal/secrets
    中的
    KAMAL_REGISTRY_PASSWORD
  • 对于GHCR:使用拥有
    write:packages
    权限的个人访问令牌
"地址已被占用"
  • 80/443端口被其他服务占用
  • 运行
    kamal proxy reboot
    或在服务器上执行
    docker ps
    检查

Kamal vs Alternatives

Kamal与其他方案对比

KamalKubernetesHeroku
ComplexityLowHighNone
CostVPS onlyVPS + overhead$$$
ControlFullFullLimited
Zero-downtimeYesYesYes
SSLAutoManualAuto
Learning curveHoursWeeksMinutes
KamalKubernetesHeroku
复杂度
成本仅VPS费用VPS费用+额外开销
控制权完全控制完全控制有限
零停机部署支持支持支持
SSL自动配置手动配置自动配置
学习曲线数小时数周数分钟

Best Practices

最佳实践

  1. Always test locally first:
    docker build . && docker run -p 3000:80 <image>
  2. Use staging destination before production
  3. Keep secrets out of git:
    .kamal/secrets
    in
    .gitignore
  4. Set up monitoring: Use hooks to notify on deploy
  5. Regular backups: Especially accessory volumes
  6. Use asset bridging for Rails:
    asset_path: /app/public/assets
  1. 始终先在本地测试
    docker build . && docker run -p 3000:80 <image>
  2. 在生产环境前使用预发布目标
  3. 不要将密钥提交到git:将
    .kamal/secrets
    加入
    .gitignore
  4. 设置监控:使用钩子在部署时发送通知
  5. 定期备份:尤其是附属组件的卷
  6. 为Rails应用使用资源桥接
    asset_path: /app/public/assets

Reference Files

参考文件

For detailed configuration options, see:
  • references/configuration.md - Complete deploy.yml reference
  • references/troubleshooting.md - Common issues and solutions
如需详细配置选项,请查看:
  • references/configuration.md - 完整的deploy.yml参考
  • references/troubleshooting.md - 常见问题及解决方案