☰
NGINX Ingress Controller 的 VirtualServer 自定义资源完全指南:从基本路由到流量治理
2026/10/13 2:40:21 网站建设 项目流程
  • API网关
  • 云原生
  • 负载均衡
  • 可观测性
  • 微服务

【免费下载链接】kubernetes-ingress

NGINX and NGINX Plus Ingress Controllers for Kubernetes

项目地址:https://gitcode.com/gh_mirrors/ku/kubernetes-ingress
点击查看免费下载

VirtualServer是 NGINX Ingress Controller(本仓库 kubernetes-ingress)提供的一等公民自定义资源(CRD),用于在标准 Kubernetes Ingress 之上实现高级配置能力:基于内容的精细化路由、流量切分、请求/响应头修改、TLS 终止与 cert-manager 集成、主动健康检查、URI 重写以及 NGINX App Protect 集成等。读完本文,你将掌握 VirtualServer 的完整字段模型、最小可用配置、上游(upstream)调优、路由动作(action)组合、高级路由(matches/splits)、路由委托(VirtualServerRoute)以及它如何被 Ingress Controller 校验并翻译为 NGINX 配置。

VirtualServer 是什么:资源定位与设计意图

VirtualServer归属于 API 组k8s.nginx.org,版本为v1,Kind为VirtualServer,作用域为Namespaced。官方 API 文档定义位于 docs/crd/k8s.nginx.org_virtualservers.md,其 Go 类型定义位于 pkg/apis/configuration/v1/types.go。

与原生 Ingress 相比,VirtualServer 的优势在于:它直接暴露了 NGINX 的server、location、upstream等核心概念,支持在同一资源内完成"域名 → 路由 → 上游 → 动作"的完整声明,而不需要借助大量注解来扩展行为。CRD 还注册了短名vs,并内置状态打印列(State、Host、IP、ExternalHostname、Ports、Age),这些定义可以从 config/crd/bases/k8s.nginx.org_virtualservers.yaml 中看到:

spec: names: kind: VirtualServer listKind: VirtualServerList plural: virtualservers shortNames: - vs singular: virtualserver scope: Namespaced

安装 CRD 的方式与安装控制器一致,例如kubectl apply -f deploy/crds.yaml。注意 VirtualServer 与 VirtualServerRoute 在共享 host 时通过host字段进行关联,且 host 必须在所有 Ingress 与 VirtualServer 资源中唯一。

从一个最小可用示例开始

仓库中的 examples/custom-resources/basic-configuration/cafe-virtual-server.yaml 给出了最经典的 cafe 示例——两个上游、两个路径、TLS 终止:

apiVersion: k8s.nginx.org/v1 kind: VirtualServer metadata: name: cafe spec: host: cafe.example.com tls: secret: tls-secret upstreams: - name: tea service: tea-svc port: 80 - name: coffee service: coffee-svc port: 80 routes: - path: /tea action: pass: tea - path: /coffee action: pass: coffee

创建后通过kubectl get vs即可查看状态;只有状态为Valid的 VirtualServer 才会被控制器接受并生成 NGINX 配置(详见下文"校验与状态")。

spec 顶层字段总览

.spec支持的顶层字段如下(完整字段表以 docs/crd/k8s.nginx.org_virtualservers.md 为准):

