不知道你是否注意到一个奇怪的现象,尽管Kubernetes Ingress API仍然处于beta状态,但是已经有许多公司使用它来暴露Kubernetes服务。从事相关项目的工程师表示,Kubernetes Ingress API越来越有可能摘下其beta标签。实际上,Kubernetes Ingress API处于beta状态已经持续了几年的时间,准确来说,是在2015年秋季开始进入该阶段的。但是,漫长的beta阶段可以让Kubernetes贡献者有时间来完善规范并使其与已经搭建好的实施软件(HAProxy、NGINX、Traefik等)保持一致,从而使API标准化以反映最常见并且有需求的功能。
随着该功能GA的临近,那么现在应该是一个合适的时机可以帮助新手快速了解Ingress的工作方式。简而言之,Ingress是一个规则,可以绘制出在集群内部的服务如何弥合鸿沟,暴露到客户可以使用它的外部世界。同时,称为Ingress controller的代理在集群网络的边缘进行侦听(监视要添加的规则),并将每个服务映射到特定的URL路径或域名以供公众使用。在Kubernetes维护者开发API的同时,其他开源项目也实现了Ingress Controller并为其代理添加了自己的独特功能。
在本文中,我将介绍这些概念,并帮助你了解Ingress模式背后的驱动力。
路由问题在Kubernetes中创建Pod时,需要为其分配selector标签,如Deployment manifest的以下片段所示:
该Deployment创建了运行Docker镜像my-app的三个副本,并为其分配app=foo标签。除了直接访问Pod,通常将它们分组在Service下,这使它们可以在单个集群IP地址上使用(但是只能在同一集群中使用)。Service充当抽象层,隐藏了pod的周期短暂特性,可以随时增加或减少或替换它们。它还可以执行基本的循环负载均衡。
例如,以下Service定义收集所有带有selector标签app = foo的Pod,并在其中平均路由流量。
但是,只能从集群内部以及运行在附近的其他Pod访问此服务。Kubernetes Operator正在努力解决如何为集群外部的客户端提供访问权限。该问题在早期就已经出现,并且将两种机制直接集成到Service规范中进行处理。编写service manifest时,包括一个名为type的字段,该字段的值为NodePort或LoadBalancer。这是一个将类型设置为NodePort的示例:
NodePort类型的服务使用起来很简单。本质上,这些服务希望Kubernetes API为他们分配一个随机的TCP端口,并将其暴露到集群之外。这样做的方便之处在于,客户端可以使用该端口将集群中的任何节点作为目标,并且他们的消息将被中转到正确的位置。这就类似于你可以拨打美国境内的任何电话,而接听电话的人都会确保为你转接到合适的人。
缺点在于,该端口的值必须介于30000到32767之间,虽然这个范围安全地避开了常用端口地范围,但是与常见的HTTP端口80和HTTPS 443相比,该端口显然不是很标准。此外,随机性本身也是一个障碍,因为它意味着你事先不知道值是什么,这使得配置NAT、防火墙规则更具挑战性——尤其是需要为每项服务设置不同的随机端口。
另一个选项是将类型设置为LoadBalancer。但是,这有一些前提条件——仅当你在GKE或EKS之类的云托管环境中运行并且可以使用该云供应商的负载均衡器技术时,它才有效,因为它是自动选择并配置的。其缺点是比较昂贵,因为使用这种类型的服务会为每个服务启动一个托管的负载均衡器以及一个新的公共IP地址,这会产生额外的费用。
Ingress路由分配一个随机端口或外部负载均衡器是很容易操作的,但也带来了独特的挑战。定义许多NodePort服务会造成随机端口混乱,而定义许多负载均衡器服务会导致需要支付比实际所需更多的云资源费用。这些情况不可能完全避免,但也许可以减少它的使用范围,甚至你只需要分配1个随机端口或1个负载均衡器就能够暴露许多内部服务。因此,这一平台需要一个新的抽象层,该层可以在入口点(entrypoint)后面整合许多服务。
那时,Kubernetes API引入了一种称为Ingress的新型manifest,它为路由问题提供了新的思路。它的工作方式是这样的:你编写一个Ingress manifest,声明你希望客户端如何路由到服务。manifest实际上并不自行执行任何操作,你必须将Ingress Controller部署到你的集群中,以监视这些声明并对其执行操作。