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 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)请求将发送到列出的后端。
通常在 Ingress 控制器中配置 defaultBackend
,以服务于与 spec 中的路径不匹配的任何请求。
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
)。
示例
类型 | 路径 | 请求路径 | 匹配? |
---|---|---|---|
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 (Prefix), /foo (Exact) | /foo | 是,优先选择 Exact |
多个匹配
在某些情况下,Ingress 中的多个路径会匹配一个请求。在这些情况下,将首先优先考虑最长匹配的路径。如果两个路径仍然匹配相等,则将优先考虑具有精确路径类型而不是前缀路径类型的路径。
主机名通配符
主机可以是精确匹配(例如“foo.bar.com
”)或通配符(例如“*.foo.com
”)。精确匹配要求 HTTP host
标头与 host
字段匹配。通配符匹配要求 HTTP host
标头等于通配符规则的后缀。
主机 | 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 对象。你可以通过确保在你的集群中最多将 1 个 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 的类型
由单个 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
Ingress 控制器会配置一个特定于实现的负载均衡器,只要 Services(service1
, service2
)存在,就可以满足 Ingress。当它完成此操作后,你可以在 Address 字段中看到负载均衡器的地址。
基于名称的虚拟主机
基于名称的虚拟主机支持将 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 地址的网络流量都可以在不需要基于名称的虚拟主机的情况下进行匹配。
例如,以下 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 扩展指定的主机名在同一端口上进行多路复用(前提是 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 中也存在并行概念,例如 就绪探针,可以让您实现相同的最终结果。请查看控制器特定的文档,以了解它们如何处理运行状况检查(例如: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 控制器 的文档以了解详细信息。
替代方案
您可以通过多种不直接涉及 Ingress 资源的方式公开 Service