
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_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_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-nginxkubectl 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-literalTAOTOKEN_API_KEY你的Key确认一下kubectl get secret taotoken-secret到这一步集群、Controller、Key 三样齐了。接下来进入正题先写 Service。3. 可复制配置Service 与 Ingress YAML 全流程先部署一个示例应用我用一个简单的 nginx 镜像方便验证。创建deploy.yamlapiVersion: 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 appdemo-app两个 Pod 都 Running 后写 Service。这里我选 ClusterIP因为最终由 Ingress 转发进来不需要 NodePort 或 LoadBalancer 直接暴露。创建service.yamlapiVersion: 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.yamlapiVersion: 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 可达。起一个临时 Podkubectl run curl-test --imagecurlimages/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 GatewayIngress 返回 502说明 Controller 连不上后端 Service。第一步kubectl get endpoints demo-svc如果是none就是 selector 不匹配。第二步确认targetPort和容器containerPort一致。第三步看 Pod 是否真的 ReadyReadiness 探针没过也会被踢出 Endpoints。404 Not FoundIngress 返回 404通常是 path 或 host 不匹配。检查请求的 Host 是否等于rules.hostpath 是否被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/nameingress-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 不落盘轮换只改 SecretPod 滚动重启即可生效。如果你需要管理多个 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 域名。两条链路各司其职你的应用暴露方案就算完整了。