如何通过 Kubernetes 服务(如网关 API)路由到特定的 pod

Posted

技术标签:

【中文标题】如何通过 Kubernetes 服务(如网关 API)路由到特定的 pod【英文标题】:How to Route to specific pod through Kubernetes Service (like a Gateway API) 【发布时间】:2020-01-20 06:08:00 【问题描述】:

我在 Windows 的“Docker Desktop”上运行 Kubernetes。

我有一个用于具有 3 个副本的部署的 LoadBalancer 服务。 我想通过某种方式访问​​ SPECIFIC pod (例如通过 URL 路径::8090/pod1)

有没有办法实现这个用例?


deployment.yaml:

apiVersion: v1
kind: Service
metadata:
  name: my-service1
  labels:
    app: stream
spec:
  ports:
  - port: 8090
    targetPort: 8090
    name: port8090
  selector:
    app: stream
  # clusterIP: None
  type: LoadBalancer
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: stream-deployment
  labels:
    app: stream
spec:
  replicas: 3
  selector:
    matchLabels:
      app: stream
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: stream
    spec:
      containers:
      - image: stream-server-mock:latest
        name: stream-server-mock
        imagePullPolicy: Never
        env:
        - name: STREAMER_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STREAMER_ADDRESS
          value: stream-server-mock:8090
        ports:
        - containerPort: 8090

我的最终目标是实现 pod 的水平自动缩放。

到目前为止,应用程序的设计/工作方式(没有 kubernetes):

有 3 个组件:REST-Server、Stream-Server(3 个实例 本地在不同端口上的不同JVM上)和RabbitMQ。

1 - The client sends a request to "REST-Server" for a stream url.
2 - The REST-Server puts in the RabbitMQ queue.
3 - One of the Stream-Server picks it up and populates its IP and sends back to REST-Server through RabbitMQ.
4 - The client receives the IP and establishes a direct WS connection using the IP.

我面临的问题是

1 - When the client requests for a stream IP, one of the pods (lets say POD1) picks it up and sends its URL (which is service URL, comes through LoadBalancer Service).
2 - Next time when the client tries to connect (WebSocket Connection) using the Service IP, it wont be the same pod which accepted the request.

它应该与接受请求的 pod 相同,并且必须可供客户端访问。

【问题讨论】:

我已经更新了问题 【参考方案1】:

如果您不需要使用部署,您可以使用StatefulSets。

对于副本 3,您将拥有 3 个命名的 pod

    流部署-0 流部署-1 流部署-2

您可以通过$(podname).$(service name).$(namespace).svc.cluster.local 访问每个 pod

详情请查看this

您可能还想设置一个入口,以从集群外部指向每个 pod。

【讨论】:

在auto-scaling的情况下,我不认为有动态命名pod的机制。 我打算在上面使用 HPA。这是我的最终目标。【参考方案2】:

正如 aerokite 所述,您可以使用 StatefulSets。但是,如果您不想修改您的部署,您可以简单地使用Headless Services。如文档中所述:

对于无头服务,不分配集群 IP。

对于定义选择器的无头服务,端点控制器 在 API 中创建 Endpoints 记录,并修改 DNS 配置返回直接指向 支持服务的 Pod。

这意味着每当您查询服务的 DNS 名称时(即 my-svc.my-namespace.svc.cluster-domain.example),您得到的是所有 Pod IP 的列表(与常规服务不同,您将获得集群 IP)。然后,您可以使用自己的机制选择您的 Pod。

关于您的新问题,如果这是您唯一的问题,您可以使用会话亲和性。如果您将service.spec.sessionAffinity 设置为ClientIP,那么来自特定客户端的连接每次都将始终转到同一个 Pod。您不需要像上面提到的无头服务那样进行其他修改。

【讨论】:

@Anthony 我也更新了我的答案。您可以使用会话关联来解决您的问题。 我在 Windows 的本地环境中运行它。如果是“无头服务”,我如何从外部访问 pod 的 IP/服务? 我尝试了 sessionAffinity 和 Headless 服务。我没有按预期工作。我可能做得不对(我猜) 我已经用应用程序活动流程再次更新了问题。【参考方案3】:

IMO,实现这一目标的唯一方法是:

    不要使用具有 3 个副本的部署,而是使用具有 1 个副本的 3 个部署(或仅创建 pod);部署1 -> pod1,部署2 -> pod2,部署3 -> pod3 在单独的服务上公开所有部署,服务1 -> 部署1,服务2 -> 部署2,服务3 -> 部署3 为每个部署使用服务创建入口资源并路由到每个 pod。例如: 入口-url/service1 入口-url/service2 入口-url/service3

【讨论】:

您可以使用无头服务。我在回答中提到了细节。 @Junaid,在 Pod 自动伸缩的情况下将不起作用。 其他答案正在使用我不知道的更好的方法。 @AlassaneNdiaye 提到的 sessionAffinity 看起来很相关,但不确定它是否满足您的 HPA 要求。

以上是关于如何通过 Kubernetes 服务(如网关 API)路由到特定的 pod的主要内容,如果未能解决你的问题,请参考以下文章

如何让快速网关在 Kubernetes 中工作?

Kubernetes环境中的API网关

技术漫谈 | 在Kubernetes下实现API网关

是否有用于 Azure AKS(Azure kubernetes 服务)集群的 API 网关

Kubernetes 集群中两个服务之间使用 Ingress 作为 API 网关的通信

Kubernetes 如何比较浅显的描述 Kubernetes 的架构