字段类型说明
hoststring服务器域名,必须是 RFC 1123 合法子域(如my-app、hello.example.com)。使用通配域名*.example.com时必须加双引号包裹。在所有 Ingress 与 VirtualServer 资源中必须唯一
ingressClassNamestring指定由哪个 Ingress Controller 处理该资源,须与引用它的 VirtualServer 的 ingressClassName 一致
listenerobject自定义 HTTP/HTTPS 监听器,listener.http与listener.https须引用 GlobalConfiguration 中定义的监听器名
tlsobjectTLS 终止配置(详见下文)
gunzipboolean是否对 gzip 响应解压后转发给客户端,取值on/off、true/false、yes/no,默认 off
policiesarray策略引用列表,policies[].name为策略名、policies[].namespace缺省时使用 VirtualServer 所在命名空间。若引用的策略不存在或无效,NGINX 会返回 500 错误响应
upstreamsarray上游(后端服务)列表(详见下文)
routesarray路由列表(详见下文)
http-snippetsstring在 http 上下文插入自定义配置片段
server-snippetsstring在 server 上下文插入自定义配置片段,覆盖 ConfigMap 的server-snippets键
add-header-inheritstring服务器级别的响应头继承行为,取值on/off/merge。merge表示与子上下文头合并;on采用标准 NGINX 继承;off表示不从父上下文继承任何头。Go 类型中通过+kubebuilder:validation:Enum=on;off;merge约束取值
dosstring对DosProtectedResource的引用,启用后对 VirtualServer 路由生效 DOS 防护
externalDNSobjectExternalDNS 集成配置(详见下文)

listener:引用 GlobalConfiguration 中的自定义监听器

examples/custom-resources/custom-listeners/cafe-virtual-server.yaml 展示了如何让 VirtualServer 监听在自定义端口上:

spec: listener: http: http-8083 https: https-8443 host: cafe.example.com tls: secret: tls-secret

这里的http-8083、https-8443必须是在 GlobalConfiguration 资源中定义过的监听器名。需要同时定义监听器协议与地址,例如http-8083对应监听8083端口的 HTTP 监听器。

tls:终止、重定向与 cert-manager 集成

tls对象包含三个部分:

tls.secret:存放 TLS 证书与私钥的 Secret 名称。Secret 必须与 VirtualServer 同命名空间,推荐类型为kubernetes.io/tls或Opaque,并须以 TLS 角色解析,证书链存放在tls.crt、私钥存放在tls.key。若 Secret 不存在或无效,NGINX 会中断对该 host 的一切 TLS 连接尝试;若未指定 Secret 但配置了通配 TLS Secret,则使用通配 Secret 终止 TLS。

tls.redirect:HTTP→HTTPS 强制跳转配置:

字段类型说明
enableboolean是否启用 TLS 重定向,默认 false
codeinteger重定向状态码,允许 301/302/307/308,默认 301
basedOnstring判断依据:scheme(请求协议)或x-forwarded-proto(X-Forwarded-Proto 头),默认scheme

tls.cert-manager:让控制器代为签发证书:

字段说明
issuer同命名空间的 Issuer 名;issuer与cluster-issuer二选一且必须且只能定义一个
cluster-issuerClusterIssuer 名(非命名空间资源,任意命名空间可用)
issuer-kind/issuer-group外部(out-of-tree)Issuer 的 Kind 与 API 组,例如AWSPCAIssuer/awspca.cert-manager.io;不能与cluster-issuer同时定义
common-name生成证书的spec.commonName,为 x509 证书添加 CN
duration/renew-before证书有效期与续期提前量,使用 Gotime.Duration格式(只能用s/m/h后缀,不能用d天后缀)
usages证书用途,逗号分隔字符串,如key agreement,digital signature, server auth
issue-temp-cert为 true 时,在正式证书签发前先向 cert-manager 申请临时自签名证书,使 HTTPS-only 服务器能在 Secret 尚不存在时完成 ACME HTTP01 挑战

仓库示例 examples/custom-resources/certmanager/cafe-virtual-server.yaml 展示了基于cluster-issuer的完整用法。

externalDNS:为 VirtualServer 自动创建 DNS 记录

字段类型说明
enableboolean启用 ExternalDNS 集成,默认 false
recordTypestring记录类型,如A、AAAA、CNAME;不定义时根据外部端点自动计算
recordTTLintegerDNS 记录 TTL,默认 0
labelsobject应用到 Endpoint 资源的标签,供 ExternalDNS 消费
providerSpecificarray各 DNS 提供商的专属属性,每项含name与value

对应示例见 examples/custom-resources/external-dns/cafe-virtual-server.yaml。该配置由控制器在同步阶段转换为 externaldns 的 Endpoint 资源(相关实现位于 internal/externaldns)。

upstreams:后端服务的完整调优面板

upstreams[]是 VirtualServer 中"服务发现 + 负载均衡 + 连接调优"的核心。其 Go 定义位于 pkg/apis/configuration/v1/types.go。基础字段:

字段类型说明
namestring上游名,RFC 1035 合法 DNS 标签(如hello、upstream-123),在资源内唯一
servicestring服务名。跨命名空间时须带命名空间前缀(如tea-namespace/tea)。服务不存在时 NGINX 视为零端点,请求返回 502;NGINX Plus 还支持同命名空间的 ExternalName 服务
portinteger服务端口,范围 1..65535;若服务未定义该端口,NGINX 视为零端点并返回 502
subselectorobject按标签键值进一步挑选服务内的 Pod(默认选全部)。注意:标签应在 Pod 创建时存在,Pod 标签更新后控制器要等到 Pod 数量变化才能感知
typestring上游类型,http(默认)或grpc。gRPC 需在 ConfigMap 启用 HTTP/2 并在 VirtualServer 配置 TLS 终止
lb-methodstring负载均衡算法,轮询写法为round_robin;默认取 ConfigMaplb-method键
use-cluster-ipboolean使用服务的 Cluster IP:Port 代替 Pod IP:Port。启用后,与多上游相关的字段(lb-method、next-upstream等)不再生效

连接、超时与缓冲

字段说明
connect-timeout/read-timeout/send-timeout建立连接、读取响应、发送请求的超时;默认分别取 ConfigMap 的proxy-connect-timeout、proxy-read-timeout、proxy-send-timeout
fail-timeout/max-fails判定服务器不可用所需的失败次数与时间窗;默认取 ConfigMap 对应键
next-upstream哪些情况下把请求转给下一个上游,默认error timeout
next-upstream-timeout/next-upstream-tries转发的总时间上限与尝试次数上限,0 表示不限制,默认 0
buffering是否缓冲上游响应,默认取 ConfigMapproxy-buffering
buffers.number/buffers.size单连接读取响应的缓冲数量与大小,默认取 ConfigMapproxy-buffers
buffer-size读取响应首部分的缓冲大小,默认取 ConfigMapproxy-buffer-size
busy-buffers-sizeproxy_buffering开启时用于读取响应的忙缓冲大小,默认取 ConfigMapproxy-busy-buffers-size
client-max-body-size客户端请求体最大允许大小,默认取 ConfigMap 对应键
client-body-buffer-size读取客户端请求体的缓冲大小,必须为数字加k(KB)或m(MB),如10m、512k(Go 类型中用Pattern=\^\d+[kKmM]?$`` 校验)
keepalive到上游的连接缓存大小,0 表示禁用;默认取 ConfigMapkeepalive
max-conns到单个上游服务器的最大并发活动连接数,默认不限
proxy-http-version与上游通信的 HTTP 版本,允许1.0/1.1/2。未设置时使用后端 Service 端口的appProtocol(kubernetes.io/h2c视为2),否则默认 HTTP/1.1;grpc类型固定使用 HTTP/2 且忽略该字段,WebSocket 必须用 HTTP/1.1,1.0会向发送上游Connection: close头
ntlm是否允许 NTLM 认证代理(仅 NGINX Plus),需要配合keepalive使用

tls 与健康检查

upstreams[].tls:tls.enable为 true 时对上游启用 HTTPS(默认 false,使用 HTTP)。注意:默认 NGINX 不校验上游证书,如需校验请配置 EgressMTLS Policy。

upstreams[].healthCheck(仅 NGINX Plus 支持):

