Ingress

使用支持协议的配置机制来提供 HTTP(或 HTTPS)网络服务,该机制理解 URI、主机名、路径等 Web 概念。Ingress 概念允许你根据通过 Kubernetes API 定义的规则,将流量映射到不同的后端。

特性状态: Kubernetes v1.19 [stable]

一个 API 对象,用于管理集群中服务的外部访问,通常是 HTTP。

Ingress 可以提供负载均衡、SSL 终止和基于名称的虚拟主机。

术语

为清楚起见,本指南定义以下术语

  • 节点:Kubernetes 中的工作机器,集群的一部分。
  • 集群:一组运行由 Kubernetes 管理的容器化应用程序的节点。在此示例中,以及在大多数常见的 Kubernetes 部署中,集群中的节点不属于公共互联网。
  • 边缘路由器:为集群实施防火墙策略的路由器。这可以是云提供商管理的网关,也可以是物理硬件。
  • 集群网络:根据 Kubernetes 网络模型 促进集群内部通信的一组逻辑或物理链路。
  • Service:一个 Kubernetes Service,它使用 标签 选择器识别一组 Pod。除非另有说明,否则假定 Service 具有仅在集群网络内可路由的虚拟 IP。

什么是 Ingress?

Ingress 将集群外部的 HTTP 和 HTTPS 路由公开到集群内部的服务。流量路由由 Ingress 资源上定义的规则控制。

这里有一个简单的例子,一个 Ingress 将所有流量发送到一个 Service

ingress-diagram

图:Ingress

Ingress 可以配置为向 Service 提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS 并提供基于名称的虚拟主机。一个 Ingress 控制器 负责实现 Ingress,通常使用负载均衡器,但它也可以配置你的边缘路由器或额外的前端来帮助处理流量。

Ingress 不会暴露任意端口或协议。将 HTTP 和 HTTPS 之外的服务暴露给互联网通常使用 Service.Type=NodePortService.Type=LoadBalancer 类型的服务。

先决条件

你必须有一个 Ingress 控制器 才能满足 Ingress 的要求。仅仅创建一个 Ingress 资源是没有任何作用的。

你可能需要部署一个 Ingress 控制器,例如 ingress-nginx。你可以从多个 Ingress 控制器 中进行选择。

理想情况下,所有 Ingress 控制器都应符合参考规范。但实际上,各种 Ingress 控制器的操作方式略有不同。

Ingress 资源

最小 Ingress 资源示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

Ingress 需要 apiVersionkindmetadataspec 字段。Ingress 对象的名称必须是有效的 DNS 子域名。有关使用配置文件的一般信息,请参阅部署应用配置容器管理资源。Ingress 经常使用注解来配置一些选项,具体取决于 Ingress 控制器,例如 rewrite-target 注解。不同的 Ingress 控制器 支持不同的注解。请查阅你选择的 Ingress 控制器的文档,以了解支持哪些注解。

Ingress 规约 包含配置负载均衡器或代理服务器所需的所有信息。最重要的是,它包含一个与所有传入请求匹配的规则列表。Ingress 资源只支持用于引导 HTTP(S) 流量的规则。

如果省略 ingressClassName,则应定义一个 默认 Ingress 类

有一些 ingress 控制器,即使没有定义默认的 IngressClass 也能工作。例如,Ingress-NGINX 控制器可以通过一个 标志 --watch-ingress-without-class 进行配置。但是,建议 指定默认的 IngressClass,如下所示

Ingress 规则

每个 HTTP 规则包含以下信息:

  • 一个可选的主机。在此示例中,未指定主机,因此该规则适用于通过指定 IP 地址的所有入站 HTTP 流量。如果提供了主机(例如,foo.bar.com),则规则适用于该主机。
  • 路径列表(例如,/testpath),每个路径都有一个关联的后端,该后端通过 service.nameservice.port.nameservice.port.number 定义。主机和路径都必须与传入请求的内容匹配,负载均衡器才会将流量引导到引用的 Service。
  • 后端是 Service 和端口名称的组合,如 Service 文档 中所述,或者通过 CRD 实现的自定义资源后端。匹配规则主机和路径的 HTTP(和 HTTPS)请求将发送到列出的后端。

defaultBackend 通常在 Ingress 控制器中配置,用于处理与规约中任何路径都不匹配的请求。

默认后端

没有规则的 Ingress 将所有流量发送到单个默认后端,在这种情况下,.spec.defaultBackend 是应该处理请求的后端。defaultBackend 通常是 Ingress 控制器 的配置选项,不会在 Ingress 资源中指定。如果未指定 .spec.rules,则必须指定 .spec.defaultBackend。如果未设置 defaultBackend,则不匹配任何规则的请求的处理将由 Ingress 控制器决定(请查阅你的 Ingress 控制器文档,了解它如何处理这种情况)。

如果 Ingress 对象中的任何主机或路径都不匹配 HTTP 请求,则流量将路由到你的默认后端。

资源后端

Resource 后端是同一命名空间(与 Ingress 对象相同)中另一个 Kubernetes 资源的 ObjectRef。Resource 是与 Service 互斥的设置,如果同时指定两者,则验证将失败。Resource 后端的一个常见用法是将数据入站到具有静态资产的对象存储后端。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets

创建上述 Ingress 后,你可以使用以下命令查看它

kubectl describe ingress ingress-resource-backend
Name:             ingress-resource-backend
Namespace:        default
Address:
Default backend:  APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /icons   APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations:  <none>
Events:       <none>

路径类型

Ingress 中的每个路径都必须具有相应的路径类型。未包含显式 pathType 的路径将无法通过验证。支持三种路径类型:

  • ImplementationSpecific:使用此路径类型,匹配由 IngressClass 决定。实现可以将其视为单独的 pathType,也可以将其视为与 PrefixExact 路径类型相同。

  • Exact:精确匹配 URL 路径,区分大小写。

  • Prefix:根据按 / 分隔的 URL 路径前缀进行匹配。匹配区分大小写,并逐个路径元素进行。路径元素是指路径中按 / 分隔的标签列表。如果请求路径的每个 p 都是 p 的元素前缀,则请求与路径 p 匹配。

示例

种类路径请求路径匹配?
前缀/(所有路径)
精确/foo/foo
精确/foo/bar
精确/foo/foo/
精确/foo//foo
前缀/foo/foo, /foo/
前缀/foo//foo, /foo/
前缀/aaa/bb/aaa/bbb
前缀/aaa/bbb/aaa/bbb
前缀/aaa/bbb//aaa/bbb是,忽略尾部斜杠
前缀/aaa/bbb/aaa/bbb/是,匹配尾部斜杠
前缀/aaa/bbb/aaa/bbb/ccc是,匹配子路径
前缀/aaa/bbb/aaa/bbbxyz否,不匹配字符串前缀
前缀/, /aaa/aaa/ccc是,匹配 /aaa 前缀
前缀/, /aaa, /aaa/bbb/aaa/bbb是,匹配 /aaa/bbb 前缀
前缀/, /aaa, /aaa/bbb/ccc是,匹配 / 前缀
前缀/aaa/ccc否,使用默认后端
混合/foo (前缀), /foo (精确)/foo是,优先选择精确匹配

多重匹配

在某些情况下,Ingress 中的多个路径将匹配一个请求。在这些情况下,优先级将首先给予最长匹配路径。如果两个路径仍然等长匹配,则优先级将给予具有精确路径类型而非前缀路径类型的路径。

主机名通配符

主机可以是精确匹配(例如 “foo.bar.com”)或通配符(例如 “*.foo.com”)。精确匹配要求 HTTP host 头与 host 字段匹配。通配符匹配要求 HTTP host 头等于通配符规则的后缀。

主机主机头匹配?
*.foo.combar.foo.com基于共享后缀匹配
*.foo.combaz.bar.foo.com不匹配,通配符只覆盖一个 DNS 标签
*.foo.comfoo.com不匹配,通配符只覆盖一个 DNS 标签
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

Ingress 类

Ingress 可以由不同的控制器实现,通常具有不同的配置。每个 Ingress 都应指定一个类,该类是对 IngressClass 资源的引用,其中包含附加配置,包括应实现该类的控制器的名称。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

IngressClass 的 .spec.parameters 字段允许你引用另一个提供与该 IngressClass 相关的配置的资源。

要使用的参数的具体类型取决于你在 IngressClass 的 .spec.controller 字段中指定的 ingress 控制器。

IngressClass 范围

根据你的 ingress 控制器,你可能可以使用集群范围的参数,或者仅用于一个命名空间的参数。

IngressClass 参数的默认范围是集群范围。

如果你设置了 .spec.parameters 字段但没有设置 .spec.parameters.scope,或者你将 .spec.parameters.scope 设置为 Cluster,那么 IngressClass 将引用集群范围的资源。参数的 kind(与 apiGroup 结合)引用集群范围的 API(可能是一个自定义资源),参数的 name 标识该 API 的特定集群范围资源。

例如

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-1
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in a
    # ClusterIngressParameter (API group k8s.example.net) named
    # "external-config-1". This definition tells Kubernetes to
    # look for a cluster-scoped parameter resource.
    scope: Cluster
    apiGroup: k8s.example.net
    kind: ClusterIngressParameter
    name: external-config-1

特性状态: Kubernetes v1.23 [stable]

如果你设置了 .spec.parameters 字段并将 .spec.parameters.scope 设置为 Namespace,那么 IngressClass 将引用命名空间范围的资源。你还必须将 .spec.parameters 中的 namespace 字段设置为包含要使用的参数的命名空间。

参数的 kind(与 apiGroup 结合)引用命名空间 API(例如:ConfigMap),参数的 name 标识你在 namespace 中指定的命名空间中的特定资源。

命名空间范围的参数有助于集群操作员委托对工作负载所用配置(例如:负载均衡器设置、API 网关定义)的控制。如果你使用集群范围的参数,则:

  • 每次应用新的配置更改时,集群操作员团队都需要批准不同团队的更改。
  • 集群操作员必须定义特定的访问控制,例如 RBAC 角色和绑定,以允许应用程序团队更改集群范围的参数资源。

IngressClass API 本身始终是集群范围的。

这是一个引用命名空间参数的 IngressClass 示例

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-2
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in an
    # IngressParameter (API group k8s.example.com) named "external-config",
    # that's in the "external-configuration" namespace.
    scope: Namespace
    apiGroup: k8s.example.com
    kind: IngressParameter
    namespace: external-configuration
    name: external-config

已弃用的注解

在 Kubernetes 1.18 中添加 IngressClass 资源和 ingressClassName 字段之前,Ingress 类是通过 Ingress 上的 kubernetes.io/ingress.class 注解指定的。此注解从未正式定义,但受到 Ingress 控制器的广泛支持。

Ingress 上较新的 ingressClassName 字段取代了该注解,但并非直接等效。虽然该注解通常用于引用应实现 Ingress 的 Ingress 控制器的名称,但该字段是对 IngressClass 资源的引用,其中包含附加的 Ingress 配置,包括 Ingress 控制器的名称。

默认 IngressClass

你可以将某个 IngressClass 标记为集群的默认 IngressClass。在 IngressClass 资源上将 ingressclass.kubernetes.io/is-default-class 注解设置为 true 将确保没有指定 ingressClassName 字段的新 Ingress 将被分配此默认 IngressClass。

有一些 Ingress 控制器即使没有定义默认的 IngressClass 也能工作。例如,Ingress-NGINX 控制器可以使用 标志 --watch-ingress-without-class 进行配置。但是,建议 指定默认的 IngressClass

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
  name: nginx-example
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: k8s.io/ingress-nginx

Ingress 的类型

由单个服务支持的 Ingress

现有 Kubernetes 概念允许你暴露单个 Service(请参阅替代方案)。你也可以通过 Ingress 来实现,方法是指定一个没有规则的 默认后端

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80

如果你使用 kubectl apply -f 创建它,你应该能够查看你添加的 Ingress 的状态。

kubectl get ingress test-ingress
NAME           CLASS         HOSTS   ADDRESS         PORTS   AGE
test-ingress   external-lb   *       203.0.113.123   80      59s

其中 203.0.113.123 是 Ingress 控制器为满足此 Ingress 而分配的 IP。

简单扇出

扇出配置根据请求的 HTTP URI,将流量从单个 IP 地址路由到多个 Service。Ingress 允许你将负载均衡器数量降至最低。例如,一个像这样的设置:

ingress-fanout-diagram

