☰
metallb+traefik+Ingress打通k8s全流程流量转发:TaoToken统一Key接入与配置骨架
2026/10/2 20:37:27 网站建设 项目流程

1. 裸机 K8s 流量入口为什么总卡在 Pending

如果你在自建机房或者几台云主机上跑 Kubernetes,大概率遇到过这个场景:写了一个type: LoadBalancer的 Service,kubectl get svc一看,EXTERNAL-IP 那一列永远是<pending>。原因不复杂,Kubernetes 本身不实现负载均衡,它只是把这个请求交给云厂商的控制器去处理。裸机环境没有这层控制器,Service 就悬在那里,只能退而求其次用 NodePort 或者 ExternalIPs,随之而来的就是端口冲突、节点 IP 变动、迁移时配置散落一地。

MetalLB 就是补上这块拼图的组件。它做三件事:从你预先划定的地址池里给 LoadBalancer Service 分配一个 VIP;通过标准网络协议(ARP 或 BGP)把这个 VIP 通告到集群外部;节点故障时把 VIP 漂移到健康节点,保证服务可用。说白了,它让裸机集群也有了"云厂商 LB"的体验。

但光有 MetalLB 还不够。它解决的是四层入口,真正对外暴露 HTTP/HTTPS 服务时,你还需要七层路由能力:按域名分流、按路径转发、统一管理证书、限流重定向。这就是 Traefik 作为 Ingress Controller 的舞台。Traefik 会自动发现 K8s 里的 Service 和 Ingress 资源,实时生成路由,不需要你手动 reload 配置。Ingress 则是 K8s 原生的七层入口资源,把外部基于域名和 URL 路径的请求精准转发到后端 Service。

这条链路串起来就是:外部请求 → MetalLB 分配的 VIP → Traefik 的 LoadBalancer Service → Ingress 规则匹配 → 后端 Service → Pod。本文会把这四段全部打通,同时给出一个运维场景下很实际的需求:当集群里跑着多个 AI 工具、需要统一管理 API Key 和通道时,怎么用一份可复制的配置骨架把 Key 收敛到一处。环境基于 Ubuntu 22.04 三主两从,组件版本 MetalLB v0.15.3、Traefik v3.6.7。

2. MetalLB 部署与地址池配置踩坑实录

2.1 一键部署与镜像导入

网络通畅的情况下,直接 apply 官方 manifest 即可:

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml

执行后会创建metallb-system命名空间,以及 controller Deployment、speaker DaemonSet、若干 CRD 和 RBAC 资源。如果集群节点拉取quay.io镜像慢,可以先把镜像包传到各节点导入:

ctr -n k8s.io images import metallb-v0.15.3-all.tar

导入完成后再执行一次 apply,然后验证:

kubectl get deploy,rs,ds,pods -n metallb-system -o wide

正常状态下 controller 是 1/1 Running,speaker 在每个节点上各一个,全部 Running。speaker 以 DaemonSet 形式运行是关键,它负责在节点上响应 ARP 请求或建立 BGP 会话,VIP 能不能被外部访问全靠它。

2.2 地址池:ARP 模式与 BGP 模式怎么选

MetalLB 的配置核心是IPAddressPool和通告方式。私有环境、CVM 这类同网段场景用 L2(ARP)模式最简单:

apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: metallbpod namespace: metallb-system spec: addresses: - 10.0.250.100/32 - 10.0.250.101/32 autoAssign: true --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: metallb2 namespace: metallb-system spec: ipAddressPools: - metallbpod

这里有个坑我踩过:L2 模式下 VIP 实际绑定在某个 speaker 节点上,如果这个 IP 段和你的物理网络不在同一广播域,ARP 通告出不去,外部就访问不到。所以地址池里的 IP 必须是节点所在网段内、未被占用的地址。另外部分云环境会做 ARP 防欺诈,需要提前向运营商或云平台申请这些内网 IP 的使用权。

如果是 VPC 或混合云环境,网关支持 BGP,那就用 BGP 模式,扩展性和故障切换都更好:

apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: metallbpod namespace: metallb-system spec: addresses: - 10.0.250.10-10.0.250.20 --- apiVersion: metallb.io/v1beta2 kind: BGPPeer metadata: name: bgp-peer-gateway namespace: metallb-system spec: myASN: 64512 peerASN: 64513 peerAddress: 10.0.250.1 --- apiVersion: metallb.io/v1beta1 kind: BGPAdvertisement metadata: name: bgp-advertise namespace: metallb-system spec: ipAddressPools: - metallbpod

