1. 为什么要在 Kubernetes 里用 Traefik 做统一入口
Traefik 是一个云原生场景下的 HTTP 反向代理和负载均衡工具,它能直接监听 Kubernetes 的 Ingress、IngressRoute 等资源变化,自动生成转发规则,不需要你手动 reload 配置文件。适合谁?适合已经在 K8s 上跑微服务、又想把外部流量收口到一个入口网关的团队;也适合像我这样,手里有一堆模型 API 调用需求,想用一个统一域名和统一 Key 去管理上游请求的人。
我这次要解决的场景很具体:集群里跑着几个内部服务,同时还要调用大模型接口。如果每个服务各自去配 endpoint 和 Key,改一次就要动一堆 Deployment,非常难受。于是我把 Traefik 作为集群的 HTTP 反向代理入口,让所有出站/入站的模型请求都先经过它,再由它转发到统一的上游通道。这样上游 endpoint 只需要在 Traefik 这一层改一次,业务侧完全无感。
Traefik 的核心链路是:请求先到 EntryPoints(入口端口),再匹配 Routers(路由规则,可挂 Middlewares),然后交给 Services(后端服务定义),最后落到具体的 Server。在 K8s 里,这套东西被抽象成 CRD,最常用的就是 IngressRoute 和 Middleware。理解了这条链路,后面配 Helm 和 YAML 就不会迷路。
本文会交付可复制的 Helm values、IngressRoute YAML,以及用 curl 验证请求经过 Traefik 转发后到底命中了什么动作。全程假设你已经有一个能正常工作的 K8s 集群和 helm v3。
2. 前置准备:TaoToken 统一 Key 与 API 通道
在把 Traefik 的上游 endpoint 指过去之前,得先有一个稳定的统一通道。我用的方案是把模型调用统一收敛到 TaoToken 的 API 通道上,官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api 。它的作用是给多个模型服务提供一个统一的 Key 和统一的 Base URL,这样 Traefik 只需要认一个上游地址,不用为每个模型单独配路由。
具体操作上,先在控制台创建一个 API Key。控制台地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,进去之后在 API Keys 页面新建一个 Key,复制出来保存好。这个 Key 就是后面 Traefik 转发时携带的凭证。如果你只是想先验证模型能不能通,可以直接用模型对话页面 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 发一条测试消息,确认 Key 有效再往下走。
这里有个关键点:Traefik 本身不生产 Key,它只是把请求转发到上游。所以我们要做的是在 Traefik 的 Service 定义里,把上游地址写成 TaoToken 的 API 基址,并在转发时注入 Authorization 头。这样业务侧请求打到 Traefik,Traefik 再带着统一 Key 去访问上游,业务代码里就不用再散落 Key 了。
如果你后面要做长期编码或 Agent 类任务,可以了解下 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,它更适合持续性的调用场景。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,遇到参数细节可以对照查。API Keys 管理页 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 用来轮换和吊销 Key。
准备好 Key 之后,先别急着装 Traefik,建议用 curl 直接打一次上游,确认通道是通的:
curl -sS https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "ping"}] }'如果返回里有 choices 字段,说明 Key 和通道都没问题。这一步过了,再让 Traefik 去转发才有意义,否则排障时会分不清是 Traefik 配错还是上游不通。
3. 可复制配置:Helm values 与 IngressRoute YAML
先装 Traefik。用 Helm 装最省事,但默认 chart 的 values 不一定符合我们的需求,所以我给一份改过的 values。先加仓库:
helm repo add traefik https://traefik.github.io/charts helm repo update然后准备一个traefik-values.yaml,重点是开启 dashboard、指定 entryPoints,并且把上游指向 TaoToken。注意这里我用了一个 ExternalName 类型的 Service 来承接上游,这样 IngressRoute 的 services 就能直接引用它:
# traefik-values.yaml deployment: replicas: 2 ingressRoute: dashboard: enabled: true ports: web: port: 8000 expose: true exposedPort: 80 websecure: port: 8443 expose: true exposedPort: 443 service: type: LoadBalancer logs: general: level: INFO access: enabled: true providers: kubernetesCRD: enabled: true allowCrossNamespace: true kubernetesIngress: enabled: true安装命令:
helm install traefik traefik/traefik \ -n traefik --create-namespace \ -f traefik-values.yaml装完之后确认 Pod 起来了:
kubectl -n traefik get pods kubectl -n traefik get svc traefik接下来定义上游。因为 TaoToken 的 API 基址是外部域名,我用 ExternalName Service 把它映射进集群:
# taotoken-upstream.yaml apiVersion: v1 kind: Service metadata: name: taotoken-upstream namespace: traefik spec: type: ExternalName externalName: taotoken.net应用它:
kubectl apply -f taotoken-upstream.yaml然后是核心的 IngressRoute。它把进入web入口、匹配/api前缀的请求,转发到上面的 upstream,并挂一个 Middleware 来注入 Authorization 头:
# taotoken-ingressroute.yaml apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: taotoken-auth namespace: traefik spec: headers: customRequestHeaders: Authorization: "Bearer <你的TAOTOKEN_KEY>" --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: taotoken-route namespace: traefik spec: entryPoints: - web routes: - match: PathPrefix(`/api`) kind: Rule priority: 10 middlewares: - name: taotoken-auth services: - name: taotoken-upstream port: 443 scheme: https passHostHeader: true注意几个参数:scheme: https是因为上游是 HTTPS;passHostHeader: true让 Host 头保持为 taotoken.net,否则上游可能因为 Host 不匹配拒绝;port: 443对应 HTTPS 端口。把<你的TAOTOKEN_KEY>换成第 2 步拿到的真实 Key,然后应用:
kubectl apply -f taotoken-ingressroute.yaml到这里,Traefik 的入口、路由、中间件、上游四件套就齐了。业务侧只需要把请求打到 Traefik 的地址加/api前缀即可。
4. 验证请求:curl 经 Traefik 转发后命中的实际动作
配置写完必须验证,否则你不知道请求到底有没有经过 Traefik,还是被别的东西截了。先拿到 Traefik 的入口地址:
kubectl -n traefik get svc traefik \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}'假设拿到的是10.0.0.50,那么入口就是http://10.0.0.50。现在用 curl 打一次,路径带上/api/v1/chat/completions:
curl -sS -v http://10.0.0.50/api/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "hello from traefik"}] }'这里故意不在 curl 里带 Authorization,因为 Key 已经由 Middleware 注入了。如果返回体里有choices,说明整条链路通了:请求先到 Traefik 的web入口,匹配到PathPrefix(/api)的路由,经过taotoken-auth中间件加上了 Authorization 头,再转发到taotoken-upstream,最终命中上游的 chat completions 动作。
想确认转发细节,可以看 Traefik 的访问日志:
kubectl -n traefik logs -l app.kubernetes.io/name=traefik --tail=50日志里会有一条类似"GET /api/v1/chat/completions HTTP/1.1" 200的记录,RouterName 会显示taotoken-route。这一步很关键,它证明请求确实走了你定义的那条路由,而不是被默认规则兜走了。
再验证一下负载均衡。因为前面deployment.replicas: 2,Traefik 有两个 Pod 在跑。连续打几次请求,观察日志里是不是两个 Pod 都在处理:
for i in $(seq 1 6); do curl -sS -o /dev/null -w "%{http_code}\n" \ http://10.0.0.50/api/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"lb test"}]}' done如果每次都是 200,且日志分布在两个 Pod 上,说明 Traefik 的负载均衡在正常工作。到这一步,HTTP 反向代理、路由匹配、中间件注入、上游转发、负载均衡这几个动作就全部验证过了。
5. 常见报错排查:401、local proxy failed 与 reading choices
配 Traefik 转发最容易踩的坑集中在认证和上游连接上,我按真实报错逐个说。
401 Unauthorized:最常见。原因通常是 Middleware 里的 Authorization 头没生效,或者 Key 写错了。先确认 Middleware 是否真的挂到了路由上:
kubectl -n traefik get ingressroute taotoken-route -o yaml看middlewares字段有没有引用taotoken-auth。再确认 Middleware 里的 Key 没有多余空格。如果 Key 是从控制台复制的,注意别把换行带进去。改完 Middleware 后 Traefik 会自动热加载,不用重启。
local proxy failed / connection refused:这个报错说明 Traefik 连不上上游。检查 ExternalName Service 的externalName是不是taotoken.net,以及 IngressRoute 里scheme是不是https、port是不是443。如果写成http加443,就会连接失败。另外确认集群的 DNS 能解析外部域名:
kubectl -n traefik run dns-test --rm -it --image=busybox -- nslookup taotoken.netreading choices 相关报错:如果返回体解析时报reading 'choices'之类的错,通常不是 Traefik 的问题,而是上游返回了非预期结构,比如返回了错误 JSON。先用 curl 直连上游确认返回格式,再对比经 Traefik 转发后的返回。重点看passHostHeader是否为 true,Host 头不对时上游可能返回错误页而不是正常 JSON。
OAuth / 认证类报错:如果你用的是需要 OAuth 的模型通道,注意 Traefik 的 headers Middleware 只能注入静态头,动态 token 刷新得在业务侧或专门的认证服务里做。这种情况建议把 OAuth 逻辑放在上游网关,Traefik 只做转发。
路由不匹配:请求返回 404,说明没有路由命中。检查match规则里的PathPrefix是否和实际请求路径一致。Traefik 的匹配是大小写敏感的,/api和/API不一样。可以用 dashboard 看路由状态,dashboard 地址通过kubectl -n traefik get ingressroute找到。
排障时如果拿不准 Key 或通道状态,回到 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 重新生成一个,再对照接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 核对参数,通常能快速定位。
6. 把入口收口到统一通道:下一步怎么做
整套配下来,Traefik 承担的是集群入口和转发职责,TaoToken 承担的是统一 Key 和上游通道职责,两者边界清晰。业务侧只需要认 Traefik 的地址,Key 和上游 endpoint 的变更都收敛在 Traefik 这一层,改一次 Middleware 或 Service 就够,不用动业务代码。
如果你还想继续往下走,几个方向可以试:一是把 Middleware 拆细,按不同路径注入不同 Key,做多租户隔离;二是开启 Traefik 的 metrics,接 Prometheus 观察转发延迟和错误率;三是把 dashboard 用 IngressRoute 暴露出来,方便日常看路由状态。dashboard 的接入方式在官方文档里有,配法和上面类似。
需要长期跑编码或 Agent 任务的,可以看下 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,它更适合持续性调用。想先验证模型效果的,直接用模型对话 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 发消息最快。控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 用来管理 Key 和查看用量。API 基址统一是 https://taotoken.net/api ,配 Traefik 上游时直接用它对应的域名即可。