图。Ingress 扇出

它将需要一个 Ingress,例如:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

当你使用 kubectl apply -f 创建 Ingress 时:

kubectl describe ingress simple-fanout-example
Name:             simple-fanout-example
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:4200 (10.8.0.90:4200)
               /bar   service2:8080 (10.8.0.91:8080)
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     22s                loadbalancer-controller  default/test

只要 Service (service1, service2) 存在,Ingress 控制器就会配置一个特定于实现的负载均衡器来满足 Ingress。完成此操作后,你可以在 Address 字段中看到负载均衡器的地址。

基于名称的虚拟主机

基于名称的虚拟主机支持将 HTTP 流量路由到相同 IP 地址上的多个主机名。

ingress-namebase-diagram

图。Ingress 基于名称的虚拟主机

以下 Ingress 指示后端负载均衡器根据 Host header 路由请求。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

如果你创建了一个 Ingress 资源,但在规则中没有定义任何主机,那么任何指向 Ingress 控制器 IP 地址的 Web 流量都可以在不需要基于名称的虚拟主机的情况下进行匹配。

例如,以下 Ingress 将请求 first.bar.com 的流量路由到 service1,将请求 second.bar.com 的流量路由到 service2,并将请求主机头不匹配 first.bar.comsecond.bar.com 的任何流量路由到 service3

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: second.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service3
            port:
              number: 80

TLS

你可以通过指定一个包含 TLS 私钥和证书的 Secret 来保护 Ingress。Ingress 资源只支持单个 TLS 端口 443,并假定在 Ingress 入口点进行 TLS 终止(到 Service 及其 Pod 的流量是明文的)。如果 Ingress 中的 TLS 配置部分指定了不同的主机,它们将根据 SNI TLS 扩展指定的主机名在同一端口上进行多路复用(前提是 Ingress 控制器支持 SNI)。TLS Secret 必须包含名为 tls.crttls.key 的键,它们包含用于 TLS 的证书和私钥。例如:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

在 Ingress 中引用此 Secret 会告诉 Ingress 控制器使用 TLS 保护从客户端到负载均衡器的通道。你需要确保你创建的 TLS Secret 来自包含 https-example.foo.com 的通用名称 (CN)(也称为完全限定域名 (FQDN))的证书。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

负载均衡

Ingress 控制器通过一些负载均衡策略设置进行引导,这些设置适用于所有 Ingress,例如负载均衡算法、后端权重方案等。更高级的负载均衡概念(例如持久会话、动态权重)尚未通过 Ingress 公开。你可以通过用于 Service 的负载均衡器来获取这些功能。

还值得注意的是,尽管健康检查没有直接通过 Ingress 公开,但在 Kubernetes 中存在并行概念,例如 readiness probes,它们允许你实现相同的最终结果。请查看特定于控制器的文档,了解它们如何处理健康检查(例如:nginxGCE)。

更新 Ingress

要更新现有 Ingress 以添加新的 Host,你可以通过编辑资源来更新它

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     35s                loadbalancer-controller  default/test
kubectl edit ingress test

这将弹出一个以 YAML 格式显示现有配置的编辑器。修改它以包含新的 Host。

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          service:
            name: service1
            port:
              number: 80
        path: /foo
        pathType: Prefix
  - host: bar.baz.com
    http:
      paths:
      - backend:
          service:
            name: service2
            port:
              number: 80
        path: /foo
        pathType: Prefix
..

保存更改后,kubectl 会更新 API 服务器中的资源,这会告诉 Ingress 控制器重新配置负载均衡器。

验证这一点

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
  bar.baz.com
               /foo   service2:80 (10.8.0.91:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     45s                loadbalancer-controller  default/test

你也可以通过对修改后的 Ingress YAML 文件调用 kubectl replace -f 来实现相同的效果。

跨可用区故障

在不同的云提供商之间,跨故障域分散流量的技术有所不同。请查阅相关 Ingress 控制器 的文档以获取详细信息。

替代方案

你可以通过多种方式暴露 Service,这些方式不直接涉及 Ingress 资源:

下一步

上次修改时间:2024 年 9 月 13 日太平洋标准时间上午 9:33:修复 markdown 文件中的一些超链接 (e6855623c7)