Ingress
Kubernetes v1.19 [stable]
一个 API 对象,用于管理集群中服务的外部访问,通常是 HTTP。
Ingress 可以提供负载均衡、SSL 终止和基于名称的虚拟主机。
注意
Ingress 已冻结。新功能正在添加到 Gateway API 中。术语
为清楚起见,本指南定义以下术语
- 节点:Kubernetes 中的工作机器,集群的一部分。
- 集群:一组运行由 Kubernetes 管理的容器化应用程序的节点。在此示例中,以及在大多数常见的 Kubernetes 部署中,集群中的节点不属于公共互联网。
- 边缘路由器:为集群实施防火墙策略的路由器。这可以是云提供商管理的网关,也可以是物理硬件。
- 集群网络:根据 Kubernetes 网络模型 促进集群内部通信的一组逻辑或物理链路。
- Service:一个 Kubernetes Service,它使用 标签 选择器识别一组 Pod。除非另有说明,否则假定 Service 具有仅在集群网络内可路由的虚拟 IP。
什么是 Ingress?
Ingress 将集群外部的 HTTP 和 HTTPS 路由公开到集群内部的服务。流量路由由 Ingress 资源上定义的规则控制。
这里有一个简单的例子,一个 Ingress 将所有流量发送到一个 Service
图:Ingress
Ingress 可以配置为向 Service 提供外部可访问的 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
也能工作。例如,Ingress-NGINX 控制器可以通过一个 标志 --watch-ingress-without-class
进行配置。但是,建议 指定默认的 IngressClass
,如下所示。
Ingress 规则
每个 HTTP 规则包含以下信息:
- 一个可选的主机。在此示例中,未指定主机,因此该规则适用于通过指定 IP 地址的所有入站 HTTP 流量。如果提供了主机(例如,foo.bar.com),则规则适用于该主机。
- 路径列表(例如,
/testpath
),每个路径都有一个关联的后端,该后端通过service.name
和service.port.name
或service.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
,也可以将其视为与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 [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。
注意
如果你的集群中有多个 IngressClass 被标记为默认,准入控制器将阻止创建未指定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。
注意
Ingress 控制器和负载均衡器可能需要一两分钟才能分配 IP 地址。在此之前,你通常会看到地址显示为<pending>
。简单扇出
扇出配置根据请求的 HTTP URI,将流量从单个 IP 地址路由到多个 Service。Ingress 允许你将负载均衡器数量降至最低。例如,一个像这样的设置:
图。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 基于名称的虚拟主机
以下 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.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,并假定在 Ingress 入口点进行 TLS 终止(到 Service 及其 Pod 的流量是明文的)。如果 Ingress 中的 TLS 配置部分指定了不同的主机,它们将根据 SNI TLS 扩展指定的主机名在同一端口上进行多路复用(前提是 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 来自包含 https-example.foo.com
的通用名称 (CN)(也称为完全限定域名 (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 中存在并行概念,例如 readiness probes,它们允许你实现相同的最终结果。请查看特定于控制器的文档,了解它们如何处理健康检查(例如:nginx 或 GCE)。
更新 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 资源: