Ingress

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

特性状态: Kubernetes v1.19 [稳定]

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

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

术语

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

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

什么是 Ingress?

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

下面是一个简单的示例,其中 Ingress 将其所有流量发送到一个服务

ingress-diagram

图。Ingress

可以将 Ingress 配置为向服务提供外部可访问的 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 的情况下工作。例如,可以使用 标志 --watch-ingress-without-class 配置 Ingress-NGINX 控制器。不过,建议 按照 下文 所示指定默认 IngressClass

Ingress 规则

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

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

defaultBackend 通常在 Ingress 控制器中配置,以服务于与规范中的路径不匹配的任何请求。

DefaultBackend

没有规则的 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 [稳定]

如果您设置了 .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.kubernetes.io/is-default-class 注释设置为 true 将确保将此默认 IngressClass 分配给未指定 ingressClassName 字段的新 Ingress。

有些 ingress 控制器可以在没有定义默认 IngressClass 的情况下工作。例如,可以使用 标志 --watch-ingress-without-class 配置 Ingress-NGINX 控制器。但是,建议 指定默认 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 类型

由单个 Service 支持的 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(service1service2)存在,Ingress 控制器就会提供满足 Ingress 的特定于实现的负载均衡器。完成后,您可以在“地址”字段中看到负载均衡器的地址。

基于名称的虚拟主机

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

ingress-namebase-diagram

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

以下 Ingress 告诉后端负载均衡器根据 Host 标头 路由请求。

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,并假定在入口点进行 TLS 终止(到 Service 及其 Pod 的流量为明文)。如果 Ingress 中的 TLS 配置部分指定了不同的主机,则根据通过 SNI TLS 扩展指定的 hostname 在同一个端口上进行多路复用(前提是 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 来自包含通用名称 (CN) 的证书,也称为 https-example.foo.com 的完全限定域名 (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 中也存在并行概念,例如 就绪探针,它们可以让您实现相同的最终结果。请查看控制器特定文档,以了解它们如何处理健康检查(例如:nginxGCE)。

更新 Ingress

要更新现有 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)
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 格式的现有配置。修改它以包含新的主机

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 年 4 月 24 日下午 8:19 PST:删除多余的尾随空格 (9a0bda61b8)