GKE 在高负载期间忽略来自 pod 的就绪探测
GKE ignores readiness probe from pod during high load
我在 kubernetes 中有一个应用程序 运行,在几个 pods 上。我正在尝试改善我们的部署体验(我们正在使用滚动部署),这目前正在造成痛苦。
我想达到的目标:
- 每个 pod 首先都没有准备好,所以它没有更多的流量
- 然后它将完成当前正在处理的请求
- 然后就可以去掉了
这应该都是可能的并且可以正常工作 - 您创建一个包含就绪和活动探测的部署。负载均衡器将拾取这些并相应地路由流量。但是,当我测试我的部署时,我看到 pods 即使切换到未就绪状态也收到请求。具体来说,当大量流量进入时,负载均衡器似乎不会更新。当我向它们发出信号时,我可以看到 pods 正在“未准备好”——如果它们在切换状态时没有获得流量,之后他们将不会收到流量。但是,如果他们在切换时获得流量,负载均衡器将忽略状态更改。
我开始想知道如何处理这个问题,因为我看不出我遗漏了什么 - 必须有可能在 kubernetes 上托管一个高流量应用程序 pods 将“未准备好” " 而不会丢失大量请求。
我的配置
部署
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-service
name: my-service
namespace: mine
spec:
replicas: 2
selector:
matchLabels:
app: my-service
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: my-service
env: production
spec:
containers:
- name: my-service
image: IMAGE ID
imagePullPolicy: Always
volumeMounts:
- name: credentials
mountPath: "/run/credentials"
readOnly: true
securityContext:
privileged: true
ports:
- containerPort: 8080
protocol: TCP
lifecycle:
preStop:
exec:
command: ["/opt/app/bin/graceful-shutdown.sh"]
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 1
initialDelaySeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /alive
port: 8080
periodSeconds: 1
failureThreshold: 2
initialDelaySeconds: 60
resources:
requests:
memory: "500M"
cpu: "250m"
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 60
nodeSelector:
cloud.google.com/gke-nodepool: stateful
Service/loadbalancer
apiVersion: v1
kind: Service
metadata:
name: stock-service-loadbalancer
namespace: stock
spec:
selector:
app: stock-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
事实证明这是一种效果或持久的连接,而不是流量。原因似乎是负载均衡器不会关闭打开的连接 - 对于我们的服务,我们使用的测试设置使用了一个长 运行 连接池。因此,负载均衡器正在更新它的路由,但现有连接一直在向终止 pod 发送数据。
结果是这种零停机策略确实有效:
- 使用 preStop 挂钩使您的 pod 无法通过就绪探测
- 确保等待几秒钟
- 然后让您的 pod 通过 SIGTERM
正常终止
- 确保您的 terminationGracePeriodSeconds 足够大以涵盖 preStop 和实际终止期
我在 kubernetes 中有一个应用程序 运行,在几个 pods 上。我正在尝试改善我们的部署体验(我们正在使用滚动部署),这目前正在造成痛苦。
我想达到的目标:
- 每个 pod 首先都没有准备好,所以它没有更多的流量
- 然后它将完成当前正在处理的请求
- 然后就可以去掉了
这应该都是可能的并且可以正常工作 - 您创建一个包含就绪和活动探测的部署。负载均衡器将拾取这些并相应地路由流量。但是,当我测试我的部署时,我看到 pods 即使切换到未就绪状态也收到请求。具体来说,当大量流量进入时,负载均衡器似乎不会更新。当我向它们发出信号时,我可以看到 pods 正在“未准备好”——如果它们在切换状态时没有获得流量,之后他们将不会收到流量。但是,如果他们在切换时获得流量,负载均衡器将忽略状态更改。
我开始想知道如何处理这个问题,因为我看不出我遗漏了什么 - 必须有可能在 kubernetes 上托管一个高流量应用程序 pods 将“未准备好” " 而不会丢失大量请求。
我的配置
部署
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-service
name: my-service
namespace: mine
spec:
replicas: 2
selector:
matchLabels:
app: my-service
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: my-service
env: production
spec:
containers:
- name: my-service
image: IMAGE ID
imagePullPolicy: Always
volumeMounts:
- name: credentials
mountPath: "/run/credentials"
readOnly: true
securityContext:
privileged: true
ports:
- containerPort: 8080
protocol: TCP
lifecycle:
preStop:
exec:
command: ["/opt/app/bin/graceful-shutdown.sh"]
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 1
initialDelaySeconds: 5
failureThreshold: 1
livenessProbe:
httpGet:
path: /alive
port: 8080
periodSeconds: 1
failureThreshold: 2
initialDelaySeconds: 60
resources:
requests:
memory: "500M"
cpu: "250m"
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 60
nodeSelector:
cloud.google.com/gke-nodepool: stateful
Service/loadbalancer
apiVersion: v1
kind: Service
metadata:
name: stock-service-loadbalancer
namespace: stock
spec:
selector:
app: stock-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
事实证明这是一种效果或持久的连接,而不是流量。原因似乎是负载均衡器不会关闭打开的连接 - 对于我们的服务,我们使用的测试设置使用了一个长 运行 连接池。因此,负载均衡器正在更新它的路由,但现有连接一直在向终止 pod 发送数据。
结果是这种零停机策略确实有效:
- 使用 preStop 挂钩使您的 pod 无法通过就绪探测
- 确保等待几秒钟
- 然后让您的 pod 通过 SIGTERM 正常终止
- 确保您的 terminationGracePeriodSeconds 足够大以涵盖 preStop 和实际终止期