字段说明
enable启用主动健康检查,默认 false
path健康检查请求路径,默认/(gRPC 上游不可配置)
interval/jitter检查间隔(默认 5s)与随机延迟时间(默认无)
fails/passes判定不健康/恢复健康的连续失败/成功次数,默认均为 1
port健康检查使用的 Pod 端口(注意:不是 Service 端口),默认使用服务器端口
connect-timeout/read-timeout/send-timeout健康检查的连接/读/写超时,默认沿用上游对应超时
headers[]健康检查请求的额外头(Host、User-Agent、Connection 由 NGINX Plus 自动设置)
statusMatch期望的状态码,如200、! 500、301-303 307,默认 2xx/3xx;gRPC 上游不支持
grpcService/grpcStatus仅 gRPC 上游:被监控的 gRPC 服务与期望的 gRPC 状态码(如服务未实现健康检查协议时配置 12)
mandatory新加入的服务器必须先通过全部健康检查才接收流量;配合slow-start可让新服务器"预热"
persistent重载后若服务器此前健康则保持 up 状态;开启 persistent 要求 mandatory 也为 true
keepalive-time健康检查 keepalive 连接复用时间,默认 60s
tls.enable健康检查是否使用 HTTPS(默认 false,且默认不校验上游证书)

完整的可运行示例见 examples/custom-resources/health-checks/README.md,其中展示了enable: true、path: /healthz、interval: 20s、fails/passes: 5、port: 8080、自定义Host头与statusMatch: "! 500"的组合。

会话保持、队列、慢启动与备份

sessionCookie:基于 NGINX 生成的会话 Cookie 的会话保持,使同一客户端始终被路由到同一上游:

字段说明
enable启用,默认 false
name/path/domainCookie 名、生效路径、生效域名
expires浏览器保留 Cookie 的时间;特殊值max表示 Cookie 于 2037-12-31 23:55:55 GMT 过期
httpOnly/secure添加 HttpOnly / Secure 属性
samesiteSameSite 属性,允许strict/lax/none

queue(仅 NGINX Plus):当无法立即选中上游服务器时,将请求放入队列,queue.size为队列大小,queue.timeout默认 60s,超时后请求不再排队。

slow-start:服务器恢复/可用后,权重从 0 逐渐恢复到标称值;默认禁用。注意:不能与random、hash、ip_hash负载均衡方法同时使用(源码 internal/configs/virtualserver.go 中的incompatibleLBMethodsForSlowStart表明确列出这些冲突方法)。

backup/backupPort:备份服务(ExternalName 类型)名称及其端口(提供备份名时端口必填,范围 1..65535)。主服务器全部不可用时启用备份;同样不能与random、hash、ip_hash混用。

routes 与 action:路径匹配与请求处置

routes[]决定 NGINXlocation的生成。核心字段:

字段类型说明
pathstring路径匹配规则,支持前缀(/、/path)、最长前缀(^~/images/)、精确匹配(=/exact/match)、大小写不敏感正则(~*^/Bar.*\.jpg)与大小写敏感正则(~^/foo.*\.jpg)。前缀/最长前缀/精确匹配不得含空白、{、}、;;正则须转义双引号且不能以未转义的反斜杠结尾。路径在该 VirtualServer 内必须唯一
actionobject该路由的默认动作
splitsarray默认流量切分,至少 2 个 split,权重 0..100 且总和必须为 100
matchesarray高级内容路由匹配规则(见下文),未匹配的请求走默认 action/splits
errorPagesarray对指定错误码的定制响应
routestring委托给 VirtualServerRoute 资源,跨命名空间时写命名空间/名称(如tea-namespace/tea)
routeSelectorobject用标签选择器(matchLabels/matchExpressions,表达式支持In、NotIn、Exists、DoesNotExist,多个条件 AND 连接)选择 VirtualServerRoute
policiesarray路由级策略,覆盖 spec 中同类型策略
location-snippetsstringlocation 上下文自定义片段,覆盖 ConfigMaplocation-snippets键
add-header-inheritstringlocation 级别的头继承行为,取值同 spec 级
dosstring引用 DosProtectedResource,对该路由启用 DOS 防护

action 的四种形态

