Kubernetes集群中只有1个Pod可以处理所有请求

时间:2019-10-27 15:29:57

标签: go kubernetes load-balancing

这是minikube Kubernetes的清单文件,用于部署和服务:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 3
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: hello_hello
        imagePullPolicy: Never
        ports:
        - containerPort: 4001
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: hello
spec:
  selector:
    app: hello
  ports:
  - port: 4001
    nodePort: 30036
    protocol: TCP
  type: NodePort

还有一个用Golang编写的简单HTTP服务器

package main
import (
    http "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    server := &http.Server{
        Addr:    ":4001",
        Handler: r,
    }

    server.ListenAndServe()
}

当我向 IP:30036 / ping 发出多个请求,然后打开Pod的日志时,我看到3个Pod中只有1个可以处理所有请求。如何使其他Pod响应请求?

3 个答案:

答案 0 :(得分:2)

您正在使用NodePort公开服务,因此没有反向代理,但您直接连接到Pod。首先,这是一个不错的选择。 (稍后您可能要使用Ingress)

您看到的是只有一个Pod可以处理您的请求。您希望每个请求都负载均衡到不同的容器。并且您的假设是正确的,但是负载平衡不是在HTTP请求层上发生,而是在TCP层上发生。

因此,当您拥有持久的TCP连接并重新使用它时,将不会遇到预期的负载平衡。由于建立TCP连接的延迟相当昂贵,通常通常会进行优化以避免重复打开新的TCP连接:HTTP保持活动。

默认情况下,大多数框架和客户端中都启用了“保持活动”,Go也是如此。 尝试resource "azurerm_resource_group" "test" { name = "resourceGroup1" location = "West US 2" } resource "azurerm_eventhub_namespace" "test" { name = "acceptanceTestEventHubNamespace" location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" sku = "Standard" capacity = 1 kafka_enabled = false tags = { environment = "Production" } } resource "azurerm_eventhub" "test" { name = "acceptanceTestEventHub" namespace_name = "${azurerm_eventhub_namespace.test.name}" resource_group_name = "${azurerm_resource_group.test.name}" partition_count = 2 message_retention = 1 } resource "azurerm_eventgrid_topic" "test" { name = "my-eventgrid-topic" location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" tags = { environment = "Production" } } resource "azurerm_eventgrid_domain" "test" { name = "my-eventgrid-domain" location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" input_schema = "eventgridschema" input_mapping_fields= { topic = "my-eventgrid-topic" } tags = { environment = "Production" } } resource "azurerm_eventgrid_event_subscription" "default" { name = "defaultEventSubscription" scope = "${azurerm_resource_group.default.id}" event_delivery_schema = "EventGridSchema" topic_name = "my-eventgrid-topic" eventhub_endpoint { storage_account_id = "${azurerm_eventhub.test.id}" } } ,看看是否可以解决您的问题。 (建议仅用于测试!)

您还可以使用多个不同的客户端,例如从命令行使用curl或在Postman中禁用keep-alive。

答案 1 :(得分:2)

感谢@Thomas的深刻见解!我尝试使用请求标头,它解决了负载平衡问题,即所有请求仅命中一个副本,而对于演示或测试,能够将请求分发到所有副本非常有用

来自文档:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection 连接:保持活动状态 连接:关闭

此请求始终点击同一广告连播

curl -H "Connection: keep-alive" http://your-service:port/path

但是,使用close,请求平衡到了所有广告连播

curl -H "Connection: close" http://your-service:port/path

答案 2 :(得分:0)

在Kubernetes集群中,发送到k8s服务的请求由kube-proxy路由。

自Kubernetes v1.2起,默认的kube-proxy模式为Iptalbles,它可以在服务和后端Pod之间实现更快的数据包解析。后端Pod之间的负载平衡是通过iptables rules直接完成的。

也许您没有生成一个Pod无法处理的足够负载,这就是为什么您从kube-proxy被路由到同一Pod的原因。

您还可以看到有关实现自定义iptalbes-rule的问题的答案: