【问题标题】:Kubernetes: Service routing to pods with multiple containersKubernetes:服务路由到具有多个容器的 pod
【发布时间】:2020-10-15 14:47:54
【问题描述】:

我目前在我的 Kubernetes 集群中遇到问题。在调试时,我想到了一个我不知道答案的问题。

我使用的是 AWS EKS,版本 1.15,但我认为我的问题与任何特定的云或 kubernetes 版本无关

我有一个部署。它有多个容器。有一个服务公开了这个部署。

假设部署有 2 个容器,C1 和 C2。 C1 需要 1 秒才能启动,但 C2 需要 30 秒才能启动(疯狂!)。因此,当我在时间 t1 启动 pod 时,发生的情况是,一旦 C1 立即启动并且 pod 进入运行状态,但只有 1/2 容器准备就绪。 pod C2 最终在时间 t2(t1+30 秒)开始。在时间 t2,有 2/2 个容器准备就绪。

还假设 C1 从服务中获取传入请求,它做一些事情然后将请求转发给 C2,C2 做一些事情然后将其返回给 C1。 C1 最终返回服务并将响应提供给客户端。

所以,我的问题是,在 t2 和 t1 之间,当 pod 处于运行状态但只有 1/2 容器准备就绪时,服务会将请求转发到 pod 吗?

换句话说,服务何时将请求转发到 pod?如果它们处于运行状态,不管有多少容器准备好了?或者如果它们处于运行状态并且所有容器都准备好了?

我的想法是服务不会转发,因为如果所有 pod 都没有准备好,但我没有任何证据/文件来证明它是合理的,它就没有任何意义。

【问题讨论】:

  • 好的,我得到了答案。如果一个 pod 的所有容器都没有准备好,则流量不会流向该 pod。仅当所有容器都准备好时,才将 Pod 的端点添加到服务中。当 1/2 容器准备好时,我描述了我的服务。 pod IP 未出现在服务端点中。当 2/2 个容器准备就绪时,它才将 pod IP 添加到服务端点。感谢所有回答的人。这对我来说很愚蠢。

标签: kubernetes containers kubernetes-pod kubernetes-service


【解决方案1】:

为了让您的场景更易于理解,我们将它们称为 webapi。这些是我们服务的组件,虽然 web 将在几秒钟内准备就绪,但 api 组件将需要更多时间。

首先,我们需要确定我们的部署策略。如果我们将 webapi 放在同一个部署中,那么在此部署之上的 service 对象将强制执行它们的定义。因此,如果您想在端口 443 上公开您的 web 服务,那么 api 也将在端口 443 上公开。是的,您可以标记它们并设置不同的定义,但是这远非理想。

我们可以说 Kubernetes 世界中的 service 对象就像一个负载平衡器。因此,如果您将两个不同的组件放在同一个部署中,并在它们之上定义一个服务对象,那么当您从外部网络调用您的服务时,您最终会到达 web api 端点,随机。

您可以查看此图片以进行可视化:Kubernetes Service Example

在理想情况下,您需要在两个不同的部署中部署此应用程序,因为它们可以解耦并用于不同的目的。部署这些之后,您需要做的就是部署两个不同的服务来公开您的部署。据我了解,api只在内网运行,所以可以是headless-service

首先,让我们为应用程序创建一个命名空间(或项目)。

kubectl create ns myapp

并定义我们的部署所以对于我们的web组件,让我们定义部署文件;

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  labels:
    app: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 9376

以及将我们的网络部署暴露给外部网络的服务

apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

您可以看到 web-deployment 部署对象具有三个副本,web-service 服务定义将相应地对传入请求进行负载平衡。

现在,让我们部署 api

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
  labels:
    app: api
spec:
  replicas: 5
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: apirepo/api
        ports:
        - containerPort: 3000

以及 api-deployment

的无头服务
apiVersion: v1
kind: Service
metadata:
  name: api-headless-service
spec:
  clusterIP: None 
  selector:
    app: api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000 

仅此而已。现在,您可以根据请求扩展或缩减您的 webapi 部署,服务定义将自动对这些部署进行负载平衡并处理服务发现。

【讨论】:

  • 如果它不是 Web 和 Api,而仅仅是一个 sidecar 容器,情况会怎样?而topicstarter不需要自动缩放? Arghya 的回答恰到好处。
  • 你是对的,topicstarter 可以通过说“具有多个容器的 pod”来表示这一点。我的错。
  • 我从我的场景中得到的主要收获是,如果您在一个 pod 中使用超过 1 个容器。每个容器的 readinessProbe 中的 initialDelaySeconds 应该等于所有容器中最大的 initialDelaySeconds。如果所有容器都没有准备好,那么让 pod 运行毫无意义。你怎么看?
  • 请问为什么需要在一个 pod 中部署多个容器才能了解情况?
  • 是的,这是一件坏事,有点反模式。一些旧的遗留服务,它们正在缓慢迁移,但目前我必须这样做。
【解决方案2】:

...当 pod 处于运行状态但只有 1/2 容器准备好时,服务是否会将请求转发到 pod?

没有。

服务何时将请求转发到 pod? 如果它们处于运行状态,不管有多少容器准备好了?或者如果它们处于运行状态并且所有容器都准备好了?

我的想法是服务不会转发,因为如果所有 pod 都没有准备好,但我没有任何证据/文件来证明它是合理的,它就没有任何意义。

Here it is :)

官方文档说“...kubelet 使用就绪探针来了解容器何时准备好开始接受流量。当所有容器都准备好时,Pod 被认为已准备就绪。一种用途该信号的主要目的是控制哪些 Pod 用作 Services 的后端。当 Pod 未准备好时,它会从 Service 负载均衡器中移除..."

另外它说:

"...应用程序暂时无法提供流量...应用程序可能依赖于外部服务...在这种情况下,您不想杀死应用程序,但又不想发送它请求也可以。Kubernetes 提供就绪探测来检测和缓解这些情况。带有容器报告它们未就绪的 pod 不会通过 Kubernetes 服务接收流量..."

Readiness probe 用于检测流量不应发送到 App 的情况。

我的想法是服务不会转发,因为如果所有 pod 都没有准备好,它就没有任何意义

你绝对在这里。

希望对你有帮助。

【讨论】:

    【解决方案3】:

    来自文档here

    Ready:Pod 能够处理请求,应该添加到 所有匹配服务的负载均衡池

    因此,如果一个 pod 是 ready,那么该 pod 的 IP 将被添加到 endpoints 对象,并且服务将开始向该 pod 发送流量。稍后,如果更多的 pod 变为 ready,那么这些 pod 的 IP 也会添加到 endpoints 对象中,并且服务将开始在所有 pod 之间进行负载平衡。

    要检查添加到服务的 pod IP,您可以运行 kubectl describe service servicename 并检查 Endpoints 部分。

    为避免流量被发送到 pod 中的容器但容器尚未准备好接受流量的情况,您可以使用 container probe

    当 Pod 内的所有容器都准备好后,只有服务的 Endpoints 会填充 Pod IP 并且流量开始流动。

    【讨论】:

    • 谢谢,Arghya。在容器 C2 中,我已经添加了 readinessProbe。在 readinessProbe 中,initialDelaySeconds 为 25。容器 C1 的端口正在接受来自服务的流量。那么,我应该在 C1 中配置 readinessProbe 的 initialDelaySeconds 为 30 吗?这样,两个容器都将在 t2 准备好。所以,当我的 pod 开始运行时,两个容器都准备好了。
    【解决方案4】:

    如果您从 deployment.yaml 文件中瞥见下面提到的 sn-p -

    spec:
      replicas: 4
        strategy:
            type: RollingUpdate
            rollingUpdate:
              maxUnavailable: 25%
    

    它表明,对于金丝雀部署,25% 的标准表明,如果您在 deployment.yaml 中设置了 4 个专用副本,那么只要其中 75% 的副本成功推出,则允许该服务提供流量。

    所以基本上你有 3/4 的副本活着,你可以提供流量。这完全是可配置的。

    【讨论】:

      【解决方案5】:

      如果容器内的端口未启动,则可能不会转发任何流量。但是,您可以在 pod 中使用 tcpdump 并按照 syn 和 reset 标志来提供它

      【讨论】:

      • 谢谢图泰。容器 C1 的端口被配置为接受来自服务的连接。容器 C1 在 1 秒内准备就绪。 C1 依赖于 C2 来处理请求。但是C2需要时间来启动。所以你的意思是,如果 C1 准备好,服务会将请求转发到 pod?这意味着将近 30 秒,请求将失败?
      猜你喜欢
      • 1970-01-01
      • 2019-01-23
      • 2019-09-19
      • 2017-08-25
      • 2022-07-07
      • 2020-07-03
      • 2021-08-10
      • 2020-01-21
      • 2021-03-26
      相关资源
      最近更新 更多