news 2026/10/2 6:45:10

Kubernetes 安装 nginx-controller 作为统一网关:TaoToken 统一 Key 接入实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kubernetes 安装 nginx-controller 作为统一网关:TaoToken 统一 Key 接入实践

1. 为什么要在 K8s 里用 nginx-controller 做统一网关

很多团队在 Kubernetes 里跑微服务,前端、后端、AI 能力调用各走各的入口,时间一长就会出现证书散落、路由规则混乱、鉴权逻辑重复的问题。我试过把 nginx-controller 作为集群的统一入口网关,把外部流量先收进来,再由网关按域名和路径转发到后端服务,后端服务再通过 TaoToken 的统一 Key 去调用大模型能力,整条链路会清爽很多。

nginx-controller 本质上是一个 Kubernetes Operator,它监听你创建的 NginxConf 自定义资源,把配置动态渲染成本地 nginx 的配置文件并热更新。你可以把它理解成「用 K8s 的声明式方式管理 nginx 配置」:加一个代理、挂一张证书、改一段 gzip 策略,都通过kubectl apply完成,不需要登录到 nginx 容器里手改nginx.conf。它支持 http、stream、custom 三种配置类型,证书可以来自 Value 内联、ConfigMap 或 Secret,更新时通过注解触发事件即可。

这套方案适合谁?适合已经在用 K8s、希望把入口流量统一收口、同时又想让后端服务以统一通道调用大模型 API 的团队。本文会从 CRD 安装、controller 部署、Ingress 路由、TLS 证书三种挂载方式,一直讲到用 curl 验证网关转发和 TaoToken 鉴权是否生效,每一步都给可复制的清单和命令。

核心检索词先明确:Kubernetes 安装 nginx-controller 作为统一网关,配合 TaoToken 统一 Key 接入大模型能力。下面按可跟做的顺序展开。

2. 安装 nginx-controller 的 CRD 与 Deployment 清单

2.1 创建 NginxConf 的 CRD

先准备 CRD。注意如果你的集群版本低于 1.29,需要删掉 CRD 里所有x-kubernetes-validations字段,否则 apply 会报 schema 校验错误。下面是精简后的 CRD 结构,保留了核心字段:

apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: nginxconfs.stable.lhstack.com spec: group: stable.lhstack.com scope: Namespaced names: kind: NginxConf plural: nginxconfs singular: nginxconf listKind: NginxConfList shortNames: - ncf versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object required: - config properties: configType: type: string enum: [http, stream, custom] default: http customConfigPath: type: string config: type: string additions: type: object properties: values: type: array items: type: object properties: value: type: string path: type: string configMaps: type: array items: type: object properties: name: type: string namespace: type: string path: type: string secrets: type: array items: type: object properties: name: type: string namespace: type: string path: type: string

执行创建:

kubectl apply -f crd.yaml kubectl explain NginxConf

kubectl explain能正常输出字段说明,就说明 CRD 注册成功了。

2.2 部署 controller 的 Deployment 与 Service

controller 我用 Deployment 部署,副本数 2 保证可用性,同时建一个 NodePort Service 暴露 80/443。清单如下:

apiVersion: v1 kind: Namespace metadata: name: ingress --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-controller namespace: ingress --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: nginx-controller subjects: - kind: ServiceAccount name: nginx-controller namespace: ingress roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-controller namespace: ingress spec: replicas: 2 selector: matchLabels: app: ingress template: metadata: labels: app: ingress spec: serviceAccountName: nginx-controller containers: - name: controller image: lhstack/nginx-controller:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http - containerPort: 443 name: https readinessProbe: httpGet: port: 9099 path: /readyz initialDelaySeconds: 5 periodSeconds: 30 livenessProbe: httpGet: port: 9099 path: /healthz initialDelaySeconds: 5 periodSeconds: 60 env: - name: KUBE_NAMESPACE value: "ingress" resources: requests: memory: 32Mi cpu: 10m limits: memory: 64Mi cpu: 10m --- apiVersion: v1 kind: Service metadata: name: ingress namespace: ingress spec: selector: app: ingress type: NodePort clusterIP: 10.43.80.80 ports: - port: 80 name: http protocol: TCP nodePort: 30080 - port: 443 name: https protocol: TCP nodePort: 30443

这里KUBE_NAMESPACE=ingress表示只监听 ingress 命名空间下的 NginxConf,做配置隔离。如果你希望监听所有命名空间,把这个环境变量留空即可。clusterIP固定成 10.43.80.80 是为了方便内网 DNS 指向,前提是集群里已经装了 DNS 服务。

apply 之后确认两个副本都起来了:

kubectl apply -f deployment.yaml kubectl -n ingress get pods -o wide kubectl -n ingress get svc ingress

看到两个 Running 的 Pod 和 NodePort 30080/30443,前置就绪。

