Manifest 里有什么
k8s/vibestrap.yaml 按这个顺序定义了四种资源:
- Namespace ——
vibestrap - Deployment —— Next.js 应用,1 副本,
/api/ping探针,合理的资源 requests/limits - Service —— ClusterIP,端口 80 → 3000
- Ingress —— nginx + cert-manager TLS,内置
www → apex跳转
harbor.funkro.com/vibestrap/vibestrap。集群里
没有任何迁移 Job——见下文 数据库迁移。
CI 帮你做了什么
.github/workflows/docker-build-push.yml 在以下情况会跑:
- 推送到
main分支 - 推送
v*形式的 tag - 在 GitHub Actions UI 手动触发
构建镜像
Dockerfile 的 runner stage 打成
harbor.funkro.com/vibestrap/vibestrap:<version>,
同时额外打 :latest tag。CI 里不放
kubeconfig。部署本身仍然是你手动敲命令 —— 这是有意为之。GitHub Actions secrets
在 Settings → Secrets and variables → Actions 里加这两个:| Secret | 内容 |
|---|---|
HARBOR_USERNAME | 你的 Harbor 账号用户名 |
HARBOR_PASSWORD | Harbor 密码或 robot account token |
首次部署
第一次kubectl apply 之前,集群里要先准备好三样东西。
1. Harbor 拉取密钥
让集群能从你的私有仓库拉镜像:harbor-secret,可以直接复制过来,不用
重新输密码:
2. 应用 Secret —— 只有两个字段必填
镜像启动时只校验DATABASE_URL 和 BETTER_AUTH_SECRET。其他环境变量
全部可选,留空时对应功能自动跳过——你可以先把服务跑起来,之后想要哪个
功能再回来填,重跑脚本 + kubectl rollout restart 就行。
kubectl create secret generic ... --from-env-file。Deployment
通过 envFrom: secretRef 把所有变量一次性注入。
3. ingress-nginx + cert-manager
Ingress 默认ingressClassName: nginx,并依赖一个名为 letsencrypt-prod
的 ClusterIssuer。如果集群里还没装:
letsencrypt-prod ClusterIssuer。
数据库迁移
迁移不在集群里跑。运行时镜像不带drizzle-kit,也没有 Job 要照看。
取而代之,触动 schema 的发布之前,从本机跑:
kubectl apply 新镜像。单副本部署本身就没竞态窗口——schema 什么时候动
完全你说了算。
生产 DB 在私有 VPC 里怎么办
如果本机直接连不到生产 DB,在集群内拉一个一次性 pod,借集群网络跑同一条命令。 完整的kubectl run 命令在 k8s/README.md 里;大致长这样:
部署
CI workflow 把 manifest 改好之后,每次部署是这样:长大之后怎么扩
Manifest 故意做得很薄 —— 真有需要再加。下面每一项都很小(10–30 行), 彼此独立。| 加什么 | 什么时候加 | 加在哪 |
|---|---|---|
HorizontalPodAutoscaler | 流量波动大,固定副本数浪费钱或扛不住 | k8s/ 下新文件 |
PodDisruptionBudget | 跑 ≥3 副本且想要节点 drain 零停机 | 新文件 |
NetworkPolicy | 多租户集群,想限制出站只到 DB 和外部 API | 新文件 |
topologySpreadConstraints | 多可用区集群,想容忍单可用区故障 | 内联在 Deployment spec 里 |
| 多环境 | 真的不只一个环境时 | k8s/staging/ 平行目录 |
故障排查
| 现象 | 可能原因 | 检查方法 |
|---|---|---|
ImagePullBackOff | Harbor 凭证错了,或 vibestrap namespace 里没有 harbor-secret | kubectl get secret harbor-secret -n vibestrap |
首次启动 Pod CrashLoopBackOff | 缺必填 env(DATABASE_URL、BETTER_AUTH_SECRET 等) | kubectl logs <pod> -n vibestrap —— Zod 会打印缺的 key |
| Pod 起来了但 DB 查询报 “column does not exist” | 上线新镜像之前忘了跑 pnpm db:migrate | 从本机跑迁移,然后重启 Deployment |
| TLS 证书一直 pending | DNS 没指向 ingress LB,或 ClusterIssuer 缺失 | kubectl describe certificate vibestrap-tls -n vibestrap |
| Stripe webhook 返回 400 “invalid signature” | STRIPE_WEBHOOK_SECRET 不对(live 和 test 串了) | 从 Stripe 后台重新复制,刷新 secret,重启 Deployment |