action只能且必须定义以下四种之一,Go 定义见 pkg/apis/configuration/v1/types.go:

pass(直通转发):action.pass: tea将请求直接传给同资源内定义的名为tea的上游。这是最简单、性能最好的转发方式。

proxy(代理并改造):

字段说明
upstream目标上游名,必须已在资源中定义
rewritePath重写后的 URI;当路由路径是正则(以~开头)时可用$1-$9捕获组
requestHeaders.pass是否将原始请求头传给上游,默认 true
requestHeaders.set[]重定义或追加请求头,每项含name、value
responseHeaders.hide[]不传给客户端的响应头
responseHeaders.pass[]允许透传被隐藏的响应头
responseHeaders.ignore[]禁用对某些响应头的处理
responseHeaders.add[]向客户端响应添加头,每项含name、value,always: true时无视响应状态码强制添加(默认 false)

redirect(重定向):redirect.url为目标 URL,支持 NGINX 变量$scheme、$http_x_forwarded_proto、$request_uri、$host,变量须用花括号包裹(如${host}${request_uri});redirect.code允许 301/302/307/308,默认 301。

return(返回预置响应):return.code允许 2XX/4XX/5XX,默认 200;return.type为 MIME 类型,默认text/plain;return.body支持花括号包裹的 NGINX 变量(如Request is ${request_uri}\n);return.headers[]为自定义响应头。

URI 重写实战

examples/custom-resources/rewrites/README.md 给出了前缀与正则两种重写示例。前缀路径重写:

routes: - path: /tea/ action: proxy: upstream: tea rewritePath: / - path: /coffee action: proxy: upstream: coffee rewritePath: /beans

效果:/tea/abc→/abc;/coffee/abc→/beans/abc。正则重写(捕获组传递剩余 URI):

- path: ~ /tea/?(.*) action: proxy: upstream: tea rewritePath: /$1

效果:/tea、/tea/→/;/tea/abc→/abc。注意/tea前缀请求会被重定向到/tea/。对应生成逻辑在 internal/configs/virtualserver.go 的generateRewrites与generateProxyPassRewrite中实现。

高级路由:matches、conditions 与 splits

routes[].matches[]实现基于内容的精细化路由(advanced content-based routing)。每个 match 至少包含 1 个conditions,并定义一个action或一组splits。匹配规则按顺序求值,未匹配的请求由路由的默认 action 或 splits 处理。

条件类型(conditions[]),Go 定义见 pkg/apis/configuration/v1/types.go:

字段说明
header请求头名,须由字母数字或-组成
cookieCookie 名,须由字母数字或_组成
argument请求参数名,须由字母数字或_组成
variableNGINX 变量名,必须以$开头
value匹配的目标值

examples/custom-resources/advanced-routing/cafe-virtual-server.yaml 同时示范了变量条件与 Cookie 条件:

- path: /tea matches: - conditions: - variable: $request_method value: POST action: pass: tea-post action: pass: tea - path: /coffee matches: - conditions: - cookie: version value: v2 action: pass: coffee-v2 action: pass: coffee-v1

这里/tea的 POST 请求走tea-post,其余走tea;/coffee携带version=v2Cookie 的请求走coffee-v2,其余走coffee-v1。匹配逻辑由 internal/configs/virtualserver.go 的generateMatchesConfig翻译为 NGINX 的map+ 内部 location 结构。

流量切分(splits):examples/custom-resources/traffic-splitting/cafe-virtual-server.yaml 演示了金丝雀发布最常用的 90/10 切分:

routes: - path: /coffee splits: - weight: 90 action: pass: coffee-v1 - weight: 10 action: pass: coffee-v2

weight取值 0..100,所有 split 权重之和必须等于 100。控制器基于split_clients/keyval 机制实现动态权重(参见 internal/configs/virtualserver.go 的generateSplitsForWeightChangesDynamicReload及 internal/k8s 中关于 DynamicWeightChangesReload 的实现)。

路由委托:VirtualServerRoute 与 routeSelector

