k8s学习之使用ingress暴露集群内部的pod服务:TaoToken统一Key接入Ingress Controller的实操大纲
1. 从 NodePort 到 Ingress为什么 Pod 服务需要七层入口刚接触 Kubernetes 的时候我习惯用 NodePort 把 Pod 服务暴露出去简单直接kubectl get svc拿到端口就能访问。但服务一多问题就来了每个 Service 都要占一个 30000-32767 的端口节点上开一堆口子运维看着头疼安全组规则也越写越长。更麻烦的是NodePort 是四层转发它只认 IP 和端口不认域名和 URL 路径你没法做到「同一个 80 端口根据 Host 头把流量分给不同的后端服务」。Ingress 就是来解决这个问题的。它本质上是集群的七层入口把「外部请求怎么转发到内部 Service」这件事从每个 Service 上抽离出来集中用一组规则描述。你可以把它理解成集群门口的智能前台访客报出要找谁域名或路径前台查表决定把他领到哪个部门Service再由 Service 把请求分发给具体的工位Pod。整个链路是这样的客户端请求先到 Ingress Controller 监听的节点端口Controller 根据 Ingress 资源里定义的 rules 匹配 Host 和 path找到对应的 ServiceService 再通过 selector 选中后端 Pod最终把请求送达。数据包走向可以记成client - NodeIP:Port - IngressController - Service - Pod。Ingress 由两个组件配合完成工作。Ingress Controller 是真正干活的组件它持续 watch Kubernetes API感知 Service、Pod、Ingress 的变化然后动态生成并热加载 Nginx或 Traefik配置。Ingress 资源本身只是一份规则声明告诉 Controller「域名 A 的 /api 路径应该转发到 Service B 的 80 端口」。没有 ControllerIngress 资源就是一堆没人执行的 YAML。这篇内容聚焦一条完整可跟做的链路部署 Ingress Controller、创建后端 Service 和 Pod、编写 Ingress 规则、通过 NodePort 接入外部流量、用 curl 验证结果同时把 TaoToken 统一 Key 接入 Ingress Controller 的配置位置讲清楚。适合已经会kubectl apply但还没系统跑通 Ingress 的同学也适合想把 AI 网关流量纳入集群入口统一管理的场景。2. TaoToken 统一 Key 接入 Ingress Controller 的前置准备在把 Ingress 跑通之前先把 TaoToken 这条链路准备好。TaoToken 提供统一的 API Key 和兼容 OpenAI 风格的接口地址你可以把它当成集群里所有 AI 调用请求的统一出口。Ingress Controller 本身不直接调用大模型但你的后端 Pod 里如果跑着需要调用模型的业务代码就可以通过环境变量或 ConfigMap 把 TaoToken 的地址和 Key 注入进去让流量走统一通道。先拿到 Key。打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后在控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 列表在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。创建时建议按用途命名比如k8s-ingress-demo方便后面在 Secret 里对应。API 基础地址是 https://taotoken.net/api 注意这个地址不带任何查询参数直接作为 Base URL 使用。模型 ID 可以在模型对话页面确认地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 选一个你常用的模型比如gpt-4o-mini或claude-3-5-sonnet记下准确的 Model ID。接下来把 Key 存进 Kubernetes Secret不要硬编码在 Deployment 里。执行kubectl create secret generic taotoken-secret \ --from-literalTAOTOKEN_API_KEYsk-你的实际Key \ -n default确认创建成功kubectl get secret taotoken-secret -o jsonpath{.data.TAOTOKEN_API_KEY} | base64 -d能打印出你的 Key 就说明 Secret 没问题。这一步的意义在于后面后端 Pod 通过envFrom或valueFrom引用这个 SecretKey 不会出现在镜像和 YAML 明文里轮换时也只需要更新 Secret。如果你打算长期在集群里跑编码类 Agent 或批量任务可以了解 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它更适合持续性的模型调用场景。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 遇到参数细节可以对照查。前置检查清单集群能正常kubectl get nodes节点可以拉取镜像本地能访问 TaoToken API 地址做连通性测试。连通性测试命令curl -s -o /dev/null -w %{http_code}\n https://taotoken.net/api返回 401 或 404 都说明网络可达401 是因为没带 Key如果超时或连接被拒先排查节点出网和 DNS。3. 可复制配置Ingress Controller 部署与 Ingress 规则 YAML这一节给出可以直接复制执行的配置。先创建独立的命名空间把 Ingress Controller 和业务服务隔离开apiVersion: v1 kind: Namespace metadata: name: ingress-nginx保存为namespace.yaml执行kubectl apply -f namespace.yaml。接着创建 RBAC 相关资源Controller 需要 watch Service、Pod、Ingress、Secret 等对象的权限。完整 RBAC 文件较长核心是 ServiceAccount、ClusterRole、ClusterRoleBinding、Role、RoleBinding 五件套命名空间统一用ingress-nginxServiceAccount 名为nginx-ingress-serviceaccount。执行kubectl apply -f rbac.yaml后可以用kubectl get clusterrole | grep nginx确认。然后是 Controller 的 Deployment。关键配置项包括镜像使用quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1启动参数里指定--default-backend-service、--configmap、--publish-service容器端口 80 和 443健康检查路径/healthz端口 10254。同时创建nginx-configuration、tcp-services、udp-services三个 ConfigMap以及default-http-backend的 Deployment 和 Service用于兜底返回 404。一次性应用kubectl apply -f namespace.yaml kubectl apply -f rbac.yaml kubectl apply -f configmap.yaml kubectl apply -f default-backend.yaml kubectl apply -f with-rbac.yaml检查 Pod 状态kubectl get all -n ingress-nginx期望看到nginx-ingress-controller和default-http-backend两个 Pod 都是 Running。接下来部署后端业务。这里用一个示例应用myappService 和 Deployment 写在一起apiVersion: v1 kind: Service metadata: name: myapp namespace: default spec: selector: app: myapp release: canary ports: - name: http targetPort: 80 port: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-backend-pod namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v2 ports: - name: http containerPort: 80保存为deploy-demo.yaml执行kubectl apply -f deploy-demo.yaml。确认三个 Pod 都 RunningService 的 Endpoints 有三个地址kubectl get pod -l appmyapp kubectl get endpoints myapp现在创建 Ingress Controller 对外的 Service用 NodePort 方式把 80 和 443 映射到节点端口 30080 和 30443apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP nodePort: 30080 - name: https port: 443 targetPort: 443 protocol: TCP nodePort: 30443 selector: app: ingress-nginx保存为service-nodeport.yaml执行kubectl apply -f service-nodeport.yaml。查看kubectl get svc -n ingress-nginx应该看到ingress-nginx的 TYPE 是 NodePort端口显示80:30080/TCP,443:30443/TCP。最后写 Ingress 规则把域名tomcat.lucky.com的请求转发到myappService 的 80 端口apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-myapp namespace: default annotations: kubernetes.io/ingress.class: nginx spec: rules: - host: tomcat.lucky.com http: paths: - path: backend: serviceName: myapp servicePort: 80保存为ingress-myapp.yaml执行kubectl apply -f ingress-myapp.yaml。注意path留空表示匹配根路径/host字段不支持 IP 地址必须是域名。如果你需要把 TaoToken 的配置注入后端 Pod可以在 Deployment 的容器里加环境变量env: - name: OPENAI_BASE_URL value: https://taotoken.net/api - name: OPENAI_API_KEY valueFrom: secretKeyRef: name: taotoken-secret key: TAOTOKEN_API_KEY - name: OPENAI_MODEL value: gpt-4o-mini这三件套 Base URL、Key、Model ID 配齐后端代码就能通过统一通道调用模型。改完 Deployment 后kubectl rollout restart deployment/myapp-backend-pod让配置生效。4. 验证请求curl 测试 Ingress 转发与成功结果配置都应用完之后先确认 Ingress 资源被 Controller 识别。执行kubectl get ingress输出里应该看到ingress-myappHOSTS 列是tomcat.lucky.comADDRESS 可能为空NodePort 模式下正常PORTS 是 80。接着在本地 hosts 文件里加一条解析把域名指向任意一个节点 IP。Linux/macOS 编辑/etc/hostsWindows 编辑C:\Windows\System32\drivers\etc\hosts加一行192.168.1.12 tomcat.lucky.com把192.168.1.12换成你集群里某个节点的真实 IP。然后直接用 curl 带 Host 头测试这样不改 hosts 也能验证curl -H Host: tomcat.lucky.com http://192.168.1.12:30080/期望返回Hello MyApp | Version: v2 | Pod Name多请求几次可以看到 Pod Name 在三个副本之间轮换说明 Service 的负载均衡生效了。如果返回default backend - 404说明请求没匹配到 Ingress 规则检查 Host 头是否和 Ingress 里的host完全一致。再验证一下 Controller 内部是否真的生成了对应的 Nginx 配置。进入 Controller Podkubectl exec -it -n ingress-nginx \ $(kubectl get pod -n ingress-nginx -l appingress-nginx -o jsonpath{.items[0].metadata.name}) \ -- /bin/bash进去后查看/etc/nginx/nginx.conf搜索server_name tomcat.lucky.com能看到对应的 server 块和proxy_pass指向 upstream说明规则已经热加载成功。如果你在后端 Pod 里集成了 TaoToken可以进 Pod 执行一次模型调用验证kubectl exec -it deploy/myapp-backend-pod -- sh curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $OPENAI_API_KEY \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:ping}]}返回 JSON 里带choices字段就说明统一 Key 通道打通了。这一步把 Ingress 入口和模型调用两条链路串起来后端服务既能被外部访问又能通过统一通道调用模型。HTTPS 场景也顺手验证一下。生成自签证书openssl genrsa -out tls.key 2048 openssl req -new -x509 -key tls.key -out tls.crt -days 365 \ -subj /CCN/STBeijing/LBeijing/ODevOps/CNtomcat.lucky.com kubectl create secret tls tomcat-ingress-secret --certtls.crt --keytls.keyIngress 里加 tls 段spec: tls: - hosts: - tomcat.lucky.com secretName: tomcat-ingress-secret rules: - host: tomcat.lucky.com http: paths: - path: backend: serviceName: myapp servicePort: 80应用后用curl -k https://tomcat.lucky.com:30443/测试-k跳过自签证书校验能看到同样的 Hello 输出就说明 TLS 终止在 Controller 上正常工作。5. 本篇常见报错排查401、404、proxy 失败与 OAuth 类问题跑 Ingress 的过程中报错基本集中在几个固定位置。下面按真实遇到的错误对照排查。401 Unauthorized这个多半不是 Ingress 的问题而是后端 Pod 调用 TaoToken 时 Key 没带对。检查 Secret 是否挂载成功kubectl exec -it deploy/myapp-backend-pod -- env | grep OPENAI如果OPENAI_API_KEY为空说明secretKeyRef的名字或 key 写错了。注意 Secret 里的 key 是TAOTOKEN_API_KEY引用时要完全一致。另外确认 Base URL 是https://taotoken.net/api不要多加/v1之外的路径也不要带 UTM 参数。local proxy failed / connection refusedController Pod 日志里出现这类信息通常是 Controller 无法访问 API Server 或后端 Service。先看日志kubectl logs -n ingress-nginx deploy/nginx-ingress-controller --tail100如果是 RBAC 权限不足日志里会有forbidden字样检查 ClusterRole 是否包含ingresses、services、endpoints的 get/list/watch。如果是后端连不上用kubectl get endpoints myapp确认 Endpoints 有地址没有地址说明 Service 的 selector 和 Pod 标签不匹配。reading choices 报错这个出现在解析模型返回时说明请求发出去了但响应结构不对。常见原因是 Model ID 写错或者 Base URL 少了/v1。用 curl 直接测curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $OPENAI_API_KEY \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:hi}]} | head -c 500如果返回里没有choices先确认 Model ID 在模型对话页面存在。地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。OAuth / token 过期类报错如果你用的是需要 OAuth 流程的工具链报错通常提示 token 无效或过期。这类问题不在 Ingress 层而在客户端凭证管理。检查 Key 是否被删除或轮换重新在 API Keys 页面生成一个更新 Secret 后重启 Podkubectl create secret generic taotoken-secret \ --from-literalTAOTOKEN_API_KEYsk-新Key \ -n default --dry-runclient -o yaml | kubectl apply -f - kubectl rollout restart deployment/myapp-backend-pod访问返回 default backend - 404请求到了 Controller 但没匹配到任何 Ingress 规则。三个检查点Host 头是否和 Ingress 的host一致kubernetes.io/ingress.class: nginx注解是否写了Ingress 的 namespace 和 Service 是否在同一命名空间。跨命名空间引用 Service 需要写全namespace/serviceName格式。NodePort 端口访问不通先确认节点防火墙和安全组放行了 30080 和 30443。然后在节点上ss -antup | grep 30080看端口是否监听。如果 Controller Pod 没起来端口自然不会监听回到kubectl get pod -n ingress-nginx看状态。CC Switch / Cline MCP / Codex auth.json 场景如果你在集群里跑编码 Agent配置时同样要写全三件套。以auth.json为例{ base_url: https://taotoken.net/api, api_key: sk-你的Key, model: gpt-4o-mini }Cline 的 MCP 配置里 Base URL 填https://taotoken.net/apiKey 填 Secret 里注入的值Model ID 填模型对话页面确认过的名称。三者缺一不可少任何一个都会在调用时报错。6. 把 Ingress 入口和统一 Key 通道固定成日常流程跑通一次之后建议把几个动作固化成习惯。第一Ingress 规则和 Service、Deployment 分文件管理命名上带业务名比如ingress-myapp.yaml、deploy-demo.yaml改规则时只动 Ingress 文件kubectl apply后 Controller 会自动热加载不需要重启。第二TaoToken 的 Key 永远走 SecretDeployment 里只引用不写明文轮换时更新 Secret 再rollout restart业务代码零改动。第三验证顺序固定成三步kubectl get ingress看规则是否注册kubectl get endpoints看后端是否有地址curl -H Host: ...看实际返回。这三步能覆盖大部分问题比盲目翻日志快得多。第四HTTPS 证书用 Secret 管理Ingress 的 tls 段引用 secretName证书更新后同样靠 Controller 热加载生效。日常排查时Controller 的日志是第一手信息kubectl logs -n ingress-nginx deploy/nginx-ingress-controller -f能实时看到规则变更和请求转发记录。如果日志里出现 upstream 相关错误基本可以定位到 Service 或 Pod 层不用在 Ingress 规则上反复改。需要长期跑编码任务或 Agent 的话Coding Plan 地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 模型列表在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。把 Ingress 入口和统一 Key 通道这两条链路都固定下来集群里的服务暴露和模型调用就不再是每次都要重新摸索的事。