Keel 自建部署 SOP
操作手册:从零部署一套 Keel 自建实例(Update server + Cloud Build
server + 前端 CDN)。目标用户:自建 Keel 后端的运维 / DevOps,
不是普通 Keel 用户(普通用户用 npx @keel-ai/cli ... 即可)。
预计时长:~60 分钟(不含审批等待)。
0. 前置条件
| 域名 | 1 个根域,如 mycorp.dev。下设 update.mycorp.dev + cdn.mycorp.dev 两个子域。 |
| SSL 证书 | Let’s Encrypt 或 阿里云免费证书。两个子域各 1 张。 |
| 服务器 | 1 台 4C8G+ ECS / VPS 跑 Update server + Cloud Build server。或拆两台。 |
| 阿里云账号 | OSS bucket + CDN domain。 |
| Disk | Update server 元数据走 SQLite(默认);后续会加 Postgres backend。 |
1. 阿里云 OSS bucket
# 1.1 创建 bucket(华东 1 / 华北 2 任选;建议跟服务器同区域)
aliyun oss mb oss://keel-bundles --acl=public-read \
--region=cn-hangzhou
# 1.2 创建 RAM 用户 + 给它 OSS 写权限
aliyun ram CreateUser --UserName keel-update-uploader
aliyun ram CreateAccessKey --UserName keel-update-uploader
# ↑ 记下 AccessKeyId + AccessKeySecret,下面填到 KEEL_UPDATE_S3_*
# 1.3 把 OSS-Read-Write policy 绑给这个用户(限定到这个 bucket)
cat > /tmp/keel-policy.json <<'EOF'
{
"Version": "1",
"Statement": [{
"Effect": "Allow",
"Action": ["oss:PutObject", "oss:GetObject", "oss:DeleteObject"],
"Resource": ["acs:oss:*:*:keel-bundles/*"]
}]
}
EOF
aliyun ram CreatePolicy --PolicyName keel-bundles-rw \
--PolicyDocument file:///tmp/keel-policy.json
aliyun ram AttachPolicyToUser --PolicyName keel-bundles-rw \
--PolicyType Custom --UserName keel-update-uploader
2. 阿里云 CDN
# 2.1 创建 CDN 域名指向 OSS bucket
aliyun cdn AddCdnDomain \
--DomainName cdn.mycorp.dev \
--CdnType download \
--Sources '[{"content":"keel-bundles.oss-cn-hangzhou.aliyuncs.com","type":"oss","port":80,"priority":20,"weight":15}]'
# 2.2 上传 SSL 证书 + 启用 HTTPS
aliyun cdn SetDomainServerCertificate \
--DomainName cdn.mycorp.dev \
--ServerCertificateStatus on \
--CertName keel-cdn-cert \
--ServerCertificate "$(cat fullchain.pem)" \
--PrivateKey "$(cat privkey.pem)"
# 2.3 域名解析(在你的 DNS 控制台):
# CNAME cdn.mycorp.dev → cdn.mycorp.dev.w.alikunlun.com (CDN console 给的目标)
3. SQLite 数据目录
# Update server 默认用 SQLite 存 manifest + patch 元数据。
# 单实例 + 本地 SSD 够 100k 设备的 polling 流量。
# Postgres backend 在路线图上,目前只支持 mem / sqlite:<path>。
mkdir -p /var/lib/keel
chown keel:keel /var/lib/keel
4. Update server 部署
# 4.1 服务器上 clone + build
git clone https://github.com/appunvs/keel.git
cd keel
go build -o /usr/local/bin/keel-update-server ./cmd/update-server
# 4.2 systemd unit
cat > /etc/systemd/system/keel-update.service <<'EOF'
[Unit]
Description=KAS Update Server
After=network.target
[Service]
EnvironmentFile=/etc/keel/update.env
ExecStart=/usr/local/bin/keel-update-server
Restart=always
RestartSec=5
User=keel
[Install]
WantedBy=multi-user.target
EOF
# 4.3 env 文件
mkdir -p /etc/keel
cat > /etc/keel/update.env <<EOF
KEEL_UPDATE_LISTEN=:8090
KEEL_UPDATE_DB=sqlite:/var/lib/keel/update.db
KEEL_UPDATE_BLOB_STORE=s3
KEEL_UPDATE_S3_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com
KEEL_UPDATE_S3_REGION=cn-hangzhou
KEEL_UPDATE_S3_BUCKET=keel-bundles
KEEL_UPDATE_S3_ACCESS_KEY=<from step 1.2>
KEEL_UPDATE_S3_SECRET_KEY=<from step 1.2>
KEEL_UPDATE_PUBLIC_URL_BASE=https://cdn.mycorp.dev
EOF
chmod 600 /etc/keel/update.env
# 4.4 启动
systemctl enable --now keel-update
systemctl status keel-update
5. nginx / 反向代理
server {
listen 443 ssl http2;
server_name update.mycorp.dev;
ssl_certificate /etc/letsencrypt/live/update.mycorp.dev/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/update.mycorp.dev/privkey.pem;
# Bundle uploads can be tens of MB — raise default limits.
client_max_body_size 128m;
proxy_request_buffering off;
proxy_read_timeout 300s;
location / {
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
6. Cloud Build server (可选)
如果你只用 OTA 不需要服务端编 bundle,可以跳过这一步。你的 RN
开发者本地用 keel build --local 编完直接 keel publish 就行。
如果要让 Cloud Build 跑(远程编 bundle,类似 EAS Build):
go build -o /usr/local/bin/keel-build-server ./cmd/build-server
# Cloud Build 在 Docker 容器里编 metro + Hermes,需要 docker。
apt-get install -y docker-ce docker-ce-cli containerd.io
systemctl enable --now docker
# build the metro+hermes builder image
bash cloud/packaging/build-cloud-build.sh
# systemd unit + nginx 类似 Update server。监听 :8091。
7. 烟测
# 7.1 健康检查
curl https://update.mycorp.dev/health
# {"status":"ok"}
# 7.2 上传一个 bundle (multipart 模式)
curl -X POST https://update.mycorp.dev/v1/myproj/update/bundles \
-F 'metadata={"version":"1.0.0","content_hash":"sha256:abc...","platform":"ios","channel":"production","runtime_version":"1.0","size_bytes":1234};type=application/json' \
-F 'bundle=@dist/index.ios.bundle;type=application/octet-stream'
# 7.3 promote + 拉 manifest
curl -X POST https://update.mycorp.dev/v1/myproj/update/bundles/abc.../promote \
-H 'Content-Type: application/json' \
-d '{"platform":"ios","channel":"production","runtime_version":"1.0"}'
curl 'https://update.mycorp.dev/v1/myproj/update/manifest?platform=ios&channel=production&runtime_version=1.0'
# {"current":{"hash":"sha256:abc...","url":"https://cdn.mycorp.dev/...",...},"patches":[]}
8. 灰度发布
# 50% 流量
curl -X POST https://update.mycorp.dev/v1/myproj/update/bundles/<hash>/promote \
-d '{"platform":"ios","channel":"production","runtime_version":"1.0","rollout":50}'
# 看着 metrics 没崩 → 推全量
curl -X POST https://update.mycorp.dev/v1/myproj/update/bundles/<hash>/promote \
-d '{"platform":"ios","channel":"production","runtime_version":"1.0","rollout":100}'
# 出事 → 回滚到上一个 hash(已经是 promoted 状态过的 bundle)
keel rollback --to=<previous-hash>
9. Submit driver 凭据
如果你要用 KAS Submit 自动上架(不只是 OTA),需要给每个市场配
凭据。每个 driver 的具体凭据见 keel/cloud/internal/submit/drivers/<market>/
里 Cred* 常量。
# 例:苹果 App Store
keel submit configure ios_appstore \
--issuer_id="..." --key_id="..." --p8_path="./AuthKey_XXX.p8" \
--bundle_id="com.mycorp.app"
# 例:华为 AGC
keel submit configure huawei \
--app_id="..." --client_id="..." --client_secret="..." \
--project_id="..."
凭据存在 ~/.keel/credentials.yml,权限 0600。CI 流水线建议用
环境变量覆盖(每个 driver 的 README 会列)。
10. 监控 + 容灾
| 项 | 做法 |
|---|---|
| 健康监控 | UptimeRobot 5min ping update.mycorp.dev/health |
| 日志 | systemd-journald → ELK / 阿里云 SLS(参考 Mortar SLS 集成) |
| Postgres 备份 | 每日全量 + 1h binlog;阿里云 RDS 默认带 |
| OSS 备份 | OSS 跨区域复制启用一次;多 region 同步 |
| CDN 故障 | 域名解析 fallback 到 OSS 直连域 |
11. 升级
cd /opt/keel
git pull
go build -o /usr/local/bin/keel-update-server ./cmd/update-server
systemctl restart keel-update
数据库迁移 Update server 自动跑(启动时扫 internal/update/
schema 文件)。
故障排查清单
| 症状 | 可能原因 |
|---|---|
/health 返回 503 | DB 不可达 / OSS endpoint 错 / 凭据失效 |
| Manifest 200 但 bundle URL 404 | OSS bucket 未开 public-read 或 CDN 没回源 |
| Patch 流没生效 | 客户端 current_hash 不在 patches 中 → 客户端走全量下载(正常) |
| Submit 报 401 | 凭据过期或 client_id 写错 |
| Cloud Build 任务卡住 | docker daemon 挂了 / 磁盘满 / metro 缓存损坏 |
参考
docs/architecture.md— 5 层产品总览docs/update.md— Update protocol 细节docs/submit.md— Submit 5 市场对比internal/update/— Update server 源码internal/submit/— Submit driver 源码