提示:
本文对 Ingress 进行基础性的介绍,更深入的细节请访问 Ingress 专题
Ingress 是提供了除 Service 之外的另一种从 Kubernetes 集群外部访问集群内部服务的解决方案。
Ingress 是 Kubernetes 集群中的一种 API 资源,只是一种资源配置,本身并不会提供服务。实际功能由 ingress-controller 提供,一般是以 hostNetwork 的方式部署运行,监听 80/443 端口,以域名的虚拟机方式对外提供7层的代理服务。常见的 ingress-controller 有 nginx-ingress-controlle 、Traefik-ingress-controller等。
通常情况下,service 和 pod 仅可在集群内部网络中通过IP地址访问。所有到达边界路由器的流量或被丢弃或被转发到其他地方。从概念上讲,可能像下面这样:
internet
|
------------
[ Services ]
Ingress是授权入站连接到达集群服务的规则集合。
internet
|
[ Ingress ]
--|-----|--
[ Services ]
你可以给 Ingress 配置提供外部可访问的 URL、负载均衡、SSL、基于名称的虚拟主机等。用户通过POST Ingress资源到 API server 的方式来请求 ingress。 Ingress controller负责实现Ingress,通常使用负载平衡器,它还可以配置边界路由和其他前端,这有助于以 HA 方式处理流量。
Ingress Spec
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: test-ingress.mydomain.com
http:
paths: /test
- backend:
serviceName: test-ingress
servicePort: 80
rules
spec.rules 定义了一个列表,每个列表项是一个包含一套相关访问规则配置。
rules.host: 定义服务的域名,和 nginx 的虚拟机主机功能类似,通过域名来区分后端的服务。rules.http: 定义路由及后端资源。rules.http.paths: 定义路由或 path,可以类比 nginx 的 Location 配置项。rules.http.paths.backend: 定义路由转发的后端服务,详见spec.backend。
backend
backend:
serviceName: test-ingress
servicePort: 80
spec.backend 定义当前 host 服务的后端。
serviceName是 Kubernetes 的 Service 资源的名称,这里只是通过 Service 名称获取到后端的 Endpoints 列表,路由请求代理时是 Ingress-controller 直接转发给 Pod,而不是转发给 Service 的 ClusterIP。servicePort: 服务端口,默认是80。该端口是由 Ingress-controller 启动参数配置的监听端口,其他未监听的端口配置是无效的。
TLS
你可以通过指定包含TLS私钥和证书的 secret 来加密 Ingress。 目前,Ingress 仅支持单个TLS端口443,并假定 TLS termination。 如果 Ingress 中的 TLS 配置部分指定了不同的主机,则它们将根据通过 SNI TLS 扩展指定的主机名(假如 Ingress controller 支持 SNI)在多个相同端口上进行复用。 TLS secret 中必须包含名为 tls.crt 和 tls.key 的密钥,这里面包含了用于 TLS 的证书和私钥,例如:
apiVersion: v1
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
kind: Secret
metadata:
name: testsecret
namespace: default
type: Opaque
在 Ingress 中引用这个 secret 将通知 Ingress controller 使用 TLS 加密从将客户端到 loadbalancer 的 channel:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: no-rules-map
spec:
tls:
- secretName: testsecret
backend:
serviceName: s1
servicePort: 80
如果配置 tls 的 Ingress 未指定具体 rules 时,这该 tls 是全局的,或者说是默认的。在有明确的 rules 时,会优先使用其ingress 中配置的 tls。
请注意,各种 Ingress controller 支持的 TLS 功能之间存在差距。 请参阅有关 nginx,GCE 或任何其他平台特 定Ingress controller 的文档,以了解 TLS 在你的环境中的工作原理。
Ingress controller 启动时附带一些适用于所有 Ingress 的负载平衡策略设置,例如负载均衡算法,后端权重方案等。更高级的负载平衡概念(例如持久会话,动态权重)尚未在 Ingress 中公开。 你仍然可以通过 service loadbalancer 获取这些功能。 随着时间的推移,我们计划将适用于跨平台的负载平衡模式加入到 Ingress 资源中。
还值得注意的是,尽管健康检查不直接通过 Ingress 公开,但 Kubernetes 中存在并行概念,例如准备探查,可以使你达成相同的最终结果。 请查看特定控制器的文档,以了解他们如何处理健康检查 (nginx,GCE)。
扩展阅读
术语
在本篇文章中你将会看到一些在其他地方被交叉使用的术语,为了防止产生歧义,我们首先来澄清下。
- 节点:Kubernetes 集群中的一台物理机或者虚拟机。
- 集群:位于 Internet 防火墙后的节点,这是 kubernetes 管理的主要计算资源。
- 边界路由器:为集群强制执行防火墙策略的路由器。 这可能是由云提供商或物理硬件管理的网关。
- 集群网络:一组逻辑或物理链接,可根据 Kubernetes网络模型实现群集内的通信。 集群网络的实现包括 Overlay 模型的 flannel 和基于SDN 的 OVS。
- 服务:使用标签选择器标识一组 pod 成为的 Kubernetes 服务。 除非另有说明,否则服务假定在集群网络内仅可通过虚拟 IP 访问。
先决条件
在使用 Ingress resource之前,有必要先了解下面几件事情。Ingress是beta版本的resource,在kubernetes1.1之前还没有。你需要一个Ingress Controller来实现Ingress,单纯的创建一个Ingress没有任何意义。
GCE/GKE会在master节点上部署一个ingress controller。你可以在一个pod中部署任意个自定义的ingress controller。你必须正确地annotate每个ingress,比如 运行多个ingress controller 和 关闭glbc。
确定你已经阅读了Ingress controller的 beta版本限制。在非GCE/GKE的环境中,你需要在pod中部署一个controller。
Ingress controllers
为了使 Ingress 正常工作,集群中必须运行 Ingress controller。 这与其他类型的控制器不同,其他类型的控制器通常作为kube-controller-manager 二进制文件的一部分运行,在集群启动时自动启动。 你需要选择最适合自己集群的Ingress controller或者自己实现一个。
- kubernetes当前支持并维护GCE和nginx两种controller.
- F5(公司)支持并维护 F5 BIG-IP Controller for Kubernetes.
- Kong 同时支持并维护社区版与企业版的 Kong Ingress Controller for Kubernetes.
- Traefik 是功能齐全的 ingress controller(Let’s Encrypt, secrets, http2, websocket…), Containous 也对其提供商业支持。
- Istio 使用CRD Gateway来控制Ingress流量。
在你开始前
以下文档描述了 Ingress 资源中公开的一组跨平台功能。 理想情况下,所有的 Ingress controller 都应该符合这个规范,但是我们还没有实现。 GCE 和 nginx 控制器的文档分别在这里和这里。如果您使用 F5 BIG-IP controller, 请参看这里. 确保您查看控制器特定的文档,以便您了解每个文档的注意事项。
跨可用域故障
在不同云供应商之间,跨故障域的流量传播技术有所不同。 有关详细信息,请查看相关 Ingress controller 的文档。 有关在federation 集群中部署 Ingress 的详细信息,请参阅 federation 文档。
未来计划
- 多样化的 HTTPS/TLS 模型支持(如SNI,re-encryption)
- 通过声明来请求 IP 或者主机名
- 结合 L4 和 L7 Ingress
- 更多的 Ingress controller
请跟踪 L7 和 Ingress 的 proposal,了解有关资源演进的更多细节,以及Ingress repository,了解有关各种 Ingress controller 演进的更多详细信息。
替代方案
你可以通过很多种方式暴露service而不必直接使用ingress:
- 使用Service.Type=LoadBalancer
- 使用Service.Type=NodePort
- 使用Port Proxy
- 部署一个Service loadbalancer 这允许你在多个service之间共享单个IP,并通过Service Annotations实现更高级的负载平衡。
基于名称的虚拟主机
Name-based的虚拟主机在同一个IP地址下拥有多个主机名。
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
下面这个 ingress 说明基于 Host header的后端loadbalancer的路由请求:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: s1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: s2
servicePort: 80
默认backend:一个没有 rule 的 ingress,如前面章节中所示,所有流量都将发送到一个默认backend。你可以用该技巧通知 loadbalancer 如何找到你网站的 404 页面,通过制定一些列 rule 和一个默认 backend 的方式。如果请求 header 中的 host 不能跟 ingress 中的 host 匹配,并且/或请求的 URL 不能与任何一个 path 匹配,则流量将路由到你的默认 backend。
Ingress类型
单Service Ingress
Kubernetes 中已经存在一些概念可以暴露单个 service(查看替代方案),但是你仍然可以通过 Ingress 来实现,通过指定一个没有 rule 的默认backend的方式。
ingress.yaml定义文件:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
使用kubectl create -f命令创建,然后查看ingress:
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test-ingress - testsvc:80 107.178.254.228
107.178.254.228就是 Ingress controller 为了实现 Ingress 而分配的 IP 地址。RULE 列表示所有发送给该 IP 的流量都被转发到了 BACKEND 所列的 Kubernetes service 上。
简单展开
如前面描述的那样,kubernetes pod 中的 IP 只在集群网络内部可见,我们需要在边界设置一个东西,让它能够接收 ingress 的流量并将它们转发到正确的端点上。这个东西一般是高可用的 loadbalancer。使用 Ingress 能够允许你将 loadbalancer 的个数降低到最少,例如,假如你想要创建这样的一个设置:
foo.bar.com -> 178.91.123.132 -> / foo s1:80
/ bar s2:80
你需要一个这样的ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: s1
servicePort: 80
- path: /bar
backend:
serviceName: s2
servicePort: 80
使用kubectl create -f创建完 ingress 后:
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test -
foo.bar.com
/foo s1:80
/bar s2:80
只要服务(s1,s2)存在,Ingress controller 就会将提供一个满足该 Ingress 的特定 loadbalancer 实现。 这一步完成后,您将在 Ingress 的最后一列看到 loadbalancer 的地址。
更新Ingress
假如你想要向已有的 ingress 中增加一个新的 Host,你可以编辑和更新该 ingress:
注意: 更新 Ingress 配置不需要重启 Ingress-controller,Ingress-controller 会 watch 配置的变化自动重载配置文件。
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test - 178.91.123.132
foo.bar.com
/foo s1:80
$ kubectl edit ing test
这会弹出一个包含已有的 yaml 文件的编辑器,修改它,增加新的 Host 配置。
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: s1
servicePort: 80
path: /foo
- host: bar.baz.com
http:
paths:
- backend:
serviceName: s2
servicePort: 80
path: /foo
..
保存它会更新 API server 中的资源,这会触发 ingress controller 重新配置 loadbalancer。
$ kubectl get ing
NAME RULE BACKEND ADDRESS
test - 178.91.123.132
foo.bar.com
/foo s1:80
bar.baz.com
/foo s2:80
在一个修改过的 ingress yaml 文件上调用 kubectl replace -f 命令一样可以达到同样的效果。