Ingress
Kubernetes v1.19 [稳定]
一个管理对集群中服务(通常为 HTTP)的外部访问的 API 对象。
Ingress 可以提供负载均衡、SSL 终止和基于名称的虚拟主机。
注意
Ingress 已冻结。新功能正在添加到 Gateway 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 spec 包含配置负载均衡器或代理服务器所需的所有信息。最重要的是,它包含一个与所有传入请求匹配的规则列表。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
定义。主机和路径都必须与传入请求的内容匹配,然后负载均衡器才能将流量定向到引用的服务。 - 后端是服务和端口名称的组合,如 服务文档 中所述,或通过 CRD 的 自定义资源后端。与 Ingress 的主机和路径匹配的 HTTP(和 HTTPS)请求将发送到列出的后端。
defaultBackend
通常在 Ingress 控制器中配置,以服务任何与规范中的路径不匹配的请求。
DefaultBackend
没有规则的 Ingress 将所有流量发送到单个默认后端,并且 .spec.defaultBackend
是在这种情况下应该处理请求的后端。defaultBackend
通常是 Ingress 控制器 的配置选项,并且未在您的 Ingress 资源中指定。如果未指定 .spec.rules
,则必须指定 .spec.defaultBackend
。如果未设置 defaultBackend
,则处理与任何规则都不匹配的请求将由 Ingress 控制器决定(请查阅 Ingress 控制器的文档,了解它如何处理这种情况)。
如果 Ingress 对象中的任何主机或路径都不匹配 HTTP 请求,则流量将路由到您的默认后端。
资源后端
资源
后端是对与 Ingress 对象位于同一命名空间中的另一个 Kubernetes 资源的 ObjectRef。资源
是与服务互斥的设置,如果两者都指定,则验证将失败。资源
后端的一个常见用途是将数据导入到具有静态资产的对象存储后端。
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
)。
示例
种类 | 路径(s) | 请求路径(s) | 匹配? |
---|---|---|---|
Prefix | / | (所有路径) | 是 |
Exact | /foo | /foo | 是 |
Exact | /foo | /bar | 否 |
Exact | /foo | /foo/ | 否 |
Exact | /foo/ | /foo | 否 |
Prefix | /foo | /foo 、/foo/ | 是 |
Prefix | /foo/ | /foo 、/foo/ | 是 |
Prefix | /aaa/bb | /aaa/bbb | 否 |
Prefix | /aaa/bbb | /aaa/bbb | 是 |
Prefix | /aaa/bbb/ | /aaa/bbb | 是,忽略尾部斜杠 |
Prefix | /aaa/bbb | /aaa/bbb/ | 是,匹配尾部斜杠 |
Prefix | /aaa/bbb | /aaa/bbb/ccc | 是,匹配子路径 |
Prefix | /aaa/bbb | /aaa/bbbxyz | 否,不匹配字符串前缀 |
Prefix | / 、/aaa | /aaa/ccc | 是的,匹配 /aaa 前缀 |
Prefix | / ,/aaa ,/aaa/bbb | /aaa/bbb | 是的,匹配 /aaa/bbb 前缀 |
Prefix | / ,/aaa ,/aaa/bbb | /ccc | 是的,匹配 / 前缀 |
Prefix | /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
将确保没有指定 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 概念允许您公开单个服务(参见 备选方案)。您也可以通过指定没有规则的默认后端来使用 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 地址的流量路由到多个服务。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
Ingress 控制器将配置一个实现特定的负载均衡器,该负载均衡器满足 Ingress,只要服务(service1
,service2
)存在。完成后,您可以在地址字段中看到负载均衡器的地址。
基于名称的虚拟主机
基于名称的虚拟主机支持将 HTTP 流量路由到同一 IP 地址上的多个主机名。
以下 Ingress 告诉后端负载均衡器根据 主机头 路由请求。
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 地址的网络流量都可以匹配,而无需基于名称的虚拟主机。
例如,以下 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 私钥和证书的 秘密 来保护 Ingress。Ingress 资源只支持单个 TLS 端口 443,并假设在 ingress 点进行 TLS 终止(到服务及其 Pod 的流量是明文的)。如果 Ingress 中的 TLS 配置部分指定了不同的主机,则它们将在同一端口上进行多路复用,根据 SNI TLS 扩展中指定的主机名(前提是 Ingress 控制器支持 SNI)。TLS 秘密必须包含名为 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 中引用此秘密告诉 Ingress 控制器使用 TLS 保护从客户端到负载均衡器的通道。您需要确保您创建的 TLS 秘密来自包含通用名称 (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 公开。您可以通过用于服务的负载均衡器获得这些功能。
还值得注意的是,即使健康检查没有通过 Ingress 直接公开,Kubernetes 中也存在并行的概念,例如 就绪探测,可以让您实现相同的结果。请查看控制器特定文档,了解它们如何处理健康检查(例如: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 控制器 的文档。
替代方案
您可以通过多种不直接涉及 Ingress 资源的方式公开服务