1. 为什么要在 traefik 入口层做统一 Key 接入
在 k8s 集群里跑 AI 工具链,最烦的不是 Pod 起不来,而是每个工具都要单独配一遍 API Key。Cline 一套、Claude Code 一套、Codex 又一套,改一次 Key 要翻五六个配置文件,改漏一个就报 401。我试过把 Key 散落在各个 Namespace 的 Secret 里,结果排查问题时连自己都记不清哪个工具用的是哪个 Key。
这个问题的本质是:AI 工具的接入配置没有收敛到统一入口。traefik 作为集群的 Ingress 入口,天然适合承担这个角色——所有外部请求都经过它,那所有 AI 服务的调用也可以在这里做一层统一转发。你只需要在 traefik 层维护一份 Base URL 和 Key,下游工具全部指向这个入口,改 Key 只改一处。
具体来说,这套方案解决三个痛点。第一是配置分散:多个 AI 工具各自维护 Base URL 和 Key,版本不一致时排查成本极高。第二是验证困难:新接入一个工具,要单独测连通性,没有统一的验证入口。第三是切换成本高:想换一个模型通道,得逐个工具改配置,容易漏改。
TaoToken 在这里的角色是提供统一的 API 通道。它的 API 地址是https://taotoken.net/api,兼容 OpenAI 风格的接口格式,所以任何支持自定义 Base URL 的工具都能接进来。你可以在 traefik 层把它作为一个 upstream service,下游工具只需要知道 traefik 的入口地址,不需要关心实际调用的是哪个通道。
这一篇的目标很明确:交付一份可复制的config.toml骨架,配合 traefik 的 IngressRoute 配置,让你在集群里完成统一接入,并且用一条 curl 命令验证连通性。不涉及复杂的 TLS 证书管理,先把通道跑通。
适合谁看?如果你已经在 k8s 里跑 traefik,并且有多个 AI 编码工具需要接入,这篇能帮你把配置收敛到一处。如果你还没装 traefik,建议先看基础安装部分,或者用官方 Helm Chart 快速起一个。
2. TaoToken 前置准备与 traefik 环境确认
在动手改配置之前,先把两件事确认清楚:TaoToken 的 Key 拿到手,traefik 的版本和 CRD 状态正常。
2.1 获取 TaoToken API Key
打开 TaoToken 官网https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,注册后在控制台里创建 API Key。控制台地址是https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite,进去之后找到 API Keys 页面,点创建,复制出来的 Key 格式类似sk-xxxxxxxx。
这个 Key 就是后面所有工具共用的那一把。你不需要为每个工具单独申请,统一用这一个就行。模型对话的入口在https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite,可以先在那里确认你要用的模型 ID,比如gpt-4o、claude-3-5-sonnet这类。
API 的基础地址是https://taotoken.net/api,注意这个地址不带 UTM 参数,直接用于代码里的 Base URL。文档地址在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite,遇到接口格式问题可以去查。
2.2 确认 traefik 版本与 CRD
在集群里执行:
kubectl get pods -n kube-system | grep traefik kubectl get crd | grep traefik.containo.us预期看到 traefik 的 Pod 处于 Running 状态,并且 CRD 列表里有ingressroutes.traefik.containo.us、middlewares.traefik.containo.us这些资源。如果 CRD 缺失,需要先应用官方提供的 CRD 清单。traefik v2.5 之后的版本 CRD 组名是traefik.containo.us,v3 改成了traefik.io,这篇以 v2.5.7 为例,如果你用的是 v3,把 YAML 里的 group 替换一下即可。
确认 traefik 的 entryPoints 配置。默认情况下 traefik 会监听web(80)和websecure(443)。如果你用的是 ConfigMap 方式配置,检查traefik.yaml里有没有定义额外的 entryPoint。后面我们要用一个内部端口来做 AI 通道的转发,所以需要确认 entryPoints 列表。
kubectl get configmap traefik -n kube-system -o yaml | grep -A 20 entryPoints如果输出里能看到web和websecure,说明基础入口正常。接下来我们要加一个专门用于 AI API 转发的 IngressRoute。
2.3 准备 Namespace 和 Secret
为了隔离,建议单独建一个 Namespace 放 AI 相关的配置:
kubectl create namespace ai-gateway然后把 TaoToken 的 Key 存成 Secret:
kubectl create secret generic taotoken-key \ --from-literal=api-key='sk-你的实际Key' \ -n ai-gateway注意这里用单引号包住 Key,避免 shell 特殊字符被解析。创建完确认一下:
kubectl get secret taotoken-key -n ai-gateway -o jsonpath='{.data.api-key}' | base64 -d能正确输出 Key 就说明 Secret 没问题。这一步看起来简单,但后面 traefik 的 Middleware 要从这个 Secret 里读 Key 并注入到请求头,所以 Secret 的命名和 Namespace 必须和后面配置里的一致。
3. 可复制的 config.toml 骨架与 traefik IngressRoute 配置
这一节是核心,交付两份配置:一份是给下游 AI 工具用的config.toml骨架,一份是 traefik 侧的 IngressRoute 和 Middleware。两份配合起来,才能实现统一接入。
3.1 config.toml 骨架
这份配置适用于支持 TOML 格式的工具,比如某些 CLI 工具和 Agent 框架。核心思路是把 Base URL 指向 traefik 的入口,Key 填一个占位符(实际由 traefik 层注入),Model ID 按需指定。
# config.toml - AI 工具统一接入骨架 # 放置路径:~/.config/ai-tool/config.toml 或项目根目录 [api] # 指向 traefik 的统一入口,不是直接指向 TaoToken base_url = "http://traefik.ai-gateway.svc.cluster.local:8000/v1" # 如果从集群外访问,换成 traefik 的 NodePort 或 LoadBalancer 地址 # base_url = "http://<traefik-external-ip>:8000/v1" # Key 这里填占位符,实际由 traefik Middleware 注入 # 如果工具不支持 Header 注入,才在这里填真实 Key api_key = "sk-injected-by-traefik" # 请求超时,单位秒 timeout = 120 [model] # 默认模型 ID,按 TaoToken 文档里的可用模型填写 default = "gpt-4o" # 备用模型,主模型不可用时切换 fallback = "claude-3-5-sonnet" [retry] # 重试次数 max_attempts = 3 # 重试间隔,单位秒 backoff = 2 [logging] # 日志级别:debug / info / warn / error level = "info" # 日志文件路径,留空输出到控制台 file = ""这份骨架的关键点是base_url指向 traefik 的内部 Service 地址,而不是直接指向https://taotoken.net/api。这样所有请求先到 traefik,由 traefik 决定转发到哪个上游。api_key填占位符是因为 traefik 的 Middleware 会从 Secret 里读真实 Key 并覆盖请求头,工具侧不需要知道真实 Key。
如果你用的工具不支持 TOML,比如 Cline 用的是 JSON 配置,对应改成:
{ "apiProvider": "openai", "openAiBaseUrl": "http://traefik.ai-gateway.svc.cluster.local:8000/v1", "openAiApiKey": "sk-injected-by-traefik", "openAiModelId": "gpt-4o" }Codex 的auth.json格式不同,但核心三件套是一样的:Base URL、Key、Model ID。Base URL 填 traefik 入口,Key 填占位符,Model ID 填你要用的模型。
3.2 traefik Middleware 注入 Key
Middleware 的作用是在请求转发到上游之前,把真实 Key 注入到Authorization头里。这样下游工具不需要持有真实 Key,Key 只在 traefik 层出现一次。
apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: taotoken-auth namespace: ai-gateway spec: headers: customRequestHeaders: Authorization: "Bearer sk-你的实际Key"把sk-你的实际Key替换成真实 Key。更安全的做法是从 Secret 读取,但 traefik 的 Middleware 原生不支持直接引用 Secret,需要用forwardAuth或者外部插件。为了简化,这里先用硬编码方式,生产环境建议用forwardAuth指向一个轻量认证服务。
如果你不想在 YAML 里明文写 Key,可以用kubectl create secret创建后,用envsubst渲染模板:
export TAOTOKEN_KEY=$(kubectl get secret taotoken-key -n ai-gateway -o jsonpath='{.data.api-key}' | base64 -d) envsubst < middleware-template.yaml | kubectl apply -f -模板里写Authorization: "Bearer ${TAOTOKEN_KEY}",这样 Key 不会出现在 shell 历史里。
3.3 IngressRoute 定义转发规则
IngressRoute 把外部请求路由到 TaoToken 的上游。因为 TaoToken 是外部服务,traefik 需要一个 ExternalName Service 或者直接配一个指向外部域名的 Service。
先创建一个 ExternalName Service:
apiVersion: v1 kind: Service metadata: name: taotoken-upstream namespace: ai-gateway spec: type: ExternalName externalName: taotoken.net然后创建 IngressRoute:
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: ai-gateway-route namespace: ai-gateway spec: entryPoints: - web routes: - match: PathPrefix(`/v1`) kind: Rule middlewares: - name: taotoken-auth namespace: ai-gateway services: - name: taotoken-upstream port: 443 scheme: https passHostHeader: true这里有几个关键参数。entryPoints指定用web(80 端口)接收请求。match用PathPrefix('/v1')匹配所有/v1开头的请求,这样 OpenAI 风格的接口都能命中。middlewares引用刚才创建的taotoken-auth,在转发前注入 Key。services指向taotoken-upstream,端口 443,scheme 用 https,因为 TaoToken 的 API 是 HTTPS 的。
passHostHeader: true很重要,它保证请求的 Host 头透传到上游,否则 TaoToken 可能因为 Host 不匹配而拒绝请求。
应用配置:
kubectl apply -f taotoken-service.yaml kubectl apply -f taotoken-middleware.yaml kubectl apply -f ai-gateway-route.yaml检查资源状态:
kubectl get ingressroute -n ai-gateway kubectl get middleware -n ai-gateway kubectl describe ingressroute ai-gateway-route -n ai-gateway如果 IngressRoute 的 status 里没有报错,说明 traefik 已经识别了路由规则。
4. 验证请求与成功结果
配置写完不算完,得实际发一个请求确认通道通了。这一步用 curl 从集群内部发起,模拟下游工具的调用。
4.1 从集群内验证
先起一个临时 Pod:
kubectl run curl-test --image=curlimages/curl -n ai-gateway --rm -it -- sh进去之后执行:
curl -v http://traefik.ai-gateway.svc.cluster.local:8000/v1/models \ -H "Content-Type: application/json"注意这里没有手动加Authorization头,因为 traefik 的 Middleware 会自动注入。如果配置正确,你会看到类似这样的响应:
{ "object": "list", "data": [ { "id": "gpt-4o", "object": "model", "created": 1710000000, "owned_by": "openai" }, { "id": "claude-3-5-sonnet", "object": "model", "created": 1710000000, "owned_by": "anthropic" } ] }看到模型列表就说明通道打通了。如果返回 401,说明 Middleware 的 Key 注入没生效,检查 Middleware 是否被正确引用,以及 Key 是否有效。
4.2 发一个实际的对话请求
模型列表通了之后,再发一个 chat completion 请求确认端到端可用:
curl -s http://traefik.ai-gateway.svc.cluster.local:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o", "messages": [ {"role": "user", "content": "用一句话说明什么是 Kubernetes Ingress"} ], "max_tokens": 100 }'预期返回:
{ "id": "chatcmpl-xxxx", "object": "chat.completion", "created": 1710000000, "model": "gpt-4o", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Kubernetes Ingress 是一种 API 对象,用于管理集群外部访问集群内服务的 HTTP 和 HTTPS 路由。" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 15, "completion_tokens": 30, "total_tokens": 45 } }看到choices里有内容返回,说明整条链路——从 traefik 入口、Middleware 注入 Key、转发到 TaoToken、再返回结果——全部正常。
4.3 从集群外验证
如果要从集群外访问,需要把 traefik 的 Service 暴露出来。用 NodePort 方式:
kubectl patch svc traefik -n kube-system -p '{"spec":{"type":"NodePort"}}' kubectl get svc traefik -n kube-system拿到 NodePort 后,用节点 IP 加端口访问:
curl -s http://<node-ip>:<node-port>/v1/models如果集群有 LoadBalancer,直接拿外部 IP 即可。集群外访问时,config.toml里的base_url要换成对应的外部地址。
验证通过后,把config.toml里的base_url改成 traefik 的入口地址,下游工具就能直接用了。Cline 的 JSON 配置、Codex 的auth.json同理,Base URL 指向 traefik,Key 填占位符,Model ID 按需指定。
5. 本篇常见错误排查
配置过程中最容易踩的坑集中在几个报错上,这里逐个对照。
5.1 401 Unauthorized
这是最常见的。返回体通常是:
{ "error": { "message": "Invalid API key", "type": "invalid_request_error" } }原因有三个可能。第一,Middleware 里的 Key 写错了,检查Authorization头的值是不是Bearer sk-开头。第二,Middleware 没有被 IngressRoute 正确引用,执行kubectl describe ingressroute ai-gateway-route -n ai-gateway看 middlewares 列表里有没有taotoken-auth。第三,Key 本身失效了,去 TaoToken 控制台确认 Key 状态。
排查命令:
kubectl get middleware taotoken-auth -n ai-gateway -o yaml看customRequestHeaders里的Authorization值是否正确。
5.2 local proxy failed 或 connection refused
报错类似:
curl: (7) Failed to connect to traefik.ai-gateway.svc.cluster.local port 8000: Connection refused这说明 traefik 的 Service 没有监听 8000 端口,或者 Service 名字不对。检查:
kubectl get svc -n kube-system | grep traefik kubectl get svc -n ai-gateway确认 traefik 的 Service 端口映射。默认 traefik 的webentryPoint 是 80,不是 8000。如果你在config.toml里写了 8000,要么改 traefik 的 entryPoint 配置,要么把base_url改成 80 端口。
5.3 reading choices 报错
返回体里出现:
{ "error": "reading choices: unexpected end of JSON input" }这通常是上游返回了非 JSON 格式的内容,比如 HTML 错误页。原因可能是passHostHeader没开,TaoToken 收到了错误的 Host 头,返回了 404 页面。检查 IngressRoute 里passHostHeader: true是否配置。
另一个可能是scheme写成了http,但 TaoToken 的 API 是 HTTPS 的。确认services里的scheme: https和port: 443。
5.4 OAuth 相关报错
如果工具报:
OAuth token exchange failed这说明工具在尝试走 OAuth 流程,而不是用 API Key。Cline 和 Claude Code 某些版本默认走 OAuth,需要在设置里切换到 API Key 模式。Claude Code 的配置在~/.claude/settings.json,把apiKeyHelper指向你的 Key,或者设置环境变量ANTHROPIC_API_KEY。
Codex 的auth.json路径通常在~/.codex/auth.json,内容格式:
{ "openai": { "apiKey": "sk-injected-by-traefik", "baseUrl": "http://traefik.ai-gateway.svc.cluster.local:8000/v1" } }注意 Base URL、Key、Model ID 三件套要齐全,缺一个都会报错。
5.5 CRD 版本不匹配
如果kubectl apply时报:
error: unable to recognize "taotoken-middleware.yaml": no matches for kind "Middleware" in version "traefik.containo.us/v1alpha1"说明集群里的 traefik CRD 版本和 YAML 里的 apiVersion 不一致。traefik v3 用的是traefik.io/v1alpha1,把 YAML 里的 group 改掉即可。确认版本:
kubectl get crd middlewares.traefik.containo.us -o jsonpath='{.spec.group}'如果返回空,说明 CRD 不存在,需要先安装对应版本的 CRD。
6. 统一接入后的工具链配置与后续扩展
通道跑通之后,接下来是把各个工具接进来。核心原则就一条:所有工具的 Base URL 都指向 traefik 入口,Key 填占位符,Model ID 按需指定。
Cline 的配置在 VS Code 设置里,搜索cline.apiProvider,选openai,然后填 Base URL 和 Key。Base URL 填http://traefik.ai-gateway.svc.cluster.local:8000/v1,Key 填sk-injected-by-traefik。Model ID 填gpt-4o或你要用的模型。
Claude Code 的配置在~/.claude/settings.json,加上:
{ "env": { "ANTHROPIC_BASE_URL": "http://traefik.ai-gateway.svc.cluster.local:8000", "ANTHROPIC_API_KEY": "sk-injected-by-traefik" } }Codex 的auth.json前面已经给过格式。如果你用 CC Switch 管理多个工具,在 CC Switch 里新增一个配置,Base URL 填 traefik 入口,Key 填占位符,Model ID 填你要用的模型。CC Switch 的好处是可以在多个配置之间快速切换,适合同时用多个模型的场景。
Coding Plan 的入口在https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite,如果你需要长期编码场景的额度管理,可以在那里看套餐详情。API Keys 管理在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite,Key 的轮换和吊销都在那里操作。
后续扩展方向有几个。第一,加限流 Middleware,防止某个工具把额度跑满。traefik 的rateLimitMiddleware 可以按 IP 或 Header 限流。第二,加日志 Middleware,把所有 AI 请求的耗时和状态码记录下来,方便排查。第三,如果集群里有多个上游通道,可以用WeightedRoundRobin做负载均衡,把请求分散到不同通道。
限流配置示例:
apiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: ai-ratelimit namespace: ai-gateway spec: rateLimit: average: 100 burst: 50 period: 1m把这个 Middleware 加到 IngressRoute 的 middlewares 列表里,就能限制每分钟最多 100 个请求。注意average和burst要根据实际额度调整,设太小会影响正常使用。
日志 Middleware 可以用accessLog配置,在 traefik 的 ConfigMap 里开启,把format设成json,然后对接你现有的日志系统。
最后提醒一点:Middleware 里的 Key 是明文存储的,生产环境建议用forwardAuth指向一个认证服务,由认证服务从 Secret 读取 Key 并注入。这样 Key 不会出现在任何 YAML 文件里。如果暂时不想搞认证服务,至少把 YAML 文件放在私有仓库里,不要提交到公开的 Git 仓库。
整套配置跑下来,改 Key 只需要改 Middleware 一处,所有工具自动生效。这就是把接入收敛到 traefik 入口层的价值。