本文说明如何把 Claude Code Hub 部署到 Kubernetes(含轻量级 k3s)集群。若你只需要单机 Docker 部署,请参考 scripts/deploy.sh 与 docker-compose.yaml。
Ingress / NodePort (可选)
│
▼
┌──────────────────┐
│ Service (ClusterIP / NodePort)
└────────┬─────────┘
│
┌────────▼─────────┐
│ Deployment │ HPA 2~6 副本,CPU 70% / Memory 80%
│ claude-code-hub │ PDB maxUnavailable=1
└────┬─────────┬────┘
│ │
┌─────▼──┐ ┌───▼─────┐
│Postgres│ │ Redis │ StatefulSet + PVC
└────────┘ └─────────┘ NetworkPolicy 仅允许 app 访问
| 维度 | Docker Compose | Kubernetes |
|---|---|---|
| 高可用 | 单容器 | HPA + PDB,滚动更新不中断 |
| 存储 | 本地卷 | PVC (由集群 StorageClass 管理) |
| 域名 | Caddy (可选) | Ingress / Traefik IngressRoute / NodePort |
| 密钥 | .env 文件 |
Kubernetes Secret |
| 升级 | docker compose pull |
cch update (带迁移 + 回滚) |
| 适用 | 个人/小团队 | 生产 / 多节点 / 企业 |
| 类别 | 要求 |
|---|---|
| OS | Linux (Ubuntu 22.04+/Debian 12+/Rocky 9+ 等) 或 macOS(仅管理端) |
| Shell | bash ≥ 3.2 (含 macOS 默认 /bin/bash) |
| 工具链 | kubectl / curl / openssl / python3 |
| 集群 | Kubernetes ≥ 1.26 (或用 --install-k3s 自动装 k3s) |
| 存储 | 默认 StorageClass 可用,或通过 --storage-class <name> 指定 |
| 域名(可选) | 有 Ingress Controller 时可启用 HTTPS/域名访问 |
| 资源 | 建议 4 vCPU / 8GB RAM / 80GB 磁盘起步 |
选项 A — 单机 k3s (推荐新手 / 家用 / 自建)
# 脚本会在检测不到集群时自动提示安装
bash scripts/deploy-k8s.sh --install-k3s -y
--install-k3s会执行官方安装脚本curl -fsSL https://get.k3s.io | sh -。 生产环境建议先审阅脚本内容,确认来源与变更窗口后再执行。
选项 B — 已有集群 (EKS / GKE / AKS / 自建标准 K8s)
需要满足:
--storage-class 指定)kubectl (单独机器管理集群时必需)bash ≥ 3.2 / curl / openssl / python3 (脚本渲染占位符时使用)macOS 默认的 /bin/bash 是 3.2 分支,脚本兼容该版本。BSD 工具链差异(
cp、date等)已在脚本内做了 POSIX 兼容处理。
# 克隆仓库
git clone https://github.com/ding113/claude-code-hub.git
cd claude-code-hub
# 一键部署 (非交互;无集群时会提示安装 k3s)
bash scripts/deploy-k8s.sh --install-k3s -y
脚本执行完会输出:
+================================================================+
| Claude Code Hub Deployment Complete! |
+================================================================+
Access URL: http://<node-ip>:<nodeport>
Namespace: claude-code-hub
Image: ghcr.io/ding113/claude-code-hub:latest
Admin Token (保管好):
<auto-generated-token>
常用命令 (cch):
cch status
cch logs
cch update
cch backup
cch info
bash scripts/deploy-k8s.sh \
--ingress-host hub.example.com \
--ingress-class nginx \
--storage-class standard \
-y
bash scripts/deploy-k8s.sh -n hub-staging -b dev -y
bash scripts/deploy-k8s.sh --dry-render --deploy-dir /tmp/cch-k8s -y
kubectl apply --dry-run=client -R -f /tmp/cch-k8s/k8s/
scripts/deploy-k8s.sh| 分组 | 参数 | 默认值 | 说明 |
|---|---|---|---|
| Cluster | -n, --namespace <ns> |
claude-code-hub |
K8s namespace |
--kube-context <ctx> |
当前 context | kubectl context | |
--install-k3s |
off | 无集群时自动安装 k3s(需 sudo) | |
| Application | -i, --image <ref> |
ghcr.io/ding113/claude-code-hub:latest |
应用镜像 |
-b, --branch <name> |
main | 分支捷径: main→:latest, dev→:dev | |
-t, --admin-token <token> |
自动 48 位随机 | ADMIN_TOKEN | |
--replicas <n> |
2 | 基线副本数 | |
--hpa-min <n> / --hpa-max <n> |
2 / 6 | HPA 上下限 | |
--timezone <tz> |
Asia/Shanghai |
容器 TZ | |
| Storage | --storage-class <name> |
自动探测 | PVC storageClassName |
--pg-size <size> |
50Gi | PostgreSQL PVC | |
--redis-size <size> |
10Gi | Redis PVC | |
| Ingress | --ingress-host <host> |
未设置 | 启用 Ingress 并绑定域名 |
--ingress-class <cls> |
自动探测 | Ingress className | |
--disable-ingress |
off | 跳过 Ingress,使用 NodePort | |
| Network | --disable-networkpolicy |
off | 跳过 NetworkPolicy(非标准 Ingress ns 时需要) |
| Deployment | -d, --deploy-dir <path> |
auto | manifest + cch 安装目录 |
--force-new |
off | 删除已有 namespace 后重装(Deployment / StatefulSet / Secret / PVC 全重建) | |
--install-cch |
off | cch 软链到 /usr/local/bin/cch |
|
--dry-render |
off | 只渲染不 apply | |
| Misc | -y, --yes |
交互 | 非交互模式 |
-h, --help |
— | 显示帮助 | |
--version |
— | 显示版本 |
bash scripts/deploy-k8s.sh \
-i harbor.example.com/cch/claude-code-hub:v1.2.3 \
-y
若 registry 需要认证:先手动创建 docker-registry Secret,再在 Deployment 追加 imagePullSecrets(脚本暂不自动生成,参见 k8s 官方文档)。
| 云厂商 | storageClassName |
|---|---|
| AWS EKS | gp3 / gp2 |
| GCP GKE | standard-rwo / premium-rwo |
| Azure AKS | managed-csi / managed-premium |
| k3s (单机) | local-path (默认) |
传入 --storage-class <name> 覆盖默认,或脚本会自动识别默认 SC。
bash scripts/deploy-k8s.sh --replicas 3 --hpa-min 3 --hpa-max 10 -y
默认模板保留 replicas=2,但 AUTO_MIGRATE 入口 src/instrumentation.ts 会先获取 PostgreSQL advisory lock,
因此首次多副本启动时迁移会串行执行。如果你更关心首启速度,也可以先用 --replicas 1 部署,确认健康后再扩容。
默认 deploy/k8s/app/networkpolicy.yaml 只在 Ingress 模式 下应用,并放行以下三个 Ingress Controller namespace:
kube-system (k3s 内置 Traefik)ingress-nginx (社区版 nginx-ingress)traefik (独立安装的 Traefik)如果你的 Ingress Controller 位于其他 namespace(例如 istio-system),有两种选择:
bash scripts/deploy-k8s.sh --disable-networkpolicy -ydeploy/k8s/app/networkpolicy.yaml 加入你的 namespace 标签,再部署若脚本回落到 NodePort (--disable-ingress 或未提供 --ingress-host),会自动跳过 app NetworkPolicy,
避免默认的 Ingress namespace 白名单把外部流量挡掉。
deploy/k8s/app/deployment.yaml 里枚举了常用环境变量(连接池、超时、限流开关、MESSAGE_REQUEST 批量参数等)。建议流程:
deploy/k8s/app/deployment.yaml 模板bash scripts/deploy-k8s.sh -y 走升级分支(自动保留 Secret)kubectl -n claude-code-hub set env deployment/claude-code-hub KEY=VAL部署完成后,cch 用于日常运维。若 --install-cch 已启用,直接运行 cch ...;否则用 bash scripts/cch ...。
cch update # 拉新镜像 + 自动迁移 + 滚动更新,失败自动回滚
cch restart # 滚动重启 (不换镜像)
cch rollback # 回滚到上一个 revision
cch scale 3 # 调整副本数
cch status # Pod / HPA / 资源使用
cch logs 500 # 最近 500 行日志
cch logs --since=10m # 透传 kubectl logs 参数
cch follow # 实时 tail
cch env # 展示当前 env (JSON)
cch info # 访问 URL + Admin Token + 镜像 digest
cch doctor # 诊断 (kubectl / 集群 / Pod / 健康)
cch backup # PostgreSQL 备份到 ~/backups/claude-code-hub/(gzip,保留 30 份)
cch secret # 输出 Admin Token
cch secret dsn # 输出 PostgreSQL 连接串
cch secret redis-url # 输出 Redis 连接串
cch dbshell # psql 交互
cch shell # 应用 Pod 的 sh
优先级: CLI 参数 > 环境变量 > ~/.config/cch/config > 默认值
| 变量 | 默认 | 说明 |
|---|---|---|
CCH_NAMESPACE |
claude-code-hub |
目标 namespace |
CCH_IMAGE |
ghcr.io/ding113/claude-code-hub:latest |
目标镜像 |
CCH_DEPLOY_DIR |
自动查找 | manifest 所在目录 |
CCH_RUNTIME |
自动探测 | 强制设置为 k3s 或 kubectl |
CCH_INGRESS_HOST |
— | 用于 cch info 的 URL 渲染 |
CCH_BACKUP_DIR |
~/backups/claude-code-hub |
备份路径 |
CCH_BACKUP_KEEP |
30 |
保留备份数 |
NO_COLOR |
— | 设为任意值禁用彩色输出 |
示例 ~/.config/cch/config (安装时由脚本自动写入):
CCH_NAMESPACE="claude-code-hub"
CCH_IMAGE="ghcr.io/ding113/claude-code-hub:latest"
CCH_DEPLOY_DIR="/home/user/.config/cch"
CCH_RUNTIME="k3s"
CCH_INGRESS_HOST="hub.example.com"
cch update)1. PostgreSQL 备份 (失败时询问是否继续)
2. k3s: 预拉镜像 / 标准 k8s: 依赖 imagePullPolicy=Always
3. 缩到 1 副本 (减少升级等待时间与排障复杂度)
4. 更新镜像 → 应用启动时通过 AUTO_MIGRATE=true 自动执行 drizzle migrate
k3s 路径: 用 digest 固定避免 tag 相同导致 rollout 空跑
标准 k8s 路径: set image(tag 相同则触发 rollout restart)
5. 健康检查 (in-pod fetch /api/health/ready)
6. 健康检查失败 → 自动 rollout undo + 恢复原副本数
7. 健康检查通过 → 恢复到 max(升级前实际副本数, HPA minReplicas)
说明: 未使用独立的迁移 Job — 应用镜像在启动时通过
AUTO_MIGRATE=true环境变量触发 drizzle migrate(入口src/instrumentation.ts),避免 Job 与应用并发迁移的竞态,且 运行时镜像不再依赖 devDependency 的 drizzle-kit。PostgreSQL 默认资源画像:
requests.memory=2Gi、limits.memory=4Gi、shared_buffers=1GB、effective_cache_size=3GB。这套默认值更适合单节点 8GB RAM 起步环境;如业务量继续增长, 再按节点规格同步上调数据库内存参数和 Pod limit。
cch rollback # 回到上一个 revision
kubectl -n claude-code-hub rollout history deployment/claude-code-hub # 查看历史
cch backup
# 产物: ~/backups/claude-code-hub/claude_code_hub_YYYYMMDD_HHMMSS.sql.gz
# 自动保留最近 30 份,多出的自动删除
建议把备份目录同步到对象存储(rsync / rclone / aws s3 sync):
# crontab 示例:每天凌晨同步到 S3
0 3 * * * aws s3 sync ~/backups/claude-code-hub s3://my-bucket/cch-backups/
# 1. 停 app (避免写入):先删掉 HPA,再直接 kubectl 缩到 0 (cch scale 要求 >=1)
# CPU/内存 HPA 不支持直接把 minReplicas 改成 0
kubectl -n claude-code-hub delete hpa claude-code-hub 2>/dev/null || true
kubectl -n claude-code-hub scale deployment/claude-code-hub --replicas=0
# 2. 在 postgres pod 内执行恢复
gunzip -c ~/backups/claude-code-hub/claude_code_hub_20260101_030000.sql.gz | \
kubectl -n claude-code-hub exec -i sts/postgres -- \
psql -U claude_code_hub -d claude_code_hub
# 3. 用与初次部署一致的 CLI 参数重跑一次完整部署,恢复 HPA / PDB / Service 等资源
# 关键:保留原始的 --replicas / --hpa-min / --hpa-max / --storage-class / --ingress-* 参数
bash scripts/deploy-k8s.sh -n claude-code-hub <repeat-your-original-cli-args> -y
cch uninstall
# 输入 namespace 名称以二次确认;会删除:
# - namespace claude-code-hub (含所有 Pod / Service / Ingress / Secret / HPA)
# - PVC (Postgres 和 Redis 数据永久丢失)
卸载后 manifest 目录 ~/.config/cch/ 保留,可手动 rm -rf 清理。
备份目录 ~/backups/claude-code-hub/ 永不自动删除。
cch doctor 检查清单优先运行:
cch doctor
输出示例:
[OK] kubectl installed: v1.31.5
[OK] Cluster reachable (runtime=k3s)
[OK] Namespace claude-code-hub exists
[OK] Secret claude-code-hub-secrets 存在
[OK] postgres StatefulSet ready
[OK] redis StatefulSet ready
[OK] App ready replicas: 2
[OK] HPA configured
[OK] Ingress resource present
[OK] StorageClass local-path (k3s default)
[OK] In-pod health check
Summary: 10 passed, 0 warnings, 0 failures
Pod 卡在 Pending
kubectl -n claude-code-hub describe pvc postgres-data-postgres-0 看 Eventsbash scripts/deploy-k8s.sh --storage-class <correct-sc> --force-newApp Pod CrashLoopBackOff
cch logs 200 # 看应用日志
kubectl -n claude-code-hub describe pod -l app=claude-code-hub # 看 Events
DSN / REDIS_URL 错:检查 Secret 是否完整 cch secret dsncch logs 看 drizzle 报错,通常是 Postgres 还没就绪kubectl -n claude-code-hub port-forward svc/claude-code-hub 13500:80 再 curlIngress 域名不通
cch info 确认 Ingress host 和 className 正确kubectl -n ingress-nginx get pods升级失败自动回滚了
cch logs 500镜像拉不下来
-iimagePullSecrets(脚本暂不自动处理)deploy/k8s/
├── namespace.yaml
├── app/
│ ├── deployment.yaml # replicas, env, resources, 3 个 probe, preStop sleep
│ ├── service.yaml # ClusterIP / NodePort
│ ├── hpa.yaml # CPU 70% / 内存 80%, scaleUp/Down 策略
│ ├── pdb.yaml # maxUnavailable=1
│ └── networkpolicy.yaml # 仅在 Ingress 模式应用
├── postgres/
│ ├── statefulset.yaml # pg18 + 保守内存参数,50Gi PVC
│ ├── service.yaml # ClusterIP,不对外
│ └── networkpolicy.yaml # 仅允许 app 访问
├── redis/
│ ├── statefulset.yaml # redis:7-alpine,密码保护,AOF
│ ├── service.yaml # ClusterIP,不对外
│ └── networkpolicy.yaml # 仅允许 app 访问
└── ingress/
├── ingress.yaml # 标准 Ingress (nginx-ingress annotations)
└── traefik-ingressroute.yaml # Traefik CRD 备选
部署脚本会在渲染时替换以下占位符:
| 占位符 | 默认 |
|---|---|
{{NAMESPACE}} |
claude-code-hub |
{{APP_IMAGE}} |
ghcr.io/ding113/claude-code-hub:latest |
{{APP_REPLICAS}} |
2 |
{{APP_HPA_MIN}} / {{APP_HPA_MAX}} |
2 / 6 |
{{APP_SERVICE_TYPE}} |
ClusterIP / NodePort |
{{STORAGE_CLASS}} |
k3s local-path / 其他自动或空 |
{{PG_STORAGE_SIZE}} |
50Gi |
{{REDIS_STORAGE_SIZE}} |
10Gi |
{{TIMEZONE}} |
Asia/Shanghai |
{{INGRESS_HOST}} |
用户参数 |
{{INGRESS_CLASS}} |
自动 / 用户参数 |
| 资源 | docker-compose | K8s |
|---|---|---|
| App | service app |
Deployment claude-code-hub |
| PostgreSQL | service postgres |
StatefulSet postgres + PVC |
| Redis | service redis |
StatefulSet redis + PVC |
| 网络 | 同一 compose 网络 | ClusterIP Service + NetworkPolicy |
| 环境变量 | env_file: .env |
Secret + Deployment.env |
| 端口 | 23000:3000 |
Ingress / NodePort |
| 持久化 | ./data/postgres、./data/redis |
PVC (StorageClass) |