myASN用私有 AS 号范围 64512-65535,peerASN和peerAddress必须和云网关配置一致,否则 BGP 会话建不起来。apply 之后检查地址池:

kubectl get ipaddresspools.metallb.io -A

2.3 用 LoadBalancer Service 验证

部署一个测试应用,Service 类型设为 LoadBalancer:

apiVersion: v1 kind: Service metadata: name: game-static-svc spec: selector: app: game-static type: LoadBalancer ports: - port: 8090 targetPort: 8090

apply 后kubectl get svc,EXTERNAL-IP 应该从<pending>变成地址池里的某个 IP。如果一直是 pending,先看kubectl describe svc的事件,再看 controller 日志kubectl logs -n metallb-system deploy/controller,通常是地址池没匹配上或者 speaker 没就绪。

3. Traefik 作为 Ingress Controller 的 Helm 配置骨架

3.1 Helm 安装与 values 关键项

Traefik 用 Helm 装最省事:

helm repo add traefik https://traefik.github.io/charts helm repo update helm pull traefik/traefik --version 39.0.0 tar xf traefik-39.0.0.tgz

解压后编辑traefik/values.yaml。有两个关键点:一是 Service 类型,装了 MetalLB 就用 LoadBalancer,没装就改 NodePort;二是 Dashboard,调试阶段建议打开。

service: type: LoadBalancer ingressRoute: dashboard: enabled: true

安装:

helm install traefik-server traefik -n traefik --create-namespace

验证:

kubectl get all -n traefik kubectl get ingressclasses

应该能看到ingressclass.networking.k8s.io/traefik-server,CONTROLLER 是traefik.io/ingress-controller。这个 IngressClass 名字后面写 Ingress 规则时要用到。

3.2 统一 Key 与 API 通道的配置骨架

运维场景里经常要在集群内跑多个 AI 工具,每个工具各自维护一份 Key 和 Base URL,改起来很痛苦。把通道收敛到一处,用环境变量或配置文件注入是更稳的做法。下面给出两个可复制的配置骨架,路径和字段名保持通用。

settings.json(适用于多数支持 JSON 配置的客户端):

{ "api_base": "https://taotoken.net/api", "api_key": "sk-你的统一Key", "model": "claude-sonnet-4-5", "timeout": 60, "retry": 3 }

config.toml(适用于 TOML 风格的客户端):

[provider] base_url = "https://taotoken.net/api" api_key = "sk-你的统一Key" model = "claude-sonnet-4-5" [network] timeout = 60 retry = 3

三件套要写全:Base URL 指向https://taotoken.net/api,Key 用统一签发的,Model ID 按实际调用的模型填。这样集群里所有工具读同一份配置,换 Key 或换模型只改一处。Key 的申请入口在控制台的 API Keys 页面,接入细节可以对照官方接入文档。

3.3 Ingress 规则与后端 Service

准备两个后端 Service,分别对应 v1 和 v2:

apiVersion: v1 kind: Service metadata: name: game-static-svc-v1 spec: selector: app: game-static-v1 type: NodePort ports: - port: 8091 targetPort: 8090 nodePort: 30891 --- apiVersion: v1 kind: Service metadata: name: game-static-svc-v2 spec: selector: app: game-static-v2 type: NodePort ports: - port: 8092 targetPort: 8090 nodePort: 30892

Ingress 规则按域名分流:

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-game namespace: default spec: ingressClassName: traefik-server rules: - host: v1.example.com http: paths: - pathType: Prefix path: / backend: service: name: game-static-svc-v1 port: number: 8091 - host: v2.example.com http: paths: - pathType: Prefix path: / backend: service: name: game-static-svc-v2 port: number: 8092

ingressClassName必须和前面查到的 IngressClass 名字一致,写错了 Traefik 不会接管这条规则。

4. 验证请求:从外部 IP 经 Traefik 到后端

4.1 确认转发链路

先拿到 Traefik 的 EXTERNAL-IP:

kubectl get svc -n traefik traefik-server

假设分配到的 VIP 是10.0.250.100,80 端口映射到容器 80。在客户端配置 hosts:

10.0.250.100 v1.example.com v2.example.com

然后直接 curl:

curl http://v2.example.com

如果返回后端应用的 HTML,说明整条链路通了:请求先到 MetalLB 分配的 VIP,speaker 节点响应 ARP,流量进入 Traefik 的 LoadBalancer Service,Traefik 根据 Host 头匹配 Ingress 规则,转发到game-static-svc-v2,最后落到 Pod。

