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/