3. 配置 Ingress 路由与 TaoToken 统一 Key 接入片段

3.1 用 NginxConf 写一条 http 代理

先写一条最简单的代理,把baidu.lhstack.com转发到外部站点,验证路由链路:

apiVersion: stable.lhstack.com/v1 kind: NginxConf metadata: name: baidu-web namespace: default spec: config: | server { server_name baidu.lhstack.com; listen 80; gzip on; gzip_types text/plain text/css application/json application/javascript; gzip_min_length 1000; gzip_comp_level 6; location / { proxy_pass https://www.baidu.com; proxy_http_version 1.1; } }
kubectl apply -f baidu-nginx-conf.yaml kubectl -n ingress logs -l app=ingress --tail=50

日志里能看到 controller 检测到 NginxConf 变更并完成 reload,就说明动态更新生效了。

3.2 后端服务通过 TaoToken 统一 Key 调用大模型

网关收口之后,后端服务调用大模型时不再各自维护 Key,而是统一走 TaoToken 的 API 通道。TaoToken 的 API 地址是https://taotoken.net/api,控制台和文档入口分别是:

  • 控制台:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
  • API Keys:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

后端服务里建议把 Base URL、Key、Model ID 三件套放进 ConfigMap 或 Secret,再由 Deployment 注入环境变量。下面是一个可复制的 settings 片段,路径与原文一致:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的TaoTokenKey", "model_id": "claude-sonnet-4-5", "timeout": 60, "max_retries": 2 }

如果你用的是 Codex 风格的auth.json,可以这样写:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的TaoTokenKey", "model": "claude-sonnet-4-5" }

在 K8s 里把它做成 Secret:

kubectl -n default create secret generic taotoken-cred \ --from-literal=TAOTOKEN_BASE_URL=https://taotoken.net/api \ --from-literal=TAOTOKEN_API_KEY=sk-你的TaoTokenKey \ --from-literal=TAOTOKEN_MODEL_ID=claude-sonnet-4-5

然后在后端 Deployment 里引用:

env: - name: TAOTOKEN_BASE_URL valueFrom: secretKeyRef: name: taotoken-cred key: TAOTOKEN_BASE_URL - name: TAOTOKEN_API_KEY valueFrom: secretKeyRef: name: taotoken-cred key: TAOTOKEN_API_KEY - name: TAOTOKEN_MODEL_ID valueFrom: secretKeyRef: name: taotoken-cred key: TAOTOKEN_MODEL_ID

这样后端服务只需要读环境变量,不把 Key 硬编码进镜像。网关层负责路由和 TLS,鉴权层由 TaoToken 统一 Key 承担,职责清晰。

3.3 给网关加上 TLS 证书

证书支持三种挂载方式:Value 内联、ConfigMap、Secret。先用 Value 方式演示,把证书内容直接写进 NginxConf:

apiVersion: stable.lhstack.com/v1 kind: NginxConf metadata: name: baidu-web namespace: default spec: additions: values: - path: /opt/tls/baidu/tls.key value: | -----BEGIN EC PRIVATE KEY----- ...你的私钥内容... -----END EC PRIVATE KEY----- - path: /opt/tls/baidu/tls.crt value: | -----BEGIN CERTIFICATE----- ...你的证书内容... -----END CERTIFICATE----- config: | server { listen 80; server_name baidu.lhstack.com; rewrite ^(.*)$ https://${server_name}$1 permanent; } server { server_name baidu.lhstack.com; listen 443 ssl http2; client_max_body_size 50m; ssl_certificate /opt/tls/baidu/tls.crt; ssl_certificate_key /opt/tls/baidu/tls.key; ssl_session_timeout 5m; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; location / { proxy_pass https://www.baidu.com; proxy_http_version 1.1; } }

如果证书用 ConfigMap 保存,把additions.values换成additions.configMaps:

spec: additions: configMaps: - name: baidu-nginx-conf namespace: kube-system path: /opt/tls/baidu

用 Secret 保存则换成additions.secrets,注意 Secret 的data要求 base64 格式:

apiVersion: v1 kind: Secret metadata: name: baidu-nginx-conf namespace: kube-system type: kubernetes.io/tls data: tls.key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0t... tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...

三种方式各有取舍:Value 适合临时验证,ConfigMap 适合明文配置,Secret 适合证书这类敏感内容。生产环境建议用 Secret。

4. 用 curl 验证网关转发与 TaoToken 鉴权是否生效

4.1 验证网关转发

先确认 NodePort 可达,把域名解析到节点 IP 或固定 clusterIP:

curl -I http://baidu.lhstack.com:30080 curl -I https://baidu.lhstack.com:30443 -k

预期看到 301 跳转到 https,以及 200 的响应头。如果返回 404,说明 NginxConf 没被 controller 加载,检查KUBE_NAMESPACE是否和 NginxConf 的 namespace 一致。

4.2 验证 TaoToken 鉴权

后端服务里用 curl 直接打 TaoToken 的 API,确认 Key 有效:

curl -sS https://taotoken.net/api/v1/messages \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "max_tokens": 64, "messages": [{"role": "user", "content": "ping"}] }'

返回里带content字段就说明鉴权通过。如果返回 401,说明 Key 无效或没带上Authorization头;如果返回local proxy failed,通常是 Base URL 写错或网络出口不通。

4.3 验证证书更新

证书过期后,如果用的是 ConfigMap 或 Secret,需要手动更新内容再触发事件:

kubectl annotate NginxConf --all -A --overwrite updated=$(date +%s)

如果只想更新某一个:

kubectl annotate -n default NginxConf baidu-web --overwrite update=$(date +%s)

用 Value 方式则不需要,因为 value 本身是 NginxConf 的字段,改动会自然触发更新。

5. 本篇常见报错排查

5.1 401 Unauthorized

最常见的是 Key 没带对。检查三件事:Authorization头是不是Bearer sk-xxx格式;Key 有没有多余空格;Base URL 是不是https://taotoken.net/api。如果后端服务从 Secret 注入,确认 Secret 的 key 名和 Deployment 里secretKeyRef.key完全一致。

5.2 local proxy failed

这个报错通常出现在请求还没到 TaoToken 就被本地网络拦了。检查集群节点能不能出网,DNS 能不能解析taotoken.net,以及有没有在 Pod 里配了错误的HTTP_PROXY。如果用了 NetworkPolicy,确认允许到 443 的出站流量。

5.3 reading choices 报错

这个一般出现在流式响应解析阶段,说明客户端把非流式响应当流式读了。检查请求体里有没有误加stream: true,或者客户端 SDK 的解析逻辑和实际响应格式不匹配。先用 curl 打一次非流式请求确认返回结构,再调客户端。

5.4 OAuth 相关报错

如果后端服务用的是 OAuth 方式拿 token,报错通常是 token 过期或 scope 不足。确认 token 有效期,以及申请的 scope 是否包含模型调用权限。用 API Key 方式可以绕开这类问题,建议后端服务优先用 Key。

5.5 NginxConf 不生效

先看 controller 日志:

kubectl -n ingress logs -l app=ingress --tail=100

如果日志里没有检测到 NginxConf,检查KUBE_NAMESPACE和 NginxConf 的 namespace 是否匹配。如果日志里有 reload 失败,检查config里的 nginx 语法,可以用nginx -t在本地先验证。

6. 把网关和统一 Key 串起来的下一步

整套链路跑通之后,你会发现入口流量和模型调用被拆成了两层:nginx-controller 负责路由、TLS、限流这些网关职责,TaoToken 负责统一 Key、模型路由、用量统计这些鉴权职责。后端服务只需要关心业务逻辑,不用再为每个模型维护一套 Key。

如果你还在选模型阶段,可以先用模型对话页面快速试一下不同模型的效果:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite

如果是要长期跑编码类或 Agent 类任务,建议直接上 Coding Plan,配额和稳定性更适合持续调用:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite

接入过程中遇到鉴权或路由问题,先查 API Keys 页面确认 Key 状态,再对照接入文档核对 Base URL 和请求格式:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 和 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

最后留一个实操建议:把 NginxConf 和 Secret 都纳入 Git 管理,证书更新走 CI 触发kubectl annotate,这样证书轮换就不会漏。网关配置和 Key 配置分离,排障时能快速定位是路由问题还是鉴权问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 6:43:07

简电云 | Java + WebSocket 实现 OCPP 2.0.1 充电桩模拟程序

一、为什么需要充电桩模拟器充电平台通常需要同时处理设备接入、订单、计费、告警和远程控制。如果所有测试都依赖真实充电桩,会遇到几个现实问题:设备数量有限,难以验证大量设备同时在线;插枪、刷卡、充电和拔枪需要人工操作&…

作者头像 李华
网站建设 2026/10/2 6:42:50

Claude Code实战:用TaoToken统一Key打通Harness工程链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 6:42:34

AI辅助学术专著写作:从选题到成稿的完整工作流与提示词框架

先聊点实际的。这两年用AI大模型写论文、写申报书的人越来越多,但真正敢把AI用在"学术专著"这个量级上的人,其实还是少数。原因很简单:专著不是长文,它有完整的理论框架、前后呼应的概念体系、统一的术语环境和严格的引…

作者头像 李华
网站建设 2026/10/2 6:42:18

从绳子到字符串:String 的底层逻辑与编程实战

1. 一个字符串的前世今生:从字母到语义的底层逻辑写了十几年代码,天天和 string 打交道,但真正让我停下来想"string 这个词到底从哪来的",是前阵子帮一个新手排查问题。他写了个String action intent.getAction()&…

作者头像 李华