Ingress
Kubernetes v1.19 [稳定]
一种 API 对象,用于管理对集群中服务的外部访问,通常是 HTTP。
Ingress 可以提供负载均衡、SSL 终止和基于名称的虚拟主机。
注意
Ingress 已冻结。新特性正在添加到 网关 API 中。术语
为了清楚起见,本指南定义了以下术语
- 节点:Kubernetes 中的一台工作机器,是集群的一部分。
- 集群:一组运行由 Kubernetes 管理的容器化应用程序的节点。在本例中以及在最常见的 Kubernetes 部署中,集群中的节点不属于公共互联网的一部分。
- 边缘路由器:强制执行集群防火墙策略的路由器。这可以是由云提供商管理的网关,也可以是物理硬件。
- 集群网络:一组逻辑或物理链接,根据 Kubernetes 网络模型,促进集群内的通信。
- 服务:Kubernetes 服务,使用 标签 选择器标识一组 Pod。除非另有说明,否则假定服务只有在集群网络内可路由的虚拟 IP。
什么是 Ingress?
Ingress 将 HTTP 和 HTTPS 路由从集群外部公开到集群内的 服务。流量路由由 Ingress 资源上定义的规则控制。
下面是一个简单的示例,其中 Ingress 将其所有流量发送到一个服务
可以将 Ingress 配置为向服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,并提供基于名称的虚拟主机。Ingress 控制器 负责实现 Ingress,通常使用负载均衡器,但它也可以配置您的边缘路由器或其他前端来帮助处理流量。
Ingress 不会公开任意端口或协议。将 HTTP 和 HTTPS 以外的服务公开到互联网通常使用类型为 Service.Type=NodePort 或 Service.Type=LoadBalancer 的服务。
先决条件
您必须有一个 Ingress 控制器 来满足 Ingress。仅创建 Ingress 资源没有任何效果。
您可能需要部署 Ingress 控制器,例如 ingress-nginx。您可以从许多 Ingress 控制器 中进行选择。
理想情况下,所有 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 需要 apiVersion
、kind
、metadata
和 spec
字段。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.name
和service.port.name
或service.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
,也可以将其视为与Prefix
或Exact
路径类型相同。Exact
:完全匹配 URL 路径,并区分大小写。Prefix
:基于 URL 路径前缀(由/
分隔)进行匹配。匹配区分大小写,并逐个路径元素进行。路径元素是指由/
分隔符分隔的路径中的标签列表。如果请求路径 p 的每个元素都是路径 p 的元素级前缀,则该请求与路径 p 匹配。注意
如果路径的最后一个元素是请求路径中最后一个元素的子字符串,则不匹配(例如:/foo/bar
匹配/foo/bar/baz
,但不匹配/foo/barbaz
)。
示例
类型 | 路径 | 请求路径 | 是否匹配? |
---|---|---|---|
前缀 | / | (所有路径) | 是 |
精确匹配 | /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.com | bar.foo.com | 基于共享后缀匹配 |
*.foo.com | baz.bar.foo.com | 不匹配,通配符仅涵盖单个 DNS 标签 |
*.foo.com | foo.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。
注意
如果您的集群中有多个 IngressClass 标记为默认值,则准入控制器会阻止创建未指定ingressClassName
的新 Ingress 对象。您可以通过确保集群中最多只有一个 IngressClass 标记为默认值来解决此问题。有些 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。
注意
Ingress 控制器和负载均衡器可能需要一两分钟才能分配 IP 地址。在那之前,您经常会看到地址列为<pending>
。简单扇出
扇出配置根据请求的 HTTP URI 将流量从单个 IP 地址路由到多个 Service。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 的特定于实现的负载均衡器。完成后,您可以在“地址”字段中看到负载均衡器的地址。
基于名称的虚拟主机
基于名称的虚拟主机支持将 HTTP 流量路由到同一 IP 地址上的多个主机名。
以下 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.com
和 second.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.crt
和 tls.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)。
注意
请记住,TLS 在默认规则上不起作用,因为证书必须为所有可能的子域颁发。因此,tls
部分中的 hosts
需要与 rules
部分中的 host
显式匹配。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 中也存在并行概念,例如 就绪探针,它们可以让您实现相同的最终结果。请查看控制器特定文档,以了解它们如何处理健康检查(例如:nginx 或 GCE)。
更新 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 资源