1. 从 Pod 到公网:K8s Service 与 Ingress 到底解决了什么问题
刚接触 K8s 的时候,我最大的困惑不是怎么写 Deployment,而是「Pod 起来了,然后呢?」。Pod 的 IP 是动态的,重启一次就换一个,你不可能把 Pod IP 写死在调用方。这时候 Service 就登场了——它给一组 Pod 提供一个稳定的虚拟 IP 和 DNS 名字,集群内部谁想访问,认准这个 Service 就行。
但 Service 只解决了「集群内怎么找到你」。如果外部用户要访问,ClusterIP 是出不去的,NodePort 会暴露一堆高位端口,LoadBalancer 又要云厂商配合。真正做 HTTP 层的域名和路径分发,得靠 Ingress。所以完整的暴露链路是:外部请求 → Ingress Controller → Service → Pod。这条链路每一环都有坑,本文就带你从零把这条链路跑通。
这篇内容适合谁?如果你已经能跑起一个 Deployment,但对「怎么让外面访问到」还模棱两可,或者你正在给 AI 应用做网关、想把模型调用统一收口,那这篇就是写给你的。我会给出可直接复制的 Service 和 Ingress YAML,再用 curl 一步步验证,最后把 TaoToken 的统一 Key/API 通道接进来,让集群里的应用通过一个稳定入口访问模型服务。
先说清楚 TaoToken 在这里的角色。TaoToken 提供统一的 API 通道和 Key 管理,官网是 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,就能发起对话或补全请求。把它和 K8s 的 Ingress 结合,就是「集群内的应用 → Ingress → 外部模型 API」这条出站链路,和「外部用户 → Ingress → 集群内应用」这条入站链路,正好对称。
很多人卡在第一步:Service 的 selector 和 Pod 的 label 对不上,Endpoints 是空的,curl 直接超时。还有人 Ingress 写完了,kubectl get ingress有地址,但访问 404,因为 pathType 或 rewrite 没配对。这些我都会在排障章节里逐个拆。
2. 前置准备:集群、Ingress Controller 与 TaoToken Key 获取
在写 YAML 之前,先把环境确认清楚。你需要一个能用的 K8s 集群,minikube、kind、k3s 或者云上的托管集群都行。我用 kind 演示,因为它本地起得快,节点少,排障直观。
第一步,确认集群状态:
kubectl cluster-info kubectl get nodes节点是 Ready 就说明集群没问题。接着要装 Ingress Controller。K8s 本身不带 Ingress 实现,Ingress 只是一个资源声明,真正干活的是 Controller。最常用的是 ingress-nginx:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml装完等 Pod 起来:
kubectl get pods -n ingress-nginx看到ingress-nginx-controller是 Running 就对了。如果你用的是 minikube,直接minikube addons enable ingress更省事。
然后是 TaoToken 的 Key。访问 https://taotoken.net/api-keys 创建你的 API Key,注意这个 Key 只在创建时完整显示一次,复制好存到安全的地方。TaoToken 的 API 入口是 https://taotoken.net/api ,后面我们在应用里配置 Base URL 时会用到。如果你想先验证 Key 能不能用,可以去模型对话页面 https://taotoken.net/model-chat 发一条测试消息,确认通道正常再往下走。
这里有个关键点:TaoToken 的 Key 是给「应用出站调用模型」用的,不是给外部用户访问你集群用的。所以本文有两条链路——入站(用户访问你的应用)和出站(你的应用调用模型)。Ingress 主要管入站,出站则是应用内部配置 Base URL 和 Key。两条链路都跑通,才算完整。
把 Key 存成 K8s Secret,别硬编码在 YAML 里:
kubectl create secret generic taotoken-secret \ --from-literal=TAOTOKEN_API_KEY='你的Key'确认一下:
kubectl get secret taotoken-secret到这一步,集群、Controller、Key 三样齐了。接下来进入正题,先写 Service。
3. 可复制配置:Service 与 Ingress YAML 全流程
先部署一个示例应用,我用一个简单的 nginx 镜像,方便验证。创建deploy.yaml:
apiVersion: apps/v1 kind: Deployment metadata: name: demo-app labels: app: demo-app spec: replicas: 2 selector: matchLabels: app: demo-app template: metadata: labels: app: demo-app spec: containers: - name: web image: nginx:1.25 ports: - containerPort: 80注意selector.matchLabels和template.metadata.labels必须一致,都是app: demo-app。这是后面 Service 能找到 Pod 的前提。
应用它:
kubectl apply -f deploy.yaml kubectl get pods -l app=demo-app两个 Pod 都 Running 后,写 Service。这里我选 ClusterIP,因为最终由 Ingress 转发进来,不需要 NodePort 或 LoadBalancer 直接暴露。创建service.yaml:
apiVersion: v1 kind: Service metadata: name: demo-svc spec: type: ClusterIP selector: app: demo-app ports: - name: http port: 80 targetPort: 80 protocol: TCPport是 Service 对外暴露的端口,targetPort是 Pod 容器实际监听的端口。两者可以不同,但这里都是 80。应用它:
kubectl apply -f service.yaml kubectl get svc demo-svc kubectl get endpoints demo-svcget endpoints这一步非常关键。如果 Endpoints 显示<none>,说明 selector 没匹配到 Pod,后面 Ingress 一定 502。正常应该看到两个 Pod IP 和端口。
现在写 Ingress。创建ingress.yaml:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: demo-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: ingressClassName: nginx rules: - host: demo.local http: paths: - path: / pathType: Prefix backend: service: name: demo-svc port: number: 80几个要点:ingressClassName: nginx要和 Controller 的 class 对上,ingress-nginx 默认就是 nginx。pathType: Prefix表示前缀匹配。rewrite-target: /在单路径时其实可省,但多路径场景下很关键,先留着。
应用并检查:
kubectl apply -f ingress.yaml kubectl get ingress demo-ingressADDRESS列有值就说明 Controller 认领了。本地 kind 环境需要把域名指到 Controller 的入口 IP,或者直接用curl -H "Host: demo.local"指定 Host 访问。
如果你要把 TaoToken 的调用也纳入进来,可以在应用的环境变量里配置:
env: - name: OPENAI_BASE_URL value: "https://taotoken.net/api" - name: OPENAI_API_KEY valueFrom: secretKeyRef: name: taotoken-secret key: TAOTOKEN_API_KEY这样应用出站调用模型时,走的就是 TaoToken 的统一通道。Base URL 是 https://taotoken.net/api ,Key 从 Secret 注入,不落盘明文。
4. 验证请求:从集群内 curl 到外部域名访问
配置写完不算完,得一步步验证。先验证集群内 Service 可达。起一个临时 Pod:
kubectl run curl-test --image=curlimages/curl -it --rm -- sh进去之后直接访问 Service 的 DNS 名:
curl -s http://demo-svc.default.svc.cluster.local看到 nginx 的欢迎页 HTML 就说明 Service 通了。如果超时,回去查 Endpoints。
接着验证 Ingress。先拿到 Controller 的入口地址:
kubectl get svc -n ingress-nginx ingress-nginx-controller如果是 LoadBalancer 类型,EXTERNAL-IP 就是入口。kind 环境通常是 NodePort,用节点 IP 加端口。假设入口是192.168.1.100:30080,用 Host 头访问:
curl -s -H "Host: demo.local" http://192.168.1.100:30080/返回 nginx 页面就说明 Ingress 路由生效了。如果返回 404,检查 path 和 pathType;返回 502,检查 Service 和 Endpoints;返回 503,多半是 Controller 没找到后端。
再验证出站链路,也就是应用调 TaoToken。在刚才的 curl-test Pod 里直接测:
curl -s https://taotoken.net/api/v1/models \ -H "Authorization: Bearer $TAOTOKEN_API_KEY"注意这个 Pod 里没有注入 Key,你可以手动带上。返回模型列表 JSON 就说明出站通道正常。这一步验证的是「集群内的 Pod 能不能访问外部模型 API」,和 Ingress 入站是两回事,但两条链路都通,你的 AI 应用才算真正可用。
实测下来,最容易出问题的是 DNS 解析和网络策略。如果你的集群装了 NetworkPolicy,默认可能拒绝所有出站,需要显式放行。验证时可以临时kubectl exec进业务 Pod,用nslookup taotoken.net确认解析正常。
5. 常见报错排查:401、502、404 与 local proxy failed
排障这块我踩过的坑最多,逐个说。
401 Unauthorized:调用 TaoToken 时出现,基本是 Key 没带对或过期。检查Authorization: Bearer后面的 Key 是否完整,有没有多余空格。如果是通过 Secret 注入,确认secretKeyRef的 key 名和创建时一致。还有一种情况是 Base URL 写错,比如漏了/api,导致请求打到错误端点返回 401。
502 Bad Gateway:Ingress 返回 502,说明 Controller 连不上后端 Service。第一步kubectl get endpoints demo-svc,如果是<none>,就是 selector 不匹配。第二步确认targetPort和容器containerPort一致。第三步看 Pod 是否真的 Ready,Readiness 探针没过也会被踢出 Endpoints。
404 Not Found:Ingress 返回 404,通常是 path 或 host 不匹配。检查请求的 Host 是否等于rules.host,path 是否被pathType正确匹配。如果用了rewrite-target,确认重写后的路径后端能处理。多路径场景下,path: /api和path: /的顺序也有讲究,Prefix 匹配下更长的路径要单独列。
local proxy failed:这个报错常见于本地开发工具或 kubectl port-forward 场景。比如你kubectl port-forward svc/demo-svc 8080:80,然后本地代理配置冲突,就会提示 local proxy failed。排查方向是确认端口没被占用,lsof -i:8080看一下。如果是 kind 环境,还要确认 kubectl 的 context 指向正确集群。
reading choices 报错:调用模型接口时如果返回结构里choices字段读取失败,多半是响应体不是预期的 JSON,比如返回了 HTML 错误页。用curl -v看原始响应,确认 Base URL 和路径拼对。TaoToken 的对话接口路径要按文档来,别自己猜。
OAuth 相关报错:如果你用的是需要 OAuth 的客户端工具,报 token 失效,检查刷新逻辑。TaoToken 的 Key 是长期有效的 API Key,不涉及 OAuth 刷新,如果你看到 OAuth 报错,说明请求打到了别的端点,回头核对 Base URL。
排查通用套路:先看 Controller 日志kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx,再看业务 Pod 日志,最后用kubectl describe ingress看事件。三层日志一对照,问题基本定位。
6. 把链路收口:TaoToken 统一通道与长期编码方案
入站和出站两条链路都跑通后,你会发现一个现实问题:模型调用如果散落在各个应用里,Key 管理会很乱。今天这个应用用 A 厂商,明天那个用 B 厂商,Key 到处复制,轮换一次要改一堆配置。TaoToken 的价值就在这里——统一 Key、统一 Base URL,应用侧只认一个入口。
对于长期跑在集群里的编码类或 Agent 类应用,建议直接用 Coding Plan,地址是 https://taotoken.net/coding-plan 。它面向的就是持续调用场景,配合 K8s 的 Secret 注入,Key 不落盘,轮换只改 Secret,Pod 滚动重启即可生效。
如果你需要管理多个 Key 或查看用量,控制台在 https://taotoken.net/console 。接入文档在 https://taotoken.net/doc ,里面有各语言的示例。Claude Code 相关的接入可以参考 https://taotoken.net/claude-code-anthropic ,如果你在集群里跑 Claude Code 类的工具,按文档配好 Base URL 和 Key 就能用。
回到 K8s 本身,生产环境还有几个优化点值得做。Ingress 加 TLS,用 cert-manager 自动签发证书;Service 配拓扑感知路由,减少跨节点跳数;给 Ingress Controller 设资源配额,避免它被业务 Pod 挤爆。这些都是在「能访问」之后,往「访问得稳」走。
最后留一个实用技巧:把 Service、Ingress、Secret 的 YAML 放进同一个 Git 仓库,用 ArgoCD 或 Flux 做 GitOps 同步。这样每次改配置都有记录,回滚也方便。集群里的应用通过环境变量拿到 TaoToken 的 Base URL 和 Key,出站调用统一走 https://taotoken.net/api ,入站访问统一走 Ingress 域名。两条链路各司其职,你的应用暴露方案就算完整了。