每个写着"一行命令把X部署到Kubernetes"的教程,技术上都没撒谎,实操上基本等于骗人。helm install确实只有一行。被跳过的部分,是那个没有存储类、没有入口控制器、没有cert-manager、也没有DNS的空集群。挡在你和那个能打开的网址之间的,正是这90%。

开源智能体平台ApowerB的Helm chart,安装命令真的只有一行。这篇文章讲的是这一行之外的全部——包括那些坑。

打开网易新闻 查看精彩图片

这个chart到底装了什么

ApowerB提供Helm chart(apowerb-chart,OCI格式,cosign签名),一次拉起的是整套栈,不只是应用本身:

  • 后端与Next.js前端:智能体运行时和它的界面
  • PostgreSQL:智能体存在这里,它们本质是数据行,加载时物化成可执行模块
  • th2etl:流水线与编排,带一个种子任务
  • th2pulse:日志与追踪存储
  • otel-collector:遥测路由
  • th2forecast:可选预测引擎,默认关闭
  • 一个PersistentVolumeClaim,用于上传文件、RAG产物和智能体池

这是一套平台,不是一个容器。也正因如此,下面这些集群前置条件,比部署一个玩具应用重要得多。

快车道:本地或开发集群

如果你已经有一个存储类能正常工作的集群,两条命令就能跑起来。

第一步,生成密钥。chart在没有密钥时会拒绝启动,这是有意设计的:

用umask 077配合openssl rand生成一组值,写进values-secrets.yaml,分别对应后端加密密钥、th2etl的API密钥、th2pulse的写入与查询令牌、PostgreSQL密码,然后chmod 600锁住文件权限。

第二步,安装:

helm upgrade --install apowerb,指向OCI仓库里的apowerb-chart,版本0.4.23,指定命名空间apowerb并创建它,带上values-secrets.yaml,超时设为10分钟。

然后做端口转发,打开界面:

kubectl -n apowerb port-forward svc/apowerb-frontend 13000:3000,浏览器访问localhost的13000端口。在界面里填一个模型密钥,你就在自己的集群上拥有了一个能用的智能体平台。这就是"一行命令"的部分,它是真的。

有一条规则会咬到所有人:每次helm upgrade都必须带上--values values-secrets.yaml。漏掉它,你就在一个正在运行的数据库底下把自己的凭据换掉了。这个文件要保管好,放进密钥管理系统做版本控制,不要提交到Git。

诚实版生产路径:从空集群到HTTPS网址

真实集群很少什么都接好了。下面是完整走法,也是大多数教程开始沉默的地方。

前置条件:Kubernetes 1.28以上。三个节点、每个4 vCPU加8 GB内存,能给出比较舒服的余量。先检查地基:

kubectl get nodes确认全部Ready;kubectl get storageclass确认不为空;kubectl get ingressclass确认存在。

第一步,能真正绑定的存储。精简版托管集群经常不带默认存储类。如果get storageclass是空的,就装一个:拉取local-path-provisioner v0.0.37的部署文件,apply它,等待local-path-storage命名空间里的部署滚动完成,超时120秒,然后给local-path这个存储类打上默认类的注解。

坑在这里:大多数存储类是WaitForFirstConsumer模式,所以单独一个PVC会一直停在Pending,看起来像坏了,其实没坏。要拿一个PVC和一个Pod一起测:

创建一个1Gi的probe-pvc,再创建一个busybox容器挂载它,往里面写一个marker文件并读出来,然后查看PVC状态和Pod日志,期望看到Bound和ok。如果这一步失败,就停下来,后面什么都不会成。

第二步,入口。查看ingressclass,查看所有命名空间里带LoadBalancer的服务,记下类名(Traefik和ingress-nginx是常见的托管插件)以及用于DNS的EXTERNAL-IP。

第三步,cert-manager和一个staging签发者。Let's Encrypt的失败限流是每小时5次,所以永远从staging开始:配置一个ClusterIssuer,指向staging的ACME目录,填上邮箱,指定私钥Secret,用http01求解,ingressClassName填第二步里实际的类名。

一个能搭进去一下午的坑:用ingressClassName,不要用已废弃的class注解。否则ACME挑战的Ingress拿不到可识别的类,证书会永远停在Ready: False。

第四步,带入口和TLS部署。还是同一条安装命令,这次打开公网访问:设置ingress.enabled为true,ingress.className填traefik,ingress.host填apowerb.example.com,ingress.tlsEnabled为true,ingress.annotations里的cert-manager.io/cluster-issuer填letsencrypt-staging。顺便创建第一个管理员:设置superadmin.email和superadmin.password。

第五步,DNS与验证。把一条A记录指向EXTERNAL-IP,然后查看证书,describe证书。卡在Ready: False?几乎总是这几种之一:DNS没有解析到负载均衡器、80端口没开(HTTP-01需要它)、class与ingressClassName的坑,或者staging的限流。一旦变成True,就把签发者换成生产环境。