Kubernetes NodePort 在负载均衡时表现奇怪

29次阅读
没有评论

问题描述

在使用 Kubernetes 的 NodePort 服务时,遇到了一个问题。他在集群中有两个节点:Controller 和 Worker。他创建了一个 Deployment,在集群中创建了两个 Pod。具体来说,Pod1 部署在 Controller 节点上,Pod2 部署在 Worker 节点上。然后,他创建了一个 NodePort 服务,希望能以某种特定的方式路由流量。他希望:
– 50% 的请求由 Pod1 处理
– 50% 的请求由 Pod2 处理

但不幸的是,实际情况并非如此。当用户请求资源并持续请求(刷新页面)时,Pod1(在这个例子中)一直在处理请求。然后,当用户停止请求一段时间(例如1分钟)后,再次请求资源时,Pod2 开始回应请求(并且在持续刷新时,Pod2 仍然在处理请求)。

用户想知道这是否是正确的行为,以及如何使 NodePort 在这种情况下实现真正的50/50负载均衡。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

Kubernetes 的 NodePort 服务默认使用轮询算法(Round Robin)来进行负载均衡。但是,由于 Pod1 和 Pod2 部署在不同的节点上,可能会导致某个节点上的 Pod 处理更多的请求。

要实现真正的50/50负载均衡,可以考虑使用其他负载均衡算法,例如 IPVS 或 Nginx Ingress Controller。

使用 IPVS

IPVS(IP Virtual Server)是一个 Linux 内核模块,可以提供高性能的负载均衡功能。要在 Kubernetes 中使用 IPVS,可以按照以下步骤进行操作:

  1. 安装和配置 IPVS。具体步骤可以参考官方文档或其他资源。
  2. 创建一个 Service,并将其类型设置为 LoadBalancer。例如,可以使用以下命令创建一个 Service:
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  1. 部署应用程序,并将其标记为 my-app。例如,可以使用以下命令部署一个应用程序:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: my-app-image
          ports:
            - containerPort: 8080
  1. 等待 Service 的外部 IP 地址分配完成。可以使用以下命令检查 Service 的状态:
kubectl get services my-service
  1. 使用分配的外部 IP 地址访问应用程序。根据 IPVS 的负载均衡算法,请求将在 Pod 之间进行均衡分发。

使用 Nginx Ingress Controller

Nginx Ingress Controller 是一个基于 Nginx 的 Kubernetes Ingress 控制器,可以提供高级的负载均衡和路由功能。要在 Kubernetes 中使用 Nginx Ingress Controller,可以按照以下步骤进行操作:

  1. 安装和配置 Nginx Ingress Controller。具体步骤可以参考官方文档或其他资源。
  2. 创建一个 Ingress,并将其配置为使用 Nginx Ingress Controller。例如,可以使用以下命令创建一个 Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: my-app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 80
  1. 部署应用程序,并将其标记为 my-app。例如,可以使用以下命令部署一个应用程序:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: my-app-image
          ports:
            - containerPort: 8080
  1. 根据 Ingress 的配置,将域名解析到 Ingress Controller 的外部 IP 地址。
  2. 使用配置的域名访问应用程序。根据 Nginx Ingress Controller 的负载均衡算法,请求将在 Pod 之间进行均衡分发。

方案2

如果你不想使用额外的负载均衡器,也可以考虑将 Pod1 和 Pod2 部署在同一个节点上。这样,NodePort 服务将能够实现真正的50/50负载均衡。你可以按照以下步骤进行操作:

  1. 将 Pod1 和 Pod2 的亲和性设置为同一个节点。可以使用以下命令将 Pod1 和 Pod2 部署在同一个节点上:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - my-app
              topologyKey: "kubernetes.io/hostname"
      containers:
        - name: my-app
          image: my-app-image
          ports:
            - containerPort: 8080
  1. 部署应用程序,并将其标记为 my-app。Pod1 和 Pod2 将被调度到同一个节点上,从而实现真正的50/50负载均衡。

请注意,方案2 可能会导致节点上的资源不均衡。如果你的集群中有多个节点,并且希望在所有节点上均衡分发流量,建议使用方案1 中的 IPVS 或 Nginx Ingress Controller。

总结

在使用 Kubernetes 的 NodePort 服务时,要实现真正的50/50负载均衡,可以考虑使用 IPVS 或 Nginx Ingress Controller。另外,将 Pod1 和 Pod2 部署在同一个节点上也可以实现50/50负载均衡,但可能导致节点资源不均衡。根据你的需求和集群配置,选择适合的解决方案。

正文完