我的 kamal 生产环境配置
Kamal 是 Basecamp 开源的一款部署工具,它的工作模式类似 Capistrano,但使用 docker 解决依赖封装。它原始设计用于 Rails 应用,由于使用了 docker,只要应用可以 docker 化也能使用 kamal 部署。
Kamal 的使用率在 Rails 社区越来越高,问题也随之出现:Build 的过程遇到网络问题怎么办?Secret 应该存在哪里?怎么配置 CI/CD?
这些问题我在实践中也解决过,在此分享我的解决方案。方案不是唯一的,有其他方案欢迎在评论区留言。
本文假设你已经读过 Kamal 官方文档,熟悉 Docker 使用,熟悉云平台 VPC、安全组等设置。
概览
首先对整个部署架构有个整体概览:
下面我逐个分析。
为什么需要 deploy server
Kamal 的配置和运行应该放在哪里?我的选择是单独配置一台 deploy server,并且放在境外机房。这是有两个考虑:
网络问题
Docker build 的过程很容易被网络问题阻塞,只要把 deploy server 放在境外,问题就解决了。一并解决的还有 rubygem、npm 包安装的网络问题等,不用再配置国内镜像。
Secrets 管理
Secrets 管理是我不在 CI/CD 服务器(例如 GitHub Action)上配置 Kamal 的原因。
当前 Kamal 2.x 版本需要在 deploy 的时候获取所有环境变量,然后覆盖到 app server。如果在 CI/CD 服务器执行 kamal,就要让 CI/CD 服务器获取所有环境变量,包括 secrets。我认为这是一个安全隐患,试想一下某一天 CI/CD 服务器泄漏了支付网关的密钥?
作为参考,GitHub Action 一个流行插件 Tj-actions/changed-files 被注入恶意代码事件:https://news.ycombinator.com/item?id=43367987 。
额外配置一台 deploy server,将 kamal 配置和 secrets 放在 deploy server 上。需要人工操作的时候登录 deploy server 执行。
CI/CD 如何触发 Deploy
CI/CD 通过 ssh 连接 deploy server,并且使用 ForceCommand 限制这个 ssh key 只能执行 deploy 命令。
ForceCommand 的设置方法是在 .ssh/authorized_keys
的对应 public key 位置添加 command="..."
参数,例如:
command="/path/to/deploy.sh" ssh-ed25519 AAA... GHA
其中 deploy.sh
脚本包含执行 kamal deploy
的所有操作,例如:
#!/bin/bash
cd /path/to/source
git fetch origin
git reset --hard origin/master
kamal deploy
ForceCommand 的设置很重要,不然 CI/CD 的 key 泄露会成为一个安全漏洞。
VPC 设置
如果 deploy server 和 app server 在同一家云服务商,可以通过跨 VPC 互联的方式将两类服务器置于同一个局域网下。app server 只需要内网 IP,不暴露在公网。Deploy server 通过内网 IP 部署到 app server。
Docker Registry 的位置
Kamal deploy 的过程需要将 app 镜像 push 到 docker registry。由于网络原因,Docker Registry 最好贴近部署区域。以阿里云为例,如果部署在阿里云杭州区域,那么选择阿里云 registry 的杭州区域。
在实践中我发现从境外往境内 push 问题较少,从境内往境外 pull 问题较多。
Registry 代理
Kamal deploy 的过程需要在 app server pull kamal proxy 的镜像,也会遇到网络问题(wtf)。我的解决方法是自建 docker registry 代理,之前已经写了一篇博客:自建 docker 镜像服务。
使用托管数据库
虽然 kamal accessory
有管理 DB 的能力,但容器不擅长管理有持久化需求的服务,所以我建议使用云平台的数据库。使用托管数据库更容易实现备份、升级等操作。
总结
以上就是我的 kamal 生产环境配置的要点。一些与 kamal 无关的配置例如 CI 配置、Web server 配置就不在这里赘述。
可以看到 kamal 生产环境需要一些额外资源和配置,对于小型应用来说有点繁琐。所以我的个人项目会使用 Fly 部署,平台默认提供了以上基础设施。对于需要部署在国内的应用,我会用 Kamal,因为它相比其他容器部署工具要简单。
有任何意见建议?欢迎在评论区交流。
我会在前面用一台 caddy 服务器作为均衡负载和 TLS,也就是 web server 的位置。Nginx 也可以。
Kamal 部署方案, 可能与 Nginx 或者 Caddy 这样的代理服务器结合吗?
适用于 kamal 2。