☰
k8s 安装 traefik 做集群内服务暴露:从 IngressRoute 到统一 Key 的落地实践
2026/10/18 10:14:30 网站建设 项目流程

1. 从 Service 到 IngressRoute:集群内服务暴露到底难在哪

在 k8s 里把服务跑起来只是第一步,真正让人头疼的是「怎么让集群外的流量稳稳地打进来」。你可能已经用过 NodePort,端口一多就乱;也试过原生 Ingress,但想加个限流、改个请求头、做灰度分流,就得靠一堆 annotation 硬凑,改完还得反复确认有没有生效。traefik 的 IngressRoute 和 Middleware 就是来解决这个问题的:它把路由规则和中间件拆成独立的 CRD(自定义资源),路由归路由、策略归策略,改限流不用动路由,加鉴权不用重启 Pod。

这篇内容聚焦 k8s 集群内服务暴露这个场景,用 traefik 的 IngressRoute 打通入口流量,再通过 Middleware 把外部 API 调用统一收敛到 TaoToken 的 Key/API 通道。适合已经能跑起一个 Deployment + Service、但对 Ingress 层还停留在「能通就行」阶段的同学。我会给出可复制的 Helm values、IngressRoute 清单和 curl 验证步骤,你照着改改就能落地。

先说清楚 traefik 的工作模型。它本质上是一个反向代理,监听集群节点的入口端口,收到请求后根据规则匹配到对应的 Service,再把流量转发过去。和 Nginx Ingress 最大的区别在于,traefik 原生支持 CRD,路由规则不是塞在 annotation 里,而是写成 IngressRoute 对象。一个 IngressRoute 里可以挂多个 Middleware,比如限流、重试、请求头改写、BasicAuth,这些 Middleware 也是独立对象,可以跨路由复用。

我试过在一个测试集群里用 NodePort 暴露了七八个服务,端口从 30080 排到 30087,每次加服务都要记端口,前端同学天天来问「这个接口走哪个端口」。后来换成 traefik 统一入口,所有服务走同一个 80/443,靠 Host 和 Path 区分,配置文件反而更清晰了。下面从安装开始,一步步来。

2. 用 Helm 安装 traefik 并准备 TaoToken 统一 Key 通道

安装 traefik 最省事的方式是 Helm。先确认你的集群能访问镜像仓库,然后加 repo:

helm repo add traefik https://traefik.github.io/charts helm repo update

接下来准备 values 文件。这里我关掉了默认的 dashboard 暴露,改用自己的 IngressRoute 控制,同时把 entryPoint 的 web 端口设成 8000,websecure 设成 8443,避免和节点上已有的 80/443 冲突。如果你节点上没占用,改回 80/443 也行。

# traefik-values.yaml deployment: replicas: 2 ingressRoute: dashboard: enabled: false ports: web: port: 8000 expose: default: true exposedPort: 30080 protocol: TCP websecure: port: 8443 expose: default: true exposedPort: 30443 protocol: TCP service: type: NodePort logs: general: level: INFO access: enabled: true

执行安装:

kubectl create namespace traefik helm install traefik traefik/traefik -n traefik -f traefik-values.yaml

装完后确认 Pod 和 Service:

kubectl get pods -n traefik kubectl get svc -n traefik

你应该能看到两个 traefik Pod 处于 Running,Service 类型是 NodePort,映射出 30080 和 30443。

现在说 TaoToken 这一层。集群里很多服务需要调用外部大模型 API,如果每个服务各自维护一套 Key,轮换和审计都很麻烦。我的做法是在 traefik 这一层做统一出口:所有需要调外部 API 的请求,先经过一个 Middleware 注入统一的认证头,再转发到 TaoToken 的 API 通道。TaoToken 的 API 地址是https://taotoken.net/api,你可以在控制台创建 Key,然后把它作为集群内的统一凭证。

具体操作是:登录 TaoToken 控制台,在 API Keys 页面创建一个新 Key,复制出来。这个 Key 不要硬编码在业务代码里,而是存成 k8s Secret:

kubectl create secret generic taotoken-key \ --from-literal=api-key='sk-你的实际Key' \ -n traefik

这样 traefik 的 Middleware 就能引用这个 Secret,业务 Pod 完全不需要知道 Key 长什么样。后面第 3 节会给出完整的 Middleware 和 IngressRoute 配置。

3. 可复制的 IngressRoute 与 Middleware 配置

这一节是核心,直接给可复制的清单。假设你有一个业务服务叫myapp,跑在default命名空间,Service 端口 9088。我们要做两件事:一是把myapp.example.com/test的流量转发到 myapp;二是把/api/llm的流量经过统一 Key 注入后转发到 TaoToken。

先写 Middleware,负责注入 Authorization 头:

apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: taotoken-auth namespace: traefik spec: headers: customRequestHeaders: Authorization: "Bearer sk-你的实际Key"

注意,生产环境更推荐用forwardAuth或者从 Secret 挂载文件读取,这里为了演示直观先写明文,你落地时换成 Secret 引用。

再写一个限流 Middleware,防止某个服务把出口打满:

apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: rate-limit namespace: traefik spec: rateLimit: average: 100 burst: 50

然后是 IngressRoute,把业务路由和 TaoToken 路由分开写:

apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: myapp-route namespace: default spec: entryPoints: - web routes: - match: Host(`myapp.example.com`) && PathPrefix(`/test`) kind: Rule services: - name: myapp port: 9088 middlewares: - name: rate-limit namespace: traefik --- apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: taotoken-route namespace: traefik spec: entryPoints: - web routes: - match: Host(`myapp.example.com`) && PathPrefix(`/api/llm`) kind: Rule services: - name: taotoken-external port: 443 middlewares: - name: taotoken-auth

