在构建裸机Kubernetes集群时,您可能会遇到一个常见问题,就像我在做的那样,除了使用NodePort之外,您真的不知道如何向Internet公开Kubernetes服务。如果使用的是NodePort服务类型,它将分配一个要打开的较大端口号,并且您必须允许防火墙规则连接到这些端口。这对您的基础架构不利,尤其是在将服务器暴露于外部Internet时。好吧,还有另一种简洁的方法可以将您的Kubernetes服务公开出去,并且使用服务的原始端口号。例如,您可以将Kubernetes群集中部署的MySQL服务通过3306而不是32767端口暴露给外界。答案是使用Kubernetes External IP服务类型。
就个人而言,我发现在Kubernetes社区中并未广泛讨论此主题,这可能是因为许多人正在使用云提供商的负载均衡器或将Metal LB用于本地部署。
什么是External IP服务
从Kubernetes官方文档中可以看到External IP的描述:
如果存在路由到一个或多个集群节点的外部IP,则Kubernetes Services可以在这些External IP上公开。在服务端口上使用外部IP(作为目标IP)进入群集的流量将被路由到服务端点之一。External IP不受Kubernetes的管理,由集群管理员负责。
对于大多数人来说,这种解释是可以理解的。这里最重要的是确保使用哪个IP来访问Kubernetes集群。使用External IP服务类型,我们可以将服务绑定到用于连接集群的IP。
如果您了解Kubernetes网络的工作方式,那将是很好的。如果您不熟悉它,请查看Mark Betz撰写的博客文章,以详细了解它们。这里最重要的是要知道Kubernetes网络与Overlay网络一起工作。这意味着一旦您到达群集中的任何节点(主节点或工作节点),您就可以虚拟访问群集中的所有节点。
下图就是他们的组网图:
在上图中,节点1和节点2都有1个IP地址。节点1上的IP地址1.2.3.4绑定到实际Pod驻留在节点2中的httpd服务,而IP地址1.2.3.5绑定到实际Pod驻留在节点1中的nginx服务。底层的overlay网络使这成为可能。当我们curl 1.2.3.4时,应该看到来自httpd服务的响应,而curl 1.2.3.5时,则应该看到来自nginx服务的响应。
为什么不使用Ingress
即使Ingress也用于将服务公开给外部,但Ingress是为L7路由构建的。这意味着它构建为支持HTTP(端口80)和/或HTTPS(端口443)流量,而不支持其他端口。Ingress充当基于主机的路由,或类似于Web Server中的虚拟主机。一些能够为其他端口提供服务的ingress controllers,或者可能为L4路由提供了解决方法,但我从未真正尝试使用它们。
External IP的优缺点
使用External IP的优点是:
- 您可以完全控制所使用的IP。您可以使用属于您的ASN的IP,而不要使用云提供商的ASN。
外部IP的缺点是:
- 我们现在将要进行的简单设置并不是高可用的。这意味着,如果节点异常,则该服务将不再可用,您将需要手动修复该问题。
- 管理IP需要做一些手工工作。IP不是为您动态配置的,因此需要人工干预。
如何使用External IP服务
同样,我们将使用与我们的群集设置相同的组网图,不同的是IP地址和主机名不同。这不是一个好例子,但是当我们验证设置时,很容易区分是哪个。在实际示例中,您可能希望在一个外部IP上公开MySQL DB,在另一个外部IP上公开Kafka群集。
我已为本教程配置了2个VM。k3s-external-ip-master将是我们的Kubernetes master节点,其IP为1.2.4.120。k3s-external-ip-worker将是Kubernetes worker节点,其IP为1.2.4.114。
步骤1:部署Kubernetes集群
让我们在主节点上安装k3s,然后让另一个节点加入集群。
1 | k3sup install --ip <master node ip> --user <username> |
您现在应该会看到类似的内容:
1 | kubectl get nodes |
步骤2:创建Kubernetes Deployment资源
我们将创建nginx和httpd资源。
1 | kubectl create deployment nginx --image=nginx |
你现在应该看到这个:
1 | $ kubectl get pods |
步骤3:将Deployment公开为External IP类型
让我们创建Nginx服务的yaml:
1 | $ cat << EOF > nginx-service.yaml |
创建httpd服务的yaml:
1 | cat << EOF > httpd-service.yaml |
使用kubectl命令创建2个服务的yaml:
1 | kubectl create -f nginx-service.yaml |
现在您的Kubernetes服务应该如下所示:
1 | kubectl get svc |
您可能会在此处看到服务类型为ClusterIP。我不确定为什么它不显示“外部IP”。
k8s官网有说明,External IP与type无关
步骤4:瞧!
让我们curl httpd服务,您应该看到Apache默认页面。
1 | curl -i 1.2.4.120 |
接下来,curl nginx服务,您应该看到nginx默认页面。
1 | curl -i 1.2.4.114 |
下一步是什么
浮动IP
如今,大多数云提供商都提供浮动IP服务。浮动IP允许您拥有1个IP,并将该IP动态分配给所需的任何IP。在这种情况下,可以将IP分配给Kubernetes集群中的任何工作节点。
在DigitalOcean(我相信其他提供商也允许这样做)中,您可以使用API调用将IP重新分配给其他VM。这意味着您可以在其他VM发生故障时迅速将其主动重新分配给其他VM,或者可以定期轮换IP。
从图中可以看到,我们有1个浮动IP 1.2.3.6,该IP首先分配给节点1,当节点1不可用时将切换到节点2。IP 1.2.3.6适用于我们的MySQL服务,并将放入我们的应用程序配置中。
我尚未尝试此设置,因此无法确认它是否有效。我将在以后的博客文章中更新结果。
任播IP
您可以将Anycast IP用作外部IP,以便它们具有高可用性。对于不熟悉Anycast IP的用户,这意味着1个IP可能会路由到2个或更多服务器。你可以在这里阅读更多。就个人而言,我不确定如何设置此设置。但是,我认为这在技术上是可行的。我认为这是运行外部IP服务的最佳方法。
结论
您可以通过很多选项为裸机Kubernetes集群获取IP。例如,您可以为此使用Inlets和MetalLB。此设置可能不是您的组织需要的最合适的设置。但是,很高兴知道如何使用此方法。
免责声明:我仅将其用于实验和测试,而本文不适用于生产。如果您打算在生产中使用它,请咨询您的解决方案架构师或CTO。