Skip to main content
deploy/k8s/ 是一套 kustomize overlay,覆盖命名空间、配置、密钥、RBAC、Deployment、 Service、Ingress 和两个 PVC。

它会创建什么

apply 之前先把镜像指向你的仓库:
deploy/k8s/kustomization.yaml

真正要紧的是那个存储卷

ReadWriteMany 不是可选项,而 RWO 是静默失败的。 RWO 的 claim 不会报错—— Kubernetes 会给每个 Pod 各自一个卷。多节点作业于是把 checkpoint 分片散落在不同 Pod 上, 这次 run 再也续不了,而日志里没有任何东西说明原因。执行器的健康检查会把 FORGE_K8S_STORAGE_SHARED 和 claim 的实际 accessModes 核对。 首次部署后去读那个结果,别想当然。
控制台把这个 claim 挂在 FORGE_STORAGE_ROOT 指定的那个路径上—— 它往 runs/<user>/<exp>/<run_id>/work 里放作业目录、测量磁盘压力、执行回收。 训练 Pod 挂载同一个 claim,所以控制台写的路径就是作业打开的路径。 容量按「权重缓存 + 数据集缓存 + 所有 run 目录」估。2Ti 是一个起点而不是建议值; 光是权重缓存,每个基座模型就是几十 GB。

推荐配置

deploy/k8s/configmap.yaml
其中四项值得理解而不是照抄:
训练 Pod 往它回传。用外部 ingress 地址会先出集群再绕回来;服务 DNS 名不会。 绝不能填 127.0.0.1——那是 worker 自己的回环。
不一致的症状是「集群起来了但 worker 注册不上」,而唯一的线索是一行很容易淹没在启动输出里的版本警告。
Ray 的 object store 就在 /dev/shm 里。用默认值的话,稍大一点的 batch 立刻 OOM。 它由内存支撑,所以它加上内存上限不能超过物理内存。
没有它,拉不到的镜像或者没有节点满足的 nodeSelector 会让作业无限期 Pending,同时一直占着队列位置。

密钥

secret.example.yaml 只是用来说明结构。上生产前请换成真实来源—— kubectl create secret、Sealed Secrets 或 External Secrets Operator—— 并把它从 kustomization.yaml 里移除。 至少要有:FORGE_WEB_JWT_SECRETFORGE_DB_URLFORGE_REDIS_URLFORGE_S3_SECRET_KEYFORGE_SECRET_ENC_KEY,以及 OIDC 的 client secret。

副本数

清单里是单副本,这是安全的默认值。往上扩之前:
  • FORGE_DB_URL 必须指向 Postgres。SQLite 是单写的
  • FORGE_WEB_JWT_SECRET 必须固定,否则副本之间互相拒绝对方签的 token
  • FORGE_REDIS_URL 必须配置,否则后台角色会整个停掉而不是跨副本不安全地跑—— 存储记账、诊断、看门狗和每日日报全都不再运行
  • 把后台角色放进它自己的 Pod。设 FORGE_INPROCESS_WORKERS=0,再应用 worker Deployment——kustomize 路径下是 worker.yaml,Helm 下是 worker.enabled=true。诊断与日报的 tick 会调 LLM 并一次占住事件循环好几秒; 拆出去之后它们不再抬高 API 尾延迟,控制台副本也变成无状态的。副本数保持 1 是对的:每个角色都经 Redis 选主,第二个副本只会空转

确认成功

然后看执行器自己的视角——它才能告诉你存储卷是不是真的 RWX: