Kubernetes:使用多个容器将服务路由到 pods
Kubernetes: Service routing to pods with multiple containers
我目前在我的 Kubernetes 集群中遇到问题。在调试时,我想到了一个我不知道答案的问题。
我正在使用 1.15 版 AWS EKS,但我认为我的问题与任何特定的云或 kubernetes 版本无关
我有一个部署。它有多个容器。有一个公开此部署的服务。
假设部署有 2 个容器,C1 和 C2。 C1 需要 1 秒才能启动,但 C2 需要 30 秒才能启动(太疯狂了!)。因此,当我在时间 t1 启动 pod 时,发生的情况是,一旦 C1 立即启动并且 pod 进入 运行 状态,但只有 1/2 容器准备就绪。 Pod C2 最终在时间 t2(t1+30seconds) 开始。在时间 t2,2/2 容器准备就绪。
还假设 C1 从服务接收传入请求,它做了一些事情,然后将请求转发给 C2,C2 做了一些事情,然后 returns 将它转发给 C1。 C1 最终 returns 服务并将响应提供给客户端。
所以,我的问题是,在 t2 和 t1 之间的时间里,当 pod 处于 运行 状态但只有 1/2 容器准备就绪时,服务是否会将请求转发到 pods ?
换句话说,服务什么时候转发请求到pods?如果它们处于 运行 状态并且不管有多少容器已准备好?或者如果它们处于 运行 状态并且所有容器都准备好了?
我的想法是服务不会转发,因为如果所有 pods 都没有准备好,但我没有任何 proof/document 来证明它是合理的,它就没有任何意义。
来自文档 here
Ready: the Pod is able to serve requests and should be added to the
load balancing pools of all matching Services
因此,如果一个 pod 是 ready
,那么 pods IP 将添加到 endpoints
对象,服务将开始向该 pod 发送流量。稍后,如果更多 pods 变为 ready
,那么这些 pods IP 也会添加到 endpoints
对象,服务将开始在所有 pods.
要检查添加到服务的 pod IP,您可以 运行 kubectl describe service servicename
并检查 Endpoints
部分。
为避免流量被发送到 pod 中的容器但容器尚未准备好接受流量的情况,您可以使用 container probe
当 pod 内的所有容器都准备就绪时,只有服务的 Endpoints
填充了 Pod IP,流量开始流动。
如果容器内的端口没有启动,那么可能不会转发任何流量。但是,您可以在 pod 中获取 tcpdump 并遵循 syn 和 reset 标志以提供
为了使您的场景更易于理解,我们将它们称为 web 和 api。这些是我们服务的组件,虽然 web 将在几秒钟内准备就绪,但 api 组件将需要更多时间。
首先,我们需要决定我们的部署策略。如果我们将 web 和 api 放在同一个部署中,那么 service 对象此部署的顶部将对它们执行定义。所以如果你想在端口 443 上公开你的 web 服务,那么 api 也会在端口 443 上公开。是的,您可以标记它们并设置不同的定义,但这远非理想。
我们可以说 Kubernetes 世界中的 service 对象就像一个 load-balancer。所以如果你把两个不同的组件放在同一个部署上,并在它们之上定义一个服务对象,那么当你从外部网络调用你的服务时,你最终会到达 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
以及将我们的 Web 部署暴露给外部网络的服务
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
仅此而已。现在,您可以根据请求扩大或缩小 web 和 api 部署,服务定义将自动对这些部署进行负载平衡,处理服务发现。
如果您从 deployment.yaml 文件中瞥见下面提到的片段 -
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
它表明,对于金丝雀部署,25% 的标准表明,如果您在 deployment.yaml 中设置了 4 个专用副本,那么每当其中的 75% 已成功推出时,就允许提供流量通过该服务。
所以基本上您有 3/4 的副本处于活动状态并且您可以为流量提供服务。这完全是可配置的。
...when pod is in running state but only 1/2 container is ready, would the service forward requests to the pods?
没有
when does the service forward request to pods?
If they are in running state and not matter how many containers are ready? OR if they are in running state and all containers are ready?
My thinking is that service won't forward as it won't make any sense if all the pods are not ready but I don't have any proof/document to justify it.
官方文档说“...kubelet 使用就绪探测来了解容器何时准备好开始接受流量。当 Pod 的所有容器都准备就绪时,Pod 就被认为准备就绪。此信号的一种用途是控制哪些 Pods 用作服务的后端。当 Pod 未就绪时,它会从服务负载均衡器中删除..."=15=]
另外它说:
"...应用程序暂时无法处理流量...应用程序可能依赖于外部服务...在这种情况下,您不想终止应用程序,但您不想向它发送请求。Kubernetes 提供就绪探测来检测和缓解这些情况。带有容器的 pod 报告它们尚未准备好不会通过 Kubernetes 服务接收流量...“=15=]
就绪探测用于检测流量不应发送到应用程序的情况。
My thinking is that service won't forward as it won't make any sense if all the pods are not ready
你在这里绝对正确。
希望对您有所帮助。
我目前在我的 Kubernetes 集群中遇到问题。在调试时,我想到了一个我不知道答案的问题。
我正在使用 1.15 版 AWS EKS,但我认为我的问题与任何特定的云或 kubernetes 版本无关
我有一个部署。它有多个容器。有一个公开此部署的服务。
假设部署有 2 个容器,C1 和 C2。 C1 需要 1 秒才能启动,但 C2 需要 30 秒才能启动(太疯狂了!)。因此,当我在时间 t1 启动 pod 时,发生的情况是,一旦 C1 立即启动并且 pod 进入 运行 状态,但只有 1/2 容器准备就绪。 Pod C2 最终在时间 t2(t1+30seconds) 开始。在时间 t2,2/2 容器准备就绪。
还假设 C1 从服务接收传入请求,它做了一些事情,然后将请求转发给 C2,C2 做了一些事情,然后 returns 将它转发给 C1。 C1 最终 returns 服务并将响应提供给客户端。
所以,我的问题是,在 t2 和 t1 之间的时间里,当 pod 处于 运行 状态但只有 1/2 容器准备就绪时,服务是否会将请求转发到 pods ?
换句话说,服务什么时候转发请求到pods?如果它们处于 运行 状态并且不管有多少容器已准备好?或者如果它们处于 运行 状态并且所有容器都准备好了?
我的想法是服务不会转发,因为如果所有 pods 都没有准备好,但我没有任何 proof/document 来证明它是合理的,它就没有任何意义。
来自文档 here
Ready: the Pod is able to serve requests and should be added to the load balancing pools of all matching Services
因此,如果一个 pod 是 ready
,那么 pods IP 将添加到 endpoints
对象,服务将开始向该 pod 发送流量。稍后,如果更多 pods 变为 ready
,那么这些 pods IP 也会添加到 endpoints
对象,服务将开始在所有 pods.
要检查添加到服务的 pod IP,您可以 运行 kubectl describe service servicename
并检查 Endpoints
部分。
为避免流量被发送到 pod 中的容器但容器尚未准备好接受流量的情况,您可以使用 container probe
当 pod 内的所有容器都准备就绪时,只有服务的 Endpoints
填充了 Pod IP,流量开始流动。
如果容器内的端口没有启动,那么可能不会转发任何流量。但是,您可以在 pod 中获取 tcpdump 并遵循 syn 和 reset 标志以提供
为了使您的场景更易于理解,我们将它们称为 web 和 api。这些是我们服务的组件,虽然 web 将在几秒钟内准备就绪,但 api 组件将需要更多时间。
首先,我们需要决定我们的部署策略。如果我们将 web 和 api 放在同一个部署中,那么 service 对象此部署的顶部将对它们执行定义。所以如果你想在端口 443 上公开你的 web 服务,那么 api 也会在端口 443 上公开。是的,您可以标记它们并设置不同的定义,但这远非理想。
我们可以说 Kubernetes 世界中的 service 对象就像一个 load-balancer。所以如果你把两个不同的组件放在同一个部署上,并在它们之上定义一个服务对象,那么当你从外部网络调用你的服务时,你最终会到达 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
以及将我们的 Web 部署暴露给外部网络的服务
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
仅此而已。现在,您可以根据请求扩大或缩小 web 和 api 部署,服务定义将自动对这些部署进行负载平衡,处理服务发现。
如果您从 deployment.yaml 文件中瞥见下面提到的片段 -
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
它表明,对于金丝雀部署,25% 的标准表明,如果您在 deployment.yaml 中设置了 4 个专用副本,那么每当其中的 75% 已成功推出时,就允许提供流量通过该服务。
所以基本上您有 3/4 的副本处于活动状态并且您可以为流量提供服务。这完全是可配置的。
...when pod is in running state but only 1/2 container is ready, would the service forward requests to the pods?
没有
when does the service forward request to pods? If they are in running state and not matter how many containers are ready? OR if they are in running state and all containers are ready?
My thinking is that service won't forward as it won't make any sense if all the pods are not ready but I don't have any proof/document to justify it.
官方文档说“...kubelet 使用就绪探测来了解容器何时准备好开始接受流量。当 Pod 的所有容器都准备就绪时,Pod 就被认为准备就绪。此信号的一种用途是控制哪些 Pods 用作服务的后端。当 Pod 未就绪时,它会从服务负载均衡器中删除..."=15=]
另外它说:
"...应用程序暂时无法处理流量...应用程序可能依赖于外部服务...在这种情况下,您不想终止应用程序,但您不想向它发送请求。Kubernetes 提供就绪探测来检测和缓解这些情况。带有容器的 pod 报告它们尚未准备好不会通过 Kubernetes 服务接收流量...“=15=]
就绪探测用于检测流量不应发送到应用程序的情况。
My thinking is that service won't forward as it won't make any sense if all the pods are not ready
你在这里绝对正确。
希望对您有所帮助。