> ## Documentation Index
> Fetch the complete documentation index at: https://starforge.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 用 Helm 部署

> 同一套 Kubernetes 部署，改为 values 驱动——适合多环境或 GitOps 流水线。

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
helm install starforge deploy/helm/starforge-console \
  --namespace starforge --create-namespace \
  --set image.repository=registry.company.com/forge/starforge-console \
  --set config.FORGE_INGEST_URL=http://starforge-console.starforge.svc.cluster.local \
  --set secrets.existingSecret=starforge-console-secrets
```

这个 chart 渲染出的对象和 [kustomize 清单](/zh-Hans/ops/install-kubernetes)一样：
ServiceAccount、ConfigMap、PVC、Role、RoleBinding、Service、Deployment，
以及可选的 Ingress 和 Secret。

跑多套环境、或者想用 values 驱动部署时选 chart；想一眼看清到底会 apply 什么时选清单。

## 一份可以直接改的 values

```yaml values.yaml theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
image:
  repository: registry.company.com/forge/starforge-console
  tag: "0.3.0"
imagePullSecrets:
  - name: starforge-registry

storage:
  accessMode: ReadWriteMany     # 没有商量余地，见下
  size: 2Ti
  storageClassName: nfs-client

config:
  FORGE_DEFAULT_FLEET_KIND: kuberay
  FORGE_STORAGE_ROOT: /starforge
  FORGE_PUBLIC_URL: https://starforge.company.com
  FORGE_INGEST_URL: http://starforge-console.starforge.svc.cluster.local
  FORGE_KUBERAY_RAY_VERSION: "2.55.1"
  FORGE_K8S_SHM_SIZE: 64Gi
  FORGE_KUBERAY_PRERUNNING_DEADLINE_S: "1800"

secrets:
  existingSecret: starforge-console-secrets

ingress:
  enabled: true
  className: nginx
  host: starforge.company.com
  tls:
    enabled: true
    secretName: starforge-console-tls
```

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
helm upgrade --install starforge deploy/helm/starforge-console \
  -n starforge --create-namespace -f values.yaml
```

## 三个决定成败的值

<ParamField path="storage.accessMode" type="ReadWriteMany" required>
  RWO 的 claim **不会失败**。Kubernetes 会给每个 Pod 各自一个卷，
  于是多节点作业的 checkpoint 分片散落在不同 Pod 上，这次 run 再也续不了——
  而日志里没有任何东西说明原因。chart 默认 RWX；StorageClass 必须真的支持它。
</ParamField>

<ParamField path="config.FORGE_INGEST_URL" type="url" required>
  训练 Pod 往它 POST 指标。用集群内服务名。
  外部 ingress 地址会先出集群再绕回来；`127.0.0.1` 是 worker 自己的回环。
</ParamField>

<ParamField path="secrets.existingSecret" type="string" required>
  没有 `FORGE_WEB_JWT_SECRET`，每个进程各用一把自己的密钥签名：
  重启即全员掉线，多副本根本不可用。chart 的安装提示会在两项都没设时给出警告。
</ParamField>

## 密钥

`secrets.create: true` 会从 `secrets.data` 渲染一个 Secret——
测试集群上很方便，生产上不对，因为那些值会落进你的 release 历史。

把 `secrets.existingSecret` 指向由 `kubectl create secret`、Sealed Secrets
或 External Secrets Operator 产生的 Secret：

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
kubectl -n starforge create secret generic starforge-console-secrets \
  --from-literal=FORGE_WEB_JWT_SECRET="$(openssl rand -hex 32)" \
  --from-literal=FORGE_DB_URL='postgresql+psycopg://forge:...@postgres:5432/forge' \
  --from-literal=FORGE_REDIS_URL='redis://:...@redis:6379/0' \
  --from-literal=FORGE_S3_SECRET_KEY='...' \
  --from-literal=FORGE_SECRET_ENC_KEY='...'
```

## chart 替你做的一件事

`FORGE_K8S_STORAGE_PVC` 是从 chart 实际创建的那个 claim 填进去的，
所以执行器被告知的永远是真实存在的那个 claim。这一对关系手写时很容易错开——
执行器去检查一个并非被挂载的 claim、报告健康，而这个错位只有在某次多节点 run 续不上时才暴露。

只有复用一个不归 chart 所有的 claim 时才需要覆盖它：

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
helm install starforge deploy/helm/starforge-console --set storage.existingClaim=my-nfs-claim
```

## apply 之前先验

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
helm lint deploy/helm/starforge-console
helm template sf deploy/helm/starforge-console -f values.yaml | kubectl apply --dry-run=client -f -
```

## 确认成功

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
kubectl -n starforge rollout status deploy/starforge-console
kubectl -n starforge get pvc -o custom-columns=NAME:.metadata.name,MODES:.spec.accessModes
kubectl -n starforge port-forward svc/starforge-console 8080:80
curl -s localhost:8080/api/cluster/health | jq .storage
```

最后那一条最值得读：它把 `FORGE_K8S_STORAGE_SHARED` 的声明和 claim 的真实访问模式做核对，
这正是能在作业之前抓到 RWO claim 的那道检查。

<Note>
  这个 chart 的每次改动都会跑 `helm lint` 和 `helm template` 验证。
  对着真实集群安装不是这里的 CI 能做的事——没有哪个 runner 有集群——
  所以在你的集群上第一次安装就是第一次真实测试。先跑上面那条 dry-run。
</Note>
