ingress-nginx 主机名路由(Host Based Routing)实战:单负载均衡器按域名分发到多后端服务
【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx
本文以 ingress-nginx 控制器为对象,讲解最常用的"基于主机名(Host)的路由"场景:一个由 ingress-nginx 驱动的负载均衡器,同时承载多个域名,并将每个域名的流量路由到不同的 Kubernetes Service 后端。读完本文,你将掌握 Ingress 资源在两个 Kubernetes API 版本(v1beta1与networking.k8s.io/v1)下的完整写法、ingressClassName与kubernetes.io/ingress.class注解的控制机制、外部 IP 获取与 DNS 配置流程,并从源码层面理解控制器"如何识别并接管一个 Ingress"。
场景概述
ingress-nginx 适用于多种使用场景、多种云厂商环境,并支持大量配置项。本文聚焦其中最典型的一个:
- 集群中已经存在两个
type: ClusterIP的 HTTP 服务:myservicea与myserviceb(注意:后端服务的类型必须是 ClusterIP,由 ingress-nginx 通过 Service 的 ClusterIP 进行代理转发); - 希望将域名
myservicea.foo.org的流量路由到myservicea; - 希望将域名
myserviceb.foo.org的流量路由到myserviceb; - 两个域名共享同一个由 ingress-nginx 创建的负载均衡器入口。
这是 Kubernetes Ingress 最基础、也最常用的能力:一个入口、多域名、多后端,按 Host 字段分发。
前置条件:先安装 ingress-nginx
在创建任何 Ingress 资源之前,需要先完成 ingress-nginx 的安装。仓库中提供了不同场景的部署方式与说明:
- 部署总览与各云厂商方案可参考 docs/deploy/index.md;
- 裸金属集群(baremetal)的部署与注意事项可参考 docs/deploy/baremetal.md;
- 控制器启动参数(如
--ingress-class、--watch-ingress-without-class等会影响下文 Ingress 接管逻辑的 Flag)可参考 docs/user-guide/cli-arguments.md。
安装完成后,集群中会运行一个(或多个)ingress-nginx 控制器实例,并通常伴随一个负载均衡器类型的 Service(详见下文"获取外部 IP"一节)。
面向 Kubernetes < 1.19 集群的 Ingress 写法(networking.k8s.io/v1beta1)
如果集群版本低于 1.19(Kubernetes 1.18 及以下),可以使用networking.k8s.io/v1beta1API 创建两个 Ingress 资源。示例中特意展示了两种指定控制器的方式,便于对照:
- 第一个 Ingress(
ingress-myservicea)使用spec.ingressClassName: nginx(ingressClassName字段在 v1beta1 中已可被部分版本识别,但在旧版本中仍以注解为主); - 第二个 Ingress(
ingress-myserviceb)使用注解kubernetes.io/ingress.class: "nginx"声明"使用共享的 ingress-nginx"。
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: ingress-myservicea spec: ingressClassName: nginx rules: - host: myservicea.foo.org http: paths: - path: / backend: serviceName: myservicea servicePort: 80 --- apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: ingress-myserviceb annotations: # use the shared ingress-nginx kubernetes.io/ingress.class: "nginx" spec: rules: - host: myserviceb.foo.org http: paths: - path: / backend: serviceName: myserviceb servicePort: 80需要注意,v1beta1版本中backend使用的是serviceName/servicePort这种扁平写法,路径匹配行为也与此后的v1版本存在差异。
面向 Kubernetes >= 1.19 集群的 Ingress 写法(networking.k8s.io/v1)
如果集群版本在 1.19.x 及以上,官方建议使用networking.k8s.io/v1API 创建 Ingress 资源。相比v1beta1,v1版本的主要变化包括:
backend改为嵌套的service.name+service.port.number(或service.port.name)结构;- 每个
path必须显式声明pathType(Prefix/Exact/ImplementationSpecific),本文示例使用Prefix表示前缀匹配; ingressClassName成为标准字段,用于指定由哪个 IngressClass 对应的控制器接管。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-myservicea spec: rules: - host: myservicea.foo.org http: paths: - path: / pathType: Prefix backend: service: name: myservicea port: number: 80 ingressClassName: nginx --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-myserviceb spec: rules: - host: myserviceb.foo.org http: paths: - path: / pathType: Prefix backend: service: name: myserviceb port: number: 80 ingressClassName: nginx将上述 YAML 通过kubectl apply -f <file>应用后,集群中会创建两个 Ingress 资源,并由同一个 ingress-nginx 实例统一管理。
控制器如何发现并接管 Ingress:ingress class 判定机制
文档明确说明:ingress-nginx 会自动发现所有带kubernetes.io/ingress.class: "nginx"注解、或声明了ingressClassName: nginx的 Ingress 资源。这一"发现/接管"判定在源码中有非常清晰的实现,对应 internal/ingress/controller/store/store.go 中的GetIngressClass函数,其判定优先级依次为:
spec.ingressClassName(优先):只要IgnoreIngressClass未开启且 Ingress 声明了ingressClassName,控制器就会到 IngressClass 列表中查找同名对象并接管它;kubernetes.io/ingress.class注解(兼容):当ingressClassName缺失时,回退检查注解kubernetes.io/ingress.class,其值必须与控制器配置的AnnotationValue(默认为nginx)一致;- 无 class 的 Ingress(可选):如果开启了
WatchWithoutClass,控制器也会接管未声明任何 class 的 Ingress。
相关常量定义在 internal/ingress/controller/ingressclass/ingressclass.go:
IngressKey = "kubernetes.io/ingress.class":旧版注解键;DefaultControllerName = "k8s.io/ingress-nginx":IngressClass 资源中spec.controller的默认值;DefaultAnnotationValue = "nginx":注解的默认期望值。
在 internal/ingress/controller/controller.go 中,控制器在同步每个 Ingress 前都会调用GetIngressClass进行校验:如果校验失败(例如 class 不匹配),该 Ingress 会被直接忽略(记录 warning 日志),不会被写入 NGINX 配置。因此,如果发现创建的 Ingress 没有生效,应首先检查ingressClassName或注解值是否与控制器实际监听的 class 一致。
关键约束:Ingress 与后端 Service 必须在同一命名空间
需要注意,Ingress 资源必须与它所引用的后端 Service 放在同一个 Namespace 中。Kubernetes Ingress 的backend.service.name只能引用同命名空间内的 Service,Ingress 不支持跨命名空间引用后端。这也意味着,如果你的两个后端服务分别部署在不同 Namespace,就需要分别在对应 Namespace 下创建各自的 Ingress 资源。
获取负载均衡器外部 IP 并配置 DNS
ingress-nginx 部署后,在众多云厂商环境中会自动创建对应的负载均衡器(Load Balancer)资源。此时你只需要做两件事:
- 获取负载均衡器的外部 IP;
- 在 DNS 服务商处为
myservicea.foo.org和myserviceb.foo.org分别添加指向该 IP 的A 记录。
获取外部 IP 的命令:
kubectl get services -n ingress-nginx输出中ingress-nginx-controller这个 Service(类型通常为LoadBalancer)的EXTERNAL-IP列即为入口 IP。将两个域名解析到该 IP 后,访问http://myservicea.foo.org与http://myserviceb.foo.org就会被同一个 ingress-nginx 实例按 Host 分别路由到myservicea与myserviceb。
主机名路由的底层原理
从源码结构看,ingress-nginx 在同步时会遍历每个 Ingress 的spec.rules,将每个rule.Host生成为 NGINX 配置中的一个server 块,同一个 Host 下的多个path则生成为该 server 块内的多个location 块。相关逻辑集中在 internal/ingress/controller/controller.go 附近(host := rule.Host之后的 server/location 构建流程),并会:
- 将 Host 统一转为小写进行归一化处理(源码中通过
toLowerCaseASCII处理,见 internal/ingress/controller/controller.go),保证匹配不区分大小写; - 在写入模板前对同一 Host 下的 location 按路径长度降序排列,以提高路径匹配的准确性;
- 如果两个 Ingress 声明了完全相同的
host + path组合,控制器会报错并拒绝生成配置(见 internal/ingress/controller/controller.go 的冲突检测),避免出现二义性路由。
因此,本文示例最终会生成两个 server 块(myservicea.foo.org、myserviceb.foo.org),各自包含一个location /转发到对应后端。
进阶:Host + Path 组合路由
host based routing 可以和 path based routing 自由组合:同一个 Host 下可以声明多个path,分别路由到不同 Service。例如在myservicea.foo.org下同时提供/api与/static两个路径前缀。路径匹配的详细规则(Prefix/Exact/ImplementationSpecific三种pathType的差异、正则表达式支持、路径优先级与告警事项)可参考 docs/user-guide/ingress-path-matching.md。
本地环境测试提示
如果使用 minikube 等本地环境进行验证,需要注意:minikube 下获取外部 IP 的方式与云厂商略有差异(通常需要借助minikube tunnel或将 Service 改为 NodePort 后通过节点 IP 访问)。具体操作可结合 docs/deploy/baremetal.md 中关于裸金属/本地部署的说明进行。验证时可直接通过 curl 携带Host头测试:
curl -H "Host: myservicea.foo.org" http://<负载均衡器IP>/ curl -H "Host: myserviceb.foo.org" http://<负载均衡器IP>/如果返回各自后端的响应内容,即说明 host based routing 已正确生效。
小结
本文完整覆盖了 ingress-nginx 主机名路由的基础用法:从新旧两版 Kubernetes API 的 Ingress 写法,到ingressClassName/kubernetes.io/ingress.class的接管判定逻辑(含 源码级解析),再到外部 IP 获取与 DNS 配置。掌握这一场景后,你可以继续深入 docs/user-guide/nginx-configuration/annotations.md 学习重写、限流、认证等高级注解,或通过 docs/user-guide/index.md 浏览完整的用户指南。
【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考