ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

metallb+traefik+Ingress打通k8s全流程流量转发:TaoToken统一Key接入与配置骨架

metallb+traefik+Ingress打通k8s全流程流量转发:TaoToken统一Key接入与配置骨架 1. 裸机 K8s 流量入口为什么总卡在 Pending如果你在自建机房或者几台云主机上跑 Kubernetes大概率遇到过这个场景写了一个type: LoadBalancer的 Servicekubectl 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 Runningspeaker 在每个节点上各一个全部 Running。speaker 以 DaemonSet 形式运行是关键它负责在节点上响应 ARP 请求或建立 BGP 会话VIP 能不能被外部访问全靠它。2.2 地址池ARP 模式与 BGP 模式怎么选MetalLB 的配置核心是IPAddressPool和通告方式。私有环境、CVM 这类同网段场景用 L2ARP模式最简单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: - metallbpodmyASN用私有 AS 号范围 64512-65535peerASN和peerAddress必须和云网关配置一致否则 BGP 会话建不起来。apply 之后检查地址池kubectl get ipaddresspools.metallb.io -A2.3 用 LoadBalancer Service 验证部署一个测试应用Service 类型设为 LoadBalancerapiVersion: v1 kind: Service metadata: name: game-static-svc spec: selector: app: game-static type: LoadBalancer ports: - port: 8090 targetPort: 8090apply 后kubectl get svcEXTERNAL-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-serverCONTROLLER 是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/apiKey 用统一签发的Model ID 按实际调用的模型填。这样集群里所有工具读同一份配置换 Key 或换模型只改一处。Key 的申请入口在控制台的 API Keys 页面接入细节可以对照官方接入文档。3.3 Ingress 规则与后端 Service准备两个后端 Service分别对应 v1 和 v2apiVersion: 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: 30892Ingress 规则按域名分流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: 8092ingressClassName必须和前面查到的 IngressClass 名字一致写错了 Traefik 不会接管这条规则。4. 验证请求从外部 IP 经 Traefik 到后端4.1 确认转发链路先拿到 Traefik 的 EXTERNAL-IPkubectl get svc -n traefik traefik-server假设分配到的 VIP 是10.0.250.10080 端口映射到容器 80。在客户端配置 hosts10.0.250.100 v1.example.com v2.example.com然后直接 curlcurl http://v2.example.com如果返回后端应用的 HTML说明整条链路通了请求先到 MetalLB 分配的 VIPspeaker 节点响应 ARP流量进入 Traefik 的 LoadBalancer ServiceTraefik 根据 Host 头匹配 Ingress 规则转发到game-static-svc-v2最后落到 Pod。4.2 用 Dashboard 排查路由调试阶段打开 Traefik Dashboard 最直观。临时端口转发kubectl -n traefik port-forward pod/traefik-server-xxx 8080:8080 --address0.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 是否全部 Runningkubectl 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命名空间时如果一直卡在 Terminatingkubectl delete ns traefik --force也无效可以用 finalize 接口强制清理。先起一个本地代理kubectl proxy --port8001 另开窗口构造 JSON{ apiVersion: v1, kind: Namespace, metadata: { name: traefik, uid: 你的命名空间UID }, spec: { finalizers: [] }, status: { phase: Terminating } }UID 从kubectl get ns traefik -o jsonpath{.metadata.uid}拿。然后 PUTcurl -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 页面操作接入参数对照接入文档遇到字段名不确定的时候以文档为准。
返回列表