这里taotoken-external是一个 ExternalName Service,指向 TaoToken 的域名:

apiVersion: v1 kind: Service metadata: name: taotoken-external namespace: traefik spec: type: ExternalName externalName: taotoken.net

应用这些清单:

kubectl apply -f middleware.yaml kubectl apply -f ingressroute.yaml kubectl apply -f external-service.yaml

应用后检查 traefik 有没有识别到:

kubectl get ingressroute -A kubectl get middleware -A

如果 traefik 的 dashboard 开着,你可以在 Routers 页面看到这两条路由的状态。没开也没关系,下一步直接用 curl 验证。

4. 用 curl 验证请求与成功结果

验证分两步:先确认业务路由通,再确认 TaoToken 通道通。

业务路由验证,假设你的节点 IP 是 192.168.1.100,NodePort 是 30080:

curl -H "Host: myapp.example.com" \ http://192.168.1.100:30080/test

预期返回你 myapp 的响应,比如{"code":0,"msg":"ok","data":"test return"}。如果返回 404,检查 IngressRoute 的 match 规则和 Service 端口是否对得上。

TaoToken 通道验证:

curl -H "Host: myapp.example.com" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"ping"}]}' \ http://192.168.1.100:30080/api/llm/v1/chat/completions

注意路径:IngressRoute 匹配的是/api/llm,转发到taotoken.net后,实际请求路径会带上/api/llm前缀。TaoToken 的 API 路径是/api,所以你需要确认转发后的路径是否正确。更稳妥的做法是在 Middleware 里加一个replacePathRegex,把/api/llm替换成/api:

apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: rewrite-taotoken namespace: traefik spec: replacePathRegex: regex: "^/api/llm/(.*)" replacement: "/api/$1"

把这个 Middleware 加到 taotoken-route 的 middlewares 列表里,再重新 curl。成功的话你会看到类似这样的返回:

{ "id": "chatcmpl-xxx", "object": "chat.completion", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "pong" } } ] }

如果返回 401,说明 Authorization 头没注入成功,检查 Middleware 是否被正确引用,以及 Key 是否有效。如果返回 502,检查 ExternalName Service 的域名解析是否正常,可以在 traefik Pod 里nslookup taotoken.net确认。

5. 常见报错排查:401、local proxy failed 与 reading choices

这一节列几个我实际踩过的坑,对照报错找原因。

401 Unauthorized:最常见。原因通常是 Middleware 没生效,或者 Key 写错了。先确认 IngressRoute 的 middlewares 字段引用了正确的 Middleware 名称和命名空间。traefik 的 Middleware 是命名空间隔离的,跨命名空间引用必须写namespace字段。然后确认 Secret 里的 Key 没有多余空格。你可以临时在 traefik Pod 里手动 curl 一次 TaoToken,排除网络问题:

kubectl exec -it -n traefik deploy/traefik -- \ curl -H "Authorization: Bearer sk-你的Key" \ https://taotoken.net/api/v1/models

如果这条通,说明 Key 没问题,问题在 Middleware 配置。

local proxy failed:这个报错通常出现在 traefik 转发到 ExternalName Service 时。原因是 traefik 的 Pod 无法解析taotoken.net,或者 DNS 配置有问题。检查 traefik 的 DNS 策略,如果是ClusterFirst,确认 CoreDNS 正常。另一个可能是 ExternalName Service 的externalName写错了,注意不要带https://前缀,只写域名。

reading choices 报错:这个一般不是 traefik 的问题,而是你调用的模型接口返回格式不对。比如你请求的是/v1/chat/completions,但实际转发到了/api根路径,返回的就不是标准的 choices 结构。检查replacePathRegex的替换规则,确保路径拼接正确。另外确认请求体里的model字段是 TaoToken 支持的模型 ID,写错了会返回错误信息而不是 choices。

OAuth 相关报错:如果你用的是 Claude Code 或者 Codex 这类工具,它们可能走 OAuth 流程。这种情况下不要用上面的 Header 注入方式,而是把 Base URL 指向你的 traefik 入口,Key 和 Model ID 在工具侧配置。三件套是:Base URL 填http://你的节点IP:30080/api/llm,Key 填 TaoToken 的 Key,Model ID 填你实际使用的模型。CC Switch 或 Cline MCP 里也是同样的三件套,缺一不可。

排查时善用 traefik 的 access log,在 values 里已经开了。看日志:

kubectl logs -n traefik deploy/traefik --tail=50

日志里会显示每条请求匹配到哪个 Router、走了哪个 Middleware、转发到哪个 Service,定位问题很快。

6. 把外部 API 调用统一收敛到 TaoToken 的落地建议

最后说几个落地时的实用建议。第一,Key 不要写死在 Middleware 里,用 Secret 挂载成文件,Middleware 通过forwardAuth读取。第二,给 TaoToken 路由单独加一个限流 Middleware,避免某个业务把出口打满影响其他服务。第三,如果你有多个集群,可以把 TaoToken 的 Key 做成统一的 Secret,通过 CI 分发,轮换时只改一处。

需要创建 Key 的话,去 TaoToken 控制台的 API Keys 页面:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,里面有各语言的调用示例。想先验证模型效果,可以直接用模型对话页面:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。如果你长期做编码类 Agent,Coding Plan 更划算:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。

整套流程跑下来,你会发现 traefik 的 IngressRoute + Middleware 组合比传统 Ingress 灵活很多,尤其是把外部 API 调用收敛到统一 Key 之后,业务侧完全不用关心认证细节。先把业务路由跑通,再加 TaoToken 通道,一步步来,遇到报错对照第 5 节排查,基本都能解决。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询