Kubernete:问一个非云集群的L4负载均衡方案
Kubernete: ask a L4 load balance solution for a non-cloud cluster
我在本地数据中心搭建了一个Kubernete集群。有 4 个节点和 1 个主节点。
寻找内部服务的L4负载均衡解决方案。
root@niubi01:/home/mesos# kubectl get nodes
NAME STATUS AGE
niubi01 Ready,master 7d
niubi02 Ready 7d
niubi03 Ready 7d
niubi04 Ready 7d
niubi05 Ready 7d
假设我们有三个 Pods 和 'hello world' 网络服务。使用 'NodePort' 创建具有公开外部 IP 的服务。外网IP为'Nodes',端口为30145.
root@niubi01:/home/mesos# kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-service 10.100.220.21 <nodes> 8080:30145/TCP 6d
如文档所述,我们可以访问任何节点IP来访问此'hello world'服务。喜欢:
curl http://niubi01:30145
curl http://niubi02:30145
curl http://niubi03:30145
curl http://niubi04:30145
curl http://niubi05:30145
从外面。
问题是我们不能保证任何节点永远处于活动状态,即使是主节点。 URL 应该取用哪个?
如何做一个像Haproxy这样的LoadBalance来为这个服务提供高可用?
我们是否应该让另一台服务器在这 5 个地址之间提供负载平衡服务?寻求更好的解决方案。
独立于您的 LoadBalancer
所在的位置,您可以在您的节点之间建立一个虚拟 IP 地址负载平衡,并将其包含在您的服务定义中,如图 in the documentation:
---
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
一旦此 IP (80.11.12.10
) 的流量到达任何节点,kube-proxy
会将其重定向到您的服务。
如许多 blog posts 中所述,实现此目的的一个选项是在节点上使用 Pacemaker。但是在集群前面有一个专用的负载平衡器也可以正常工作。
使用虚拟 IP 的好处是您不必在防火墙或相关配置中弄乱 NodePorts。另一个好处是这不仅限于 HTTP 流量。
缺点是外部负载均衡器的配置和服务的 IP 分配不是自动的,必须手动完成。要缓解此问题,您可以实施自己的提供程序(请参阅其他 provider implementations on Github),或者您可以从 etcd 读取服务配置并将其用作外部负载均衡器配置的来源。
正如您已经注意到的那样,您必须设置一个自定义负载均衡器才能完成这项工作。此负载均衡器必须在您的集群外部并由您自己配置。
我建议您通读 Ingress
and ingress-controller
. Especially the nginx-ingress-controller 的概念在这里非常有用。
优点是您只需设置一次自定义外部负载均衡器,而不用为您想要公开的所有服务设置。您的负载平衡器应该平衡到入口控制器的流量,然后它将根据提供的 Ingress
资源进行内部负载平衡。
要部署入口控制器,执行以下操作就足够了:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/default-backend.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/nginx-ingress-controller.yaml
第一行创建一个 default-backend
用于所有不匹配的入口。它基本上只是 returns 404
第二行创建一个Deployment
,默认有1个副本。在生产环境中,您可能希望通过扩展部署或使用 nginx-ingress-controller.yaml
文件的本地修改副本来更改副本计数。此外,我建议为 ingress-controller 使用专用节点(通过使用 DaemonSet+NodeAffinity+Taints+Tolerations),以防您预计会有大量流量。
ingress-controller 现在可以在不暴露的情况下运行。我假设公开控制器不是示例的一部分,因为这取决于所使用的基础设施而变化太大。在您的情况下,您应该创建一个 Kubernetes Service
,通过部署此资源将 ingress-controller 公开为 NodePort
:
apiVersion: v1
kind: Service
metadata:
name: nginx-ingres-controller-svc
labels:
name: nginx-ingres-controller-svc
namespace: kube-system
spec:
type: NodePort
ports:
- port: 80
nodePort: 30080
name: http
- port: 443
nodePort: 30443
name: https
selector:
k8s-app: nginx-ingress-controller
请注意,此处明确指定了 nodePort
。这让您在配置外部负载均衡器时更轻松。
毕竟这是 set-up,您可以创建 Ingress
资源以将外部流量引导至您的内部服务。例如:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: example.company.org
http:
paths:
- path: /
backend:
serviceName: example-service
servicePort: 8080
如果您的数据中心 DNS 设置为将 example.company.org
解析到外部负载均衡器,调用它会直接将您带到 example-service
所有这一切听起来可能比仅使用 NodePort 并为新服务更改外部负载均衡器的配置更复杂。但是如果是set-up一次,配置和自动化就简化了很多。它还提供了大量新功能,否则必须手动实现。例如,nginx-ingress-controller 通过简单地向 Ingress
资源添加注释来原生支持基本身份验证。当与 kube-lego
结合使用时,它还支持 letsencrypt。如开头所述,您应该阅读有关 ingress 的文档以了解它免费带来的内容。
如果 LB 是外部的,那么您需要某种 keepalive/probe 来确定哪些节点应该接收流量。
循环设计无法实现这一点,因为您只是每 1/n 次将流量发送到黑洞。
您还应该考虑以动态方式添加新节点以防集群增长。在这种情况下,您可能需要使用 kubernetes 运算符。
Netris/Metallb.
提供了预构建和随时可用的选项来执行此操作
我们最近写了一篇文章来解释这种 design/implementation 在这里:https://www.netris.ai/cloud-like-load-balancer/
我在本地数据中心搭建了一个Kubernete集群。有 4 个节点和 1 个主节点。 寻找内部服务的L4负载均衡解决方案。
root@niubi01:/home/mesos# kubectl get nodes
NAME STATUS AGE
niubi01 Ready,master 7d
niubi02 Ready 7d
niubi03 Ready 7d
niubi04 Ready 7d
niubi05 Ready 7d
假设我们有三个 Pods 和 'hello world' 网络服务。使用 'NodePort' 创建具有公开外部 IP 的服务。外网IP为'Nodes',端口为30145.
root@niubi01:/home/mesos# kubectl get service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example-service 10.100.220.21 <nodes> 8080:30145/TCP 6d
如文档所述,我们可以访问任何节点IP来访问此'hello world'服务。喜欢:
curl http://niubi01:30145
curl http://niubi02:30145
curl http://niubi03:30145
curl http://niubi04:30145
curl http://niubi05:30145
从外面。 问题是我们不能保证任何节点永远处于活动状态,即使是主节点。 URL 应该取用哪个? 如何做一个像Haproxy这样的LoadBalance来为这个服务提供高可用? 我们是否应该让另一台服务器在这 5 个地址之间提供负载平衡服务?寻求更好的解决方案。
独立于您的 LoadBalancer
所在的位置,您可以在您的节点之间建立一个虚拟 IP 地址负载平衡,并将其包含在您的服务定义中,如图 in the documentation:
---
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
一旦此 IP (80.11.12.10
) 的流量到达任何节点,kube-proxy
会将其重定向到您的服务。
如许多 blog posts 中所述,实现此目的的一个选项是在节点上使用 Pacemaker。但是在集群前面有一个专用的负载平衡器也可以正常工作。
使用虚拟 IP 的好处是您不必在防火墙或相关配置中弄乱 NodePorts。另一个好处是这不仅限于 HTTP 流量。
缺点是外部负载均衡器的配置和服务的 IP 分配不是自动的,必须手动完成。要缓解此问题,您可以实施自己的提供程序(请参阅其他 provider implementations on Github),或者您可以从 etcd 读取服务配置并将其用作外部负载均衡器配置的来源。
正如您已经注意到的那样,您必须设置一个自定义负载均衡器才能完成这项工作。此负载均衡器必须在您的集群外部并由您自己配置。
我建议您通读 Ingress
and ingress-controller
. Especially the nginx-ingress-controller 的概念在这里非常有用。
优点是您只需设置一次自定义外部负载均衡器,而不用为您想要公开的所有服务设置。您的负载平衡器应该平衡到入口控制器的流量,然后它将根据提供的 Ingress
资源进行内部负载平衡。
要部署入口控制器,执行以下操作就足够了:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/default-backend.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/nginx-ingress-controller.yaml
第一行创建一个 default-backend
用于所有不匹配的入口。它基本上只是 returns 404
第二行创建一个Deployment
,默认有1个副本。在生产环境中,您可能希望通过扩展部署或使用 nginx-ingress-controller.yaml
文件的本地修改副本来更改副本计数。此外,我建议为 ingress-controller 使用专用节点(通过使用 DaemonSet+NodeAffinity+Taints+Tolerations),以防您预计会有大量流量。
ingress-controller 现在可以在不暴露的情况下运行。我假设公开控制器不是示例的一部分,因为这取决于所使用的基础设施而变化太大。在您的情况下,您应该创建一个 Kubernetes Service
,通过部署此资源将 ingress-controller 公开为 NodePort
:
apiVersion: v1
kind: Service
metadata:
name: nginx-ingres-controller-svc
labels:
name: nginx-ingres-controller-svc
namespace: kube-system
spec:
type: NodePort
ports:
- port: 80
nodePort: 30080
name: http
- port: 443
nodePort: 30443
name: https
selector:
k8s-app: nginx-ingress-controller
请注意,此处明确指定了 nodePort
。这让您在配置外部负载均衡器时更轻松。
毕竟这是 set-up,您可以创建 Ingress
资源以将外部流量引导至您的内部服务。例如:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- host: example.company.org
http:
paths:
- path: /
backend:
serviceName: example-service
servicePort: 8080
如果您的数据中心 DNS 设置为将 example.company.org
解析到外部负载均衡器,调用它会直接将您带到 example-service
所有这一切听起来可能比仅使用 NodePort 并为新服务更改外部负载均衡器的配置更复杂。但是如果是set-up一次,配置和自动化就简化了很多。它还提供了大量新功能,否则必须手动实现。例如,nginx-ingress-controller 通过简单地向 Ingress
资源添加注释来原生支持基本身份验证。当与 kube-lego
结合使用时,它还支持 letsencrypt。如开头所述,您应该阅读有关 ingress 的文档以了解它免费带来的内容。
如果 LB 是外部的,那么您需要某种 keepalive/probe 来确定哪些节点应该接收流量。
循环设计无法实现这一点,因为您只是每 1/n 次将流量发送到黑洞。
您还应该考虑以动态方式添加新节点以防集群增长。在这种情况下,您可能需要使用 kubernetes 运算符。
Netris/Metallb.
提供了预构建和随时可用的选项来执行此操作我们最近写了一篇文章来解释这种 design/implementation 在这里:https://www.netris.ai/cloud-like-load-balancer/