Ingress
Kubernetes v1.19 [stable]
一个管理集群内服务外部访问的 API 对象,通常是 HTTP。
Ingress 可以提供负载均衡、SSL 终结以及基于名称的虚拟主机。
注意
Ingress 功能已冻结。新功能正在添加到 Gateway API 中。术语
为清晰起见,本指南定义以下术语
- 节点(Node):Kubernetes 中的工作机器,是集群的一部分。
- 集群(Cluster):一组运行由 Kubernetes 管理的容器化应用的节点。在此示例中,以及在大多数常见的 Kubernetes 部署中,集群中的节点不属于公共互联网。
- 边缘路由器(Edge router):为你的集群强制执行防火墙策略的路由器。它可以是由云提供商管理的网关,也可以是物理硬件。
- 集群网络(Cluster network):一组逻辑或物理连接,根据 Kubernetes 网络模型 促进集群内的通信。
- Service(服务):一个 Kubernetes Service,它使用标签选择器识别一组 Pod。除非另有说明,否则假定 Service 仅具有在集群网络内可路由的虚拟 IP。
什么是 Ingress?
Ingress 将来自集群外部的 HTTP 和 HTTPS 路由暴露给集群内部的服务。流量路由由 Ingress 资源上定义的规则控制。
以下是一个简单示例,其中 Ingress 将所有流量发送到一个 Service
图. Ingress
Ingress 可以配置为提供外部可访问的 URL、负载均衡流量、终止 SSL / TLS,并提供基于名称的虚拟主机。一个 Ingress 控制器 负责实现 Ingress,通常通过负载均衡器,但它也可以配置你的边缘路由器或其他前端来帮助处理流量。
Ingress 不暴露任意端口或协议。将 HTTP 和 HTTPS 以外的服务暴露到互联网通常使用类型为 Service.Type=NodePort 或 Service.Type=LoadBalancer 的 Service。
前提条件
你必须拥有一个 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
进行定义。主机和路径都必须与传入请求的内容匹配,负载均衡器才会将流量导向所引用的 Service。 - 后端(backend)是 Service 和端口名称的组合,如 Service 文档中所述,或者通过CRD定义的自定义资源后端。与规则的主机和路径匹配的发送到 Ingress 的 HTTP (和 HTTPS) 请求将被发送到列出的后端。
Ingress 控制器中通常配置一个 defaultBackend
来处理任何与规约中路径不匹配的请求。
默认后端 (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 中的多个路径会匹配一个请求。在这种情况下,优先权首先给予最长匹配路径。如果两个路径仍然同样匹配,优先权将给予具有 Exact 路径类型的路径而不是 Prefix 路径类型。
主机名通配符
主机可以是精确匹配(例如 “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 [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.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 类型
单个 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>
。简单扇出 (Fanout)
扇出配置根据请求的 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 头部路由请求。
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 扩展指定的主机名在同一端口上进行多路复用(前提是 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 以添加新的 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 资源的方式暴露 Service