Skip to content
English

应用层部署(Helm) ​

应用层由 chatkit Helm chart 部署 FinClaw 全部业务微服务(api-gateway / identity-service / orchestrator / ai-infra-rs / claw-fleet-manager 等)。基础层(RKE2 + 状态服务)必须已就绪。

Chart 结构 ​

Chart.yaml 元数据:apiVersion: v2、name: chatkit、version: 0.1.0、appVersion: 1.0.0,描述为 "ChatKit Middleware on Kubernetes (dual-track with Docker Compose / fleet.sh)"。

templates/ 目录清单:

模板渲染对象用途
platform-service.yamlplatform namespace全部平台微服务 Deployment + Service(api-gateway / identity-service / orchestrator / ag-ui-server / claw-fleet-manager 等);nodePort 可选
shared-claw.yamlplatform namespaceProfile A(B0 PoC)共享 ai-infra-rs Deployment + Service
tenant-claw.yamlclaw namespaceProfile B 静态 gitops 租户 claw StatefulSet + headless Service(动态租户由 claw-fleet-manager 经 K8s API 应用同样 manifest)
restate-bundled.yamlplatform namespace可选的集群内 Restate stub,仅 PoC 用;生产用 externalServices 指向基础层
restate-claw-namespace-alias.yamlclaw namespaceExternalName alias,让租户 claw 通过 ext-restate-svc 跨命名空间解析 Restate
ingress.yamlcluster入口 Ingress,支持 splitStreamingPaths 把 SSE 路径直接打到 ag-ui-server
storage.yamlplatform namespace平台 PVC(workspaces / aiInfraData / skillsData / docToolkitCache)
storage-nfs.yamlclusterNFS CSI 静态 PV(profile=csi-nfs)
storage-claw-namespace.yamlclaw namespace租户 claw 命名空间下的 NFS PV 与 PVC
storage-extra.yamlplatform namespace额外存储卷
fleet-manager-rbac.yamlplatform + claw namespaceNamespace + ServiceAccount + Role/RoleBinding,让 claw-fleet-manager 能管理租户 claw StatefulSet
identity-keys.yamlplatform namespaceidentity-service 的 JWT 签名密钥 Secret(existingSecret 或 chart files 两种来源)
secrets.yamlplatform namespaceinternal-service-token / cron-internal-token / llm-api-key;chart 在 render 时即拒绝空 / CHANGE_ME / 旧占位符
infra-configmap.yamlplatform namespace把 infra.* 端点文档化进 ConfigMap
app-config.yamlplatform namespace把 chart-config/* 配置文件(services.yaml / ai-infra.yaml / identity-service.yaml / skill-service.yaml / mcp-servers.yaml / persona-templates.json / nginx.conf / inbound.yaml)打包成 ConfigMap 并按 subPath 挂载
external-services.yamlcluster把集群外服务(基础层 Restate / TEI)以 Headless Service + Endpoints 暴露给集群内 DNS
searxng.yamlplatform namespaceClaw web_search 用的 SearXNG Deployment + Service
_helpers.tpl-chatkit.image / chatkit.storageProfile / chatkit.storageClaimName 等 helper

服务镜像默认通过 global.registry + global.tag 组合,单服务 hotfix 可经 images.overrides.<svc>.full 完整覆盖。

values 层次 ​

Helm 多文件 overlay,按以下顺序 -f 合并(后者覆盖前者):

文件用途何时使用
values.generated.yamlSSOT:服务端口 / 副本 / peer URL / servicesEnv,由 config/services.yaml 自动生成始终
values.yaml全局 registry / tag / secrets 默认 / claw / storage / ingress / infra.restate / clawFleet 默认始终
values-basic.yaml默认 stack overlay(stack: default;文件名 basic 为历史遗留)始终
values-poc-basic.yamlProfile A(B0 PoC 共享单 claw)PoC / 共享 claw 场景
values-k8s-fleet.yamlProfile B(per-tenant claw via claw-fleet-manager K8s backend)生产多租户
values-k8s-ingress.yaml启用外部 Ingress + SSE sticky session需要外部域名接入时
values-k8s-nfs-example.yamlNFS CSI 静态 PV 接入示例用 NFS 做存储时复制为 site overlay
values-k8s-external-example.yaml集群外 TEI / Restate 经 Headless Service 接入示例TEI 在集群外时参考
values-k8s-tenant-examples.yaml静态 gitops 租户 claw items 示例用静态 claw 时参考
values-site.yaml(自建)站点特有:image registry、密钥、infra.* 主机 IP、NodePort、license始终
deploy/sites/<customer>/*(可选)多客户拆分:site.yaml / infra.yaml / images.yaml / secrets.yaml / services.env.yaml多客户环境

values.generated.yaml 是 SSOT,由发布流程自动生成,禁止手工编辑;如需修改服务端口或 infra 端点,请联系凡泰极客支持。

内部 registry 镜像拉取 ​

基础层 ansible 部署的内部 registry 域名为 registry.finogeeks.internal:5000。站点 values-site.yaml 中设置:

yaml
global:
  registry: registry.finogeeks.internal:5000/finclaw
  tag: "1.1.11"                    # 与离线包版本一致
  imagePullPolicy: IfNotPresent
  imagePullSecrets: []             # 私有仓库需要凭证时填 [{ name: harbor-pull }]

私有 registry 凭证:

  • 若 registry 启用认证,先在集群内创建 imagePullSecret,再在 global.imagePullSecrets 引用
  • 单服务 hotfix 不必整包升级,用 images.overrides.<svc>.full 完整覆盖一条镜像即可

Ingress 与 SSE 长连接 ​

ingress.yaml 默认 disabled(ingress.enabled: false)。需要外部域名接入时合并 values-k8s-ingress.yaml,并设置 ingress.host:

yaml
ingress:
  enabled: true
  host: chatkit.example.com
  className: nginx
  splitStreamingPaths: true
  agUiServer:
    stickySessions:
      enabled: true
services:
  ag-ui-server:
    replicas: 2

关键设计:

  • api-gateway catch-all:/ 路径打到 api-gateway,承担静态资源、REST、auth_request 子请求;proxy-read-timeout 默认 1200s
  • SSE 长连接路径(splitStreamingPaths: true):/agent(Prefix)与 /events(Exact)绕过 api-gateway 直接打到 ag-ui-server,proxy-read-timeout 提升到 86400s、关闭 proxy-buffering、proxy_http_version 1.1、X-Accel-Buffering: no
  • Sticky session:ag-ui-server 多副本时通过 ingress cookie affinity 把客户端固定到某个 Pod,因为 ag-ui-server 进程内有运行态注册表;cookie 名 chatkit-ag-ui-affinity、max-age 86400
  • clientMaxBodySize:默认 100m,与 api-gateway 一致

Restate 外置 / NFS 存储 / external-services ​

Restate 外置(生产默认) ​

infra.restate.mode: external(默认),chart 不部署 Restate,而是经 externalServices 用 Headless Service + Endpoints 把基础层 Restate 暴露成集群内 DNS ext-restate-svc:

yaml
externalServices:
  enabled: true
  items:
    restate:
      name: ext-restate-svc
      ips: ["10.0.1.187", "10.0.1.188", "10.0.1.189"]   # 基础层 restate 分组所有节点 IP
      ports: [26180, 26182]
infra:
  restate:
    ingressUrl: http://ext-restate-svc:26180
    adminUrl: http://ext-restate-svc:26182
    clawNamespaceAlias:
      enabled: true
      serviceName: ext-restate-svc

restate-claw-namespace-alias.yaml 会在 chatkit-claw 命名空间再创建一个 ExternalName,让租户 claw Pod 跨命名空间解析 Restate。

PoC 场景若要 chart 内置 Restate stub,设 infra.restate.bundled.enabled: true,渲染 restate-bundled.yaml(StatefulSet,单副本,docker.restate.dev/restatedev/restate:1.3.2,10Gi 存储)。生产禁用。

NFS 存储 ​

storage.profile: csi-nfs 时,chart 渲染 storage-nfs.yaml 与 storage-claw-namespace.yaml,创建一组静态 PV(reclaimPolicy: Retain、storageClassName: ""、nfs.csi.k8s.io driver)。NFS server 需提前 export 每个 PV 对应的子目录:

shell
mkdir -p /nfs/finclaw/{workspaces-pvc,ai-infra-data-pvc,doc-toolkit-cache-pv,skills-data-pvc}
echo '/nfs/finclaw/workspaces-pvc *(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports
# 其余三条同上
exportfs -ra

Profile B 还需为每租户 claw 的 volumeClaimTemplates 准备动态 StorageClass(不要用未 export 的 /nfs 根,CSI 会报 "read-only file system")。

External-services ​

external-services.yaml 是通用机制,不只用于 Restate。集群外 TEI 也可同样接入:

yaml
externalServices:
  items:
    tei:
      name: chatkit-tei
      ips: ["10.0.6.11", "10.0.6.3"]
      ports: [26117]
infra:
  memory:
    enabled: true
    embeddingEndpoint: "http://chatkit-tei:26117/embed"

安装步骤 ​

Step 1:生成 / 复用 Identity JWT 密钥 ​

bash
./deploy/scripts/generate-identity-keys-for-k8s.sh \
  --output-dir ./identity-keys \
  --create-secret --namespace chatkit \
  --secret-name chatkit-identity-keys

site overlay 中引用:

yaml
identityKeys:
  enabled: true
  existingSecret: chatkit-identity-keys

Step 2:准备 values-site.yaml ​

从 values-site-example.yaml 复制,至少填写:

  • global.registry / global.tag:与 push-images-to-registry.sh 的 REGISTRY 一致
  • secrets.internalServiceToken:强随机串,chart 在 render 时即拒绝空 / CHANGE_ME / 旧占位符
  • secrets.llmApiKey:LLM 凭证
  • infra.postgres.host / infra.timescaledb.host:基础层 PG/Timescale 主库 IP,不要用 ext-*-svc Headless DNS 做写库
  • infra.redis.url / infra.nats.url / infra.restate.ingressUrl / infra.restate.adminUrl
  • externalServices.items.restate.ips:基础层 restate 分组所有节点 IP

Step 3:推镜像到内部 registry ​

bash
./deploy/scripts/load-images.sh                              # 加载到本机 docker
./deploy/scripts/push-images-to-registry.sh registry.finogeeks.internal:5000/finclaw

Step 4:helm install ​

Profile B(生产推荐):

bash
helm upgrade --install chatkit deploy/k8s/helm/chatkit \
  -f deploy/k8s/helm/chatkit/values.generated.yaml \
  -f deploy/k8s/helm/chatkit/values.yaml \
  -f deploy/k8s/helm/chatkit/values-basic.yaml \
  -f deploy/k8s/helm/chatkit/values-k8s-fleet.yaml \
  -f deploy/k8s/helm/chatkit/values-k8s-ingress.yaml \
  -f values-site.yaml \
  --namespace chatkit --create-namespace

Profile A(PoC 共享 claw):

bash
helm upgrade --install chatkit deploy/k8s/helm/chatkit \
  -f deploy/k8s/helm/chatkit/values.generated.yaml \
  -f deploy/k8s/helm/chatkit/values.yaml \
  -f deploy/k8s/helm/chatkit/values-basic.yaml \
  -f deploy/k8s/helm/chatkit/values-poc-basic.yaml \
  -f values-site.yaml \
  --namespace chatkit --create-namespace

建议正式安装前先 --dry-run=server 校验模板渲染与 K8s API server 端的引用完整性。

License 硬门禁 ​

identity-service 启动时校验 DEPLOYMENT_LICENSE_KEY + DEPLOYMENT_LICENSE_CIPHER,缺失或解密失败会 fail-fast。两者通过 servicesEnv(或 services.env.yaml)注入:

  • DEPLOYMENT_LICENSE_KEY:base64url(no padding) 的 32 字节随机密钥
  • DEPLOYMENT_LICENSE_CIPHER:0x01 || IV(12) || tag(16) || AES-256-GCM(plaintext),AAD 为 ck-deployment-license-v1,plaintext 为 {"expiresAt","customer","issuedAt"} JSON

KEY/CIPHER 由凡泰签发并提供(离线包默认内置 30 天有效期),到期或需续期时联系凡泰,更新流程见 更新 License。

安装后验证 ​

bash
./scripts/verify-k8s-install.sh --gateway http://<node-ip>:30001
# 完整 e2e
./scripts/verify-k8s-install.sh --gateway http://10.0.0.5:30001 --profile b --e2e
# 仅 HTTP 检查(无 kubectl 访问的机器)
./scripts/verify-k8s-install.sh --gateway http://10.0.0.5:30001 --skip-kubectl

verify-k8s-install.sh 检查项:

  1. Kubernetes 集群访问与命名空间权限
  2. 平台 Pod 状态:api-gateway / identity-service / orchestrator / ag-ui-server / claw-fleet-manager Deployment ready;无 Pending / CrashLoop
  3. 平台 PVC 全部 Bound
  4. claw-fleet-manager /health:status: ok、runtime_backend 与 Profile 一致(Profile B 应为 kubernetes)
  5. Profile B 租户 claw Pod ready、PVC Bound、cron Restate 已注册、跨命名空间访问 identity、INTERNAL_SERVICE_TOKEN 已注入
  6. 选项 --e2e:注册 / 登录 / agent SSE 烟雾测试

补充手工检查:

bash
kubectl get all --all-namespaces | grep -E "chatkit|claw"
kubectl -n chatkit get deploy,svc,ingress,pvc,cm,secret
kubectl -n chatkit-claw get pods,svc,pvc
helm -n chatkit history chatkit

更多排障命令见 排障与巡检。

Digital Ecosystem Infrastructure.