当单个 VirtualServer 过大或需要跨团队协作时,可以将路由定义拆分到 VirtualServerRoute 资源中。方式一:通过routes[].route显式引用:

routes: - path: /tea route: default/tea

方式二:通过routeSelector按标签批量选择:

routes: - path: / routeSelector: matchLabels: app: coffee

完整示例见 examples/custom-resources/basic-configuration-vsr/cafe-virtual-server.yaml。控制器在同步时会把选中的 VirtualServerRoute 合并进 VirtualServer 的生成配置(VirtualServerEx结构中的VirtualServerRoutes与VirtualServerSelectorRoutes字段即用于承载这些路由,见 internal/configs/virtualserver.go)。

校验与状态:从声明到 Valid 的旅程

VirtualServer 提交到集群后,控制器会执行两轮校验:

  1. CRD 模式校验:基于 config/crd/bases/k8s.nginx.org_virtualservers.yaml 中openAPIV3Schema的约束(枚举值、正则、必填项等),由 API Server 在写入时强制执行。
  2. 控制器业务校验:位于 pkg/apis/configuration/validation/virtualserver.go,配合 pkg/apis/configuration/validation/common.go 完成 host 唯一性、路径格式、权重总和、引用存在性等检查,并返回三种状态(定义见 pkg/apis/configuration/v1/types.go):
    • Valid:校验通过并正常工作;
    • Warning:已接受但可能以降级状态运行;
    • Invalid:校验失败或 NGINX 重载对应配置失败。

状态会写入status.state / status.reason / status.message / status.externalEndpoints(见 pkg/apis/configuration/v1/types.go),并通过kubectl get vs打印列直接可见。

从源码看 VirtualServer 如何变成 NGINX 配置

VirtualServer 的"翻译"工作集中在 internal/configs/virtualserver.go(约 3000 行)。其生成函数与 NGINX 指令的对应关系可以帮你建立从 YAML 到nginx.conf的映射直觉:

生成函数对应 NGINX 配置
generateUpstreams(L1406)upstream块:server、keepalive、max_conns、slow_start等
generateHealthCheck(L1789)NGINX Plus 的health_check指令
generateLocation/generateLocationForProxying/generateLocationForRedirect/generateLocationForReturn(L2085 起)各类location块
generateProxySetHeaders、generateProxyHideHeaders、generateProxyAddHeaders(L2108 起)proxy_set_header、proxy_hide_header、add_header等
generateSplits/generateMatchesConfig(L2323、L2517)split_clients/map+ 内部 location 路由
generateErrorPages(L2981)error_page指令
generateTLSRedirectConfig(L2817)基于$scheme/$http_x_forwarded_proto的 301/302 重定向

这套生成逻辑同样服务于 VirtualServerRoute 合并后的路由与 gRPC 上游(generateGRPCPass)。相关单元测试可在 internal/configs/virtualserver_test.go 中找到,端到端的行为验证则覆盖在 tests/suite/test_virtual_server.py 等测试套件中。

延伸阅读

  • VirtualServer 官方字段参考
  • VirtualServerRoute 资源参考
  • GlobalConfiguration(自定义监听器)参考
  • examples/custom-resources 目录下的全部可运行示例,尤其是 basic-configuration、advanced-routing、traffic-splitting 与 rewrites
  • Policy 资源参考 与 App Protect DOS 资源参考,用于理解policies与dos字段的对接对象
  • API网关
  • 云原生
  • 负载均衡
  • 可观测性
  • 微服务

【免费下载链接】kubernetes-ingress

NGINX and NGINX Plus Ingress Controllers for Kubernetes

项目地址:https://gitcode.com/gh_mirrors/ku/kubernetes-ingress
点击查看免费下载

相关推荐

上一篇:Sunshine游戏串流终极指南:15分钟打造你的个人云游戏平台
下一篇:Python Machine Learning Book 过拟合深度指南:从学习曲线诊断到正则化与降维实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询