4.2 用 Dashboard 排查路由

调试阶段打开 Traefik Dashboard 最直观。临时端口转发:

kubectl -n traefik port-forward pod/traefik-server-xxx 8080:8080 --address=0.0.0.0

浏览器访问http://节点IP:8080/dashboard/,在 HTTP Routers 里能看到每条 Ingress 生成的路由、匹配规则和后端服务。如果某条规则没出现,多半是 IngressClass 不匹配或者 Ingress 资源没被正确解析。

4.3 验证统一 Key 通道

配置好settings.json或config.toml后,用一次最小请求验证通道是否可用。以 curl 为例:

curl -X POST https://taotoken.net/api/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: sk-你的统一Key" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-5", "max_tokens": 64, "messages": [{"role": "user", "content": "ping"}] }'

返回正常响应就说明 Key 和通道都通了。这一步和 K8s 流量转发是两条独立的链路,前者验证的是 AI 工具的统一接入,后者验证的是集群入口,两者在运维上经常需要同时维护,所以放在一起讲。

5. 常见报错排查对照

5.1 Service EXTERNAL-IP 一直 Pending

现象是kubectl get svc里 EXTERNAL-IP 显示<pending>。先确认地址池是否存在且未耗尽:

kubectl get ipaddresspools.metallb.io -A kubectl describe svc 你的服务名

如果事件里提示没有可用地址,说明地址池里的 IP 都被占用了,扩容地址池即可。如果地址池正常但依然 pending,检查 speaker 是否全部 Running,kubectl logs -n metallb-system ds/speaker看有没有 ARP 或 BGP 相关报错。

5.2 401 与 local proxy failed

调用统一通道时如果返回 401,先核对 Key 是否完整、有没有多余空格,以及请求头字段名是否正确。有些客户端用Authorization: Bearer,有些用x-api-key,要和通道要求一致。如果报local proxy failed,通常是客户端配置了本地代理但代理没起来,或者 Base URL 写成了本地地址。检查settings.json里的api_base是否指向https://taotoken.net/api,不要带多余路径。

5.3 reading choices 与 OAuth 报错

reading choices这类报错一般出现在响应解析阶段,说明请求发出去了但返回结构不符合客户端预期。常见原因是 Model ID 写错,或者通道返回的是错误 JSON 被客户端当成正常响应解析。先用 curl 直接打一次,看原始返回是什么。OAuth 相关报错则多出现在需要交互式登录的客户端,这类场景建议改用 API Key 方式接入,避免在集群环境里做浏览器授权。

5.4 命名空间 Terminating 卡死

删除traefik命名空间时如果一直卡在 Terminating,kubectl delete ns traefik --force也无效,可以用 finalize 接口强制清理。先起一个本地代理:

kubectl proxy --port=8001 &

另开窗口构造 JSON:

{ "apiVersion": "v1", "kind": "Namespace", "metadata": { "name": "traefik", "uid": "你的命名空间UID" }, "spec": { "finalizers": [] }, "status": { "phase": "Terminating" } }

UID 从kubectl get ns traefik -o jsonpath='{.metadata.uid}'拿。然后 PUT:

curl -X PUT http://127.0.0.1:8001/api/v1/namespaces/traefik/finalize \ -H "Content-Type: application/json" \ -d @traefik-force-delete.json

执行完再查kubectl get ns | grep traefik,应该就消失了。这个操作要谨慎,确认命名空间里确实没有还需要保留的资源。

6. 把入口链路和 Key 通道一起收进运维手册

整条链路跑通之后,日常运维其实就两件事:入口侧盯住 MetalLB 的地址池余量和 Traefik 的路由状态,接入侧盯住统一 Key 的配额和通道健康。入口侧建议给地址池留出冗余,别等到 Service 创建时才发现在排队;Traefik 的 Dashboard 在调试期开着,稳定后可以关掉减少暴露面。接入侧把settings.json和config.toml纳入配置管理,Key 轮换时只改一处,集群里所有工具同步生效。

需要长期跑编码类 Agent 或者多模型切换的场景,可以了解下 Coding Plan,按用量规划比逐个申请更省心。验证模型响应是否正常,直接在模型对话页面发一条消息就能看到原始返回,比在集群里翻日志快得多。Key 的签发和轮换在控制台的 API Keys 页面操作,接入参数对照接入文档,遇到字段名不确定的时候以文档为准。

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

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

立即咨询