
1. 为什么你的 K8s 集群需要 Traefik 和 StatefulSet 一起上Kubernetes 集群跑起来之后真正让人头疼的往往不是 Pod 能不能启动而是两件事外面的流量怎么稳定进来里面的有状态服务怎么稳定存数据。Traefik 作为 Ingress 控制器解决的是南北向流量入口问题StatefulSet 解决的是有状态工作负载的稳定网络标识和独立存储问题。这两个东西单独用都不难难的是放在同一个集群里配合着用还要让 AI 编码工具能通过统一 Key 接入你的开发流程。我见过太多集群Deployment 跑了一堆无状态服务Ingress 规则也写了但一遇到 MySQL 主从、Redis Cluster、Kafka 这种有状态服务就抓瞎。Pod 重启后 IP 变了从库连不上主库PVC 没绑对数据丢了都不知道找谁。更麻烦的是团队里每个人用的 AI 编码工具五花八门有人用 Claude Code有人用 Cline有人用 CodexAPI Key 散落在各个配置文件里换个人接手就得重新配一遍。这篇内容面向的是已经在跑 K8s 集群、需要把南北向流量和有状态服务一起落地的运维和开发人员。你会看到 Traefik IngressRoute 的完整 YAML 骨架、StatefulSet 加 Headless Service 的可复制配置以及怎么通过 TaoToken 的统一 API 通道把 AI 编码工具的 settings.json 和 config.toml 配好让整个团队用同一套 Key 和 Base URL。所有配置都是实测能跑通的你直接改改域名和镜像地址就能用。Traefik 的核心价值在于它监听 K8s API自动发现 Ingress 和 Service 的变化动态生成路由规则不需要你手动 reload。StatefulSet 的核心价值在于它为每个 Pod 提供稳定的主机名比如koten-sts-0.sts-svc.default.svc.cluster.local和独立的 PVCPod 重建后名字和存储都不变。这两者配合你就能在同一个集群里既跑无状态的 Web 服务又跑有状态的数据库中间件。2. 用 Helm 部署 Traefik 并暴露 Dashboard 的完整操作Traefik 的安装方式有好几种Helm 是最省事的。我习惯先把 Chart 拉到本地改完 values.yaml 再装这样出问题好排查。下面这套流程在 K8s 1.24 和 Helm 3.x 上验证过。先添加 Traefik 的 Helm 仓库并更新索引helm repo add traefik https://traefik.github.io/charts helm repo update拉取指定版本的 Chart 包我用的 23.1.0 对应 Traefik v2.10.1helm pull traefik/traefik --version 23.1.0 tar xf traefik-23.1.0.tgz cd traefik如果你在内网环境需要把镜像推到私有 Harbor。先拉取官方镜像再打标签推送docker pull traefik:v2.10.1 docker tag traefik:v2.10.1 harbor.koten.com/koten-traefik/traefik:v2.10.1 docker push harbor.koten.com/koten-traefik/traefik:v2.10.1修改 values.yaml把镜像地址换成私有仓库同时把 Service 类型改成 NodePort 并指定端口。这里注意nodePort字段在service下面别改错位置image: repository: harbor.koten.com/koten-traefik/traefik tag: v2.10.1 service: type: NodePort nodePort: 32080 dashboard: enabled: true安装到 default 命名空间helm install traefik ./traefik -n default装完后检查 Pod 状态看到Running就对了kubectl get pods -l app.kubernetes.io/nametraefikDashboard 默认没有对外暴露用 port-forward 临时开一下kubectl port-forward $(kubectl get pods -l app.kubernetes.io/nametraefik -o name) --address0.0.0.0 9000:9000浏览器访问http://节点IP:9000/dashboard/能看到 Traefik 的 Dashboard 页面就说明部署成功了。Dashboard 里会显示当前的路由、服务、中间件状态后面排查 Ingress 问题全靠它。这里有个坑要注意Helm 安装的 Traefik 默认只监听web80和websecure443两个入口点。如果你用 NodePort 暴露需要在 values.yaml 里确认ports.web.nodePort和ports.websecure.nodePort都配了否则 Service 创建时会报端口冲突。我一般把 web 设成 32080websecure 设成 32443避免和集群里其他 NodePort 服务撞车。另外Traefik 的 CRD 在 Helm 安装时默认会一起装。如果你之前手动装过旧版 CRD升级时可能报customresourcedefinition already exists的错。解决办法是先删掉旧的 CRD 再重装或者加--skip-crds参数跳过 CRD 安装。生产环境建议把 CRD 单独管理不要和 Helm release 绑死。3. 可复制的 Traefik IngressRoute 与 StatefulSet YAML 骨架这一节直接给能用的 YAML。先看 Traefik 的 IngressRoute它比原生 Ingress 更灵活支持中间件、优先级、TLS 配置。下面这个例子把apps01.koten.com和apps02.koten.com分别路由到两个 ServiceapiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: koten-ingressroute-apps namespace: default spec: entryPoints: - web routes: - match: Host(apps01.koten.com) kind: Rule services: - name: apps-v1 port: 80 - match: Host(apps02.koten.com) kind: Rule services: - name: apps-v2 port: 80对应的 Deployment 和 Service 骨架apiVersion: apps/v1 kind: Deployment metadata: name: deploy-nginx-v1 labels: apps: myweb spec: replicas: 3 selector: matchLabels: apps: v1 template: metadata: labels: apps: v1 spec: containers: - name: v1 image: harbor.koten.com/koten-web/nginx:1.24.0-alpine ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: apps-v1 spec: selector: apps: v1 ports: - port: 80 targetPort: 80StatefulSet 加 Headless Service 的骨架注意clusterIP: None和serviceName的对应关系apiVersion: v1 kind: Service metadata: name: sts-svc spec: clusterIP: None selector: apps: v1 ports: - port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: koten-sts-all spec: replicas: 3 serviceName: sts-svc selector: matchLabels: apps: v1 volumeClaimTemplates: - metadata: name: data spec: storageClassName: managed-nfs-storage accessModes: - ReadWriteMany resources: requests: storage: 2Gi template: metadata: labels: apps: v1 spec: containers: - name: v1 image: harbor.koten.com/koten-nginx/nginx:1.24.0-alpine volumeMounts: - name: data mountPath: /usr/share/nginx/html现在说 TaoToken 的接入配置。TaoToken 提供统一的 API 通道Base URL 是https://taotoken.net/api你可以在官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册后拿到 Key。Claude Code 的 settings.json 放在~/.claude/settings.json配置片段如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的TaoTokenKey } }Cline 的 config.toml 或者 VS Code 设置里Base URL 填https://taotoken.net/apiModel ID 根据你用的模型填比如claude-sonnet-4-20250514。Codex 的 auth.json 在~/.codex/auth.json格式类似{ base_url: https://taotoken.net/api, api_key: sk-你的TaoTokenKey }三件套记住Base URL 统一用https://taotoken.net/apiKey 从 TaoToken 控制台拿Model ID 按实际模型填。这样团队里所有人用同一套配置换工具也不用重新申请 Key。4. 验证请求与成功结果从 curl 到 Dashboard 全链路检查配置写完不验证等于没写。这一节按顺序走一遍验证流程每一步都有预期结果。先确认 Traefik 的 Pod 和 Service 状态kubectl get pods -l app.kubernetes.io/nametraefik kubectl get svc traefik预期看到 Pod 是RunningService 的PORT(S)显示80:32080/TCP,443:32443/TCP。如果 NodePort 没显示回去检查 values.yaml 里的service.type和nodePort配置。验证 IngressRoute 是否被 Traefik 识别kubectl get ingressroute kubectl describe ingressroute koten-ingressroute-appsDashboard 里HTTP选项卡下应该能看到两条路由规则状态是enabled。如果显示disabled多半是entryPoints写错了确认是web而不是websecure。用 curl 带 Host 头测试路由curl -H Host: apps01.koten.com -sI http://节点IP:32080 | grep -i server curl -H Host: apps02.koten.com -sI http://节点IP:32080 | grep -i server预期返回的Server头分别是nginx/1.24.0和nginx/1.25.1。如果返回 404检查 Service 的selector是否和 Pod 的 label 匹配如果返回 502检查 Pod 是否真的在监听 80 端口。StatefulSet 的验证分三步。先看 Pod 是否按顺序创建kubectl get pods -l appsv1 -w你会看到koten-sts-0先 Running然后koten-sts-1最后koten-sts-2。这是 StatefulSet 的默认行为podManagementPolicy是OrderedReady。测试 Headless Service 的 DNS 解析和 Pod 间通信kubectl exec -it koten-sts-0 -- sh ping koten-sts-1.sts-svc.default.svc.cluster.local -c 3 ping koten-sts-2.sts-svc.default.svc.cluster.local -c 3预期三个 Pod 之间能互相 ping 通丢包率 0%。注意主机名格式是pod-name.service-name.namespace.svc.cluster.local少一段都解析不了。验证独立存储。在koten-sts-0里写个文件kubectl exec -it koten-sts-0 -- sh -c echo pod-0-data /usr/share/nginx/html/index.html kubectl exec -it koten-sts-1 -- cat /usr/share/nginx/html/index.html预期koten-sts-1里看不到pod-0-data因为每个 Pod 绑的是独立的 PVC。然后删掉koten-sts-0再等它重建kubectl delete pod koten-sts-0 kubectl get pods -l appsv1 -w kubectl exec -it koten-sts-0 -- cat /usr/share/nginx/html/index.html预期重建后的 Pod 名字还是koten-sts-0文件内容还在。这就验证了稳定网络标识和持久化存储都生效了。最后验证 TaoToken 通道。用 curl 直接请求 APIcurl -s https://taotoken.net/api/v1/models \ -H Authorization: Bearer sk-你的TaoTokenKey | head -c 200预期返回模型列表的 JSON。如果返回 401检查 Key 是否复制完整如果返回 404检查 Base URL 是否多了或少了/v1。Claude Code 里跑一个简单对话测试能正常返回就说明 settings.json 配对了。5. 本篇常见报错排查401、local proxy failed 与 OAuth 问题这一节列几个我实际踩过的坑每个都给出报错原文和解决动作。报错一401 Unauthorized或invalid api key这个最常见。TaoToken 的 Key 格式是sk-开头的一长串复制时容易漏掉尾部字符。检查settings.json或auth.json里的 Key 是否完整前后有没有多余空格。另外确认 Base URL 是https://taotoken.net/api不要写成https://taotoken.net/api/v1路径拼接由客户端负责。报错二local proxy failed或connection refused这个通常出现在 Claude Code 或 Cline 配置了本地代理端口的情况下。如果你之前配过HTTP_PROXY或HTTPS_PROXY环境变量客户端会尝试走本地代理但代理没启动就报这个错。解决方法是清掉相关环境变量或者确认代理服务在运行。TaoToken 的 API 通道不需要额外代理直接连就行。报错三reading choices或unexpected end of JSON input这个报错说明请求发出去了但返回的内容不是预期的 JSON 格式。常见原因是 Model ID 填错了比如把claude-sonnet-4-20250514写成了claude-sonnet-4。去 TaoToken 的模型列表接口查一下可用模型 ID填准确。另一个可能是请求超时网络抖动导致响应截断重试一次通常能好。报错四OAuth token expired或authentication failed如果你用的是 Codex 的 OAuth 登录模式切到 API Key 模式后需要清掉旧的 OAuth 缓存。Codex 的缓存一般在~/.codex/下面删掉auth.json重新生成确保里面是base_url和api_key两个字段而不是access_token和refresh_token。报错五Traefik Dashboard 显示路由disabled检查 IngressRoute 的entryPoints是否和 Traefik 启动参数里的--entrypoints.web.address:80对应。Helm 默认的 entryPoint 名字是web和websecure如果你自定义了名字IngressRoute 里也要同步改。另外确认 IngressRoute 的namespace和 Service 的namespace一致跨命名空间引用需要加namespace字段。报错六StatefulSet Pod 一直Pending多半是 PVC 绑不上。kubectl describe pvc data-koten-sts-0看事件如果是no persistent volumes available检查 StorageClass 名字是否写对NFS provisioner 是否在运行。如果是waiting for first consumer说明 StorageClass 的volumeBindingMode是WaitForFirstConsumer这是正常的Pod 调度后才会绑。报错七Headless Service DNS 解析失败确认 Service 的clusterIP字段是None不是空字符串。另外 StatefulSet 的serviceName必须和 Headless Service 的metadata.name完全一致。DNS 格式是pod-name.service-name.namespace.svc.cluster.local在 Pod 内部可以省略.cluster.local后缀但跨命名空间访问必须写全。6. 把 AI 编码工具接进 K8s 工作流的统一入口Traefik 和 StatefulSet 配好之后你的 K8s 集群就有了稳定的流量入口和有状态服务底座。接下来把 AI 编码工具接进来让日常写 YAML、排查 Pod 日志、生成 IngressRoute 这些活儿效率更高。TaoToken 在这里的角色是统一 Key 和 API 通道。团队里不管谁用 Claude Code、Cline 还是 Codex都从同一个控制台拿 KeyBase URL 统一填https://taotoken.net/api。新人入职不用挨个申请账号离职回收也只需要停一个 Key。模型切换在客户端改 Model ID 就行不用动网络配置。具体操作上Claude Code 用户改~/.claude/settings.jsonCline 用户在 VS Code 设置里填 Base URL 和 KeyCodex 用户改~/.codex/auth.json。三件套配好之后跑一个连通性测试确认能返回模型列表。如果遇到 401 或local proxy failed按第 5 节的排查步骤走一遍基本都能解决。长期做 K8s 运维和 Agent 开发的团队建议直接上 Coding Plan把 Key 管理和用量统计集中起来。API Keys 页面可以生成和管理 Key接入文档里有各客户端的详细配置示例。模型对话页面可以快速验证某个模型是否可用不用写代码就能测。最后给一个实用技巧把 Traefik 的 Dashboard 端口转发命令写成 alias加到~/.bashrc里。每次排查 Ingress 问题直接敲traefik-dash就能打开比记那串kubectl port-forward命令省事得多。StatefulSet 的 PVC 命名规则是volumeClaimTemplate-name-statefulset-name-ordinal删 Pod 不删 PVC数据就一直在。真要清理存储记得先确认 PVC 名字再删别手抖。