问题描述
在我们的开发Kubernetes集群中(托管在EKS中),工程师们会推送功能分支,每个功能分支会在自己的隔离命名空间中创建相同的部署(Deployments)和服务(Services)。我们使用nginx ingress进行动态负载均衡,允许我们根据功能分支名称按需创建主机名,并在端口80和/或443上一致地公开HTTP服务。这会创建一个单独的ELB(Elastic Load Balancer),并可以进行基于主机名的路由。
然而,我们还有一些非HTTP服务,希望能够在所有命名空间中一致地公开一个端口,比如说端口4000,为了举一个具体的例子。此外,我们希望为这些服务使用友好的可读性良好的主机名。
似乎可以通过ExternalDNS解决主机名的问题。然而,我找不到一种在不为每个命名空间额外增加负载均衡器的情况下一致地公开端口4000的方法。换句话说,如果我有100个命名空间,就会有100个负载均衡器。
我觉得自己对网络有足够的理解,这似乎只是一个困难的限制,我希望能被证明是错误的。我正在处理的协议不会发送所请求的主机名,因此我必须为每个服务分配唯一的IP地址(假设端口不能更改)。我猜我正在寻找的是,是否有更经济高效的方法来做到这一点,因为增加负载均衡器的成本是不可接受的。
在任何人建议在命名空间之间使用不同端口之前,我想说是的,这确实可以解决问题,但这会使开发体验更加繁琐,所以我想避免这种方法。另外,kubectl port-forward
是可行的,这是我们一直在使用的,我正在调查是否可以改进这一点,以便工程师在部署命名空间后可以立即访问服务,而无需先运行任何额外的命令。
最后,一些额外的背景信息,我实际上并不需要负载均衡。这是一个开发集群,每个服务资源永远只会解析到一个单独的Pod。我不知道这是否提供了任何独特的解决方法。
解决方案
最佳解决方案
在开发Kubernetes集群中跨命名空间一致地公开端口,并使用友好的人类可读主机名,可以通过以下方式实现:
-
使用ServiceType: NodePort:为每个命名空间中的服务定义Service资源,并将其ServiceType设置为NodePort。这将在每个节点上打开一个特定的端口,以便可以直接访问服务。
-
使用Ingress:虽然您提到了不希望为每个命名空间都创建负载均衡器,但您可以考虑使用Ingress来实现一些定制的路由。您可以创建一个统一的Ingress控制器,然后为每个命名空间创建Ingress资源,将其指向相应的Service资源。这样,您可以在不创建新的负载均衡器的情况下实现路由。
-
使用DNS记录:为了使友好的主机名解析到正确的IP地址,您可以使用ExternalDNS来自动为每个服务创建DNS记录。这将为每个服务提供易于识别的主机名,并且不需要手动管理DNS记录。
下面是一个示例步骤,演示如何在开发Kubernetes集群中实现一致的端口公开:
- 在每个命名空间中创建一个Service资源,并将其类型设置为NodePort,例如:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: my-namespace
spec:
selector:
app: my-app
type: NodePort
ports:
- protocol: TCP
port: 4000
targetPort: 4000
- 在每个命名空间中创建一个Ingress资源,将其指向相应的Service资源,例如:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
namespace: my-namespace
spec:
rules:
- host: my-service-hostname.example.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: my-service
port:
number: 4000
- 使用ExternalDNS来为每个Ingress资源创建DNS记录,使主机名能够解析到正确的IP地址。
请注意,虽然这些方法可以实现一致的端口公开,但由于您提到了不希望创建额外的负载均衡器,所以在某些情况下可能会涉及一些资源和管理开销。根据您的需求和约束,您可以选择适合您情况的方法。