Kubernetes Pod Horizontal Autoscaling safe drain,celery worker 中途缩容
Kubernetes Pod Horizontal Autoscaling safe drain, celery worker scales down mid-work
我在 GKE 上有一个 Kubernetes 集群。
除其他外,我当前的布局有一个 Pod(worker-pod),配置了一个 Horizontal pod autoscaler,它根据 BlueMedora 的 BindPlane 在 Stackdriver 上提供的外部指标进行缩放。
自动缩放功能完美无缺,但有时当需要缩小时,pods 会在完成一项永远无法完成的任务时精疲力尽。
pod 是 运行 一个 Celery worker,而作业队列由另一个带有 RabbitMQ 的 Pod 管理,我不确定是在 K8s 端还是在 rabbitMQ 端修复这个问题。
如何避免 HPA 在执行任务时缩小 pod 的尺寸?
我的 pod 规格(简体):
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-worker
labels:
component: worker
spec:
selector:
matchLabels:
app: pod-worker
replicas: 1
template:
metadata:
labels:
app: pod-worker
component: worker
spec:
containers:
- name: worker
image: custom-image:latest
imagePullPolicy: Always
command: ['celery']
args: ['worker','-A','celery_tasks.task','-l','info', '-Q', 'default,priority','-c','1', '-Ofair']
resources:
limits:
cpu: 500m
requests:
cpu: 150m
memory: 200Mi
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
restartPolicy: Always
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: pod-worker
labels:
component: worker
spec:
maxReplicas: 30
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: pod-worker
metrics:
- external:
metricName: external.googleapis.com|bluemedora|generic_node|rabbitmq|cluster|messages
targetAverageValue: "40"
type: External
要解决此问题,您有多种方法,首先,为了避免丢失要处理的消息,您需要使用 RabbitMQ 手动 ACK,您需要在工作成功后进行 ACK,如果失败,则任务将重新排队,并且然后重新加工。
其次,本质上,当自动缩放(缩减)开始时,它将发送一个 SIGTERM 信号并等待,直到变量(在 podSpec 中):
terminationGracePeriodSeconds: 90
因此您可以修改该变量并将其设置得高一些,以便它能够在任务完成后正常关闭。
在terminationGracePeriodSeconds时间过去后,pod会收到一个SIGKILL信号,这会杀死pod。
另外,你可以用python处理这些信号,这里是一个小例子:
import signal
import time
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self,signum, frame):
self.kill_now = True
if __name__ == '__main__':
killer = GracefulKiller()
while not killer.kill_now:
time.sleep(1)
print("doing something in a loop ...")
print "End of the program. I was killed gracefully :)"
我在 GKE 上有一个 Kubernetes 集群。 除其他外,我当前的布局有一个 Pod(worker-pod),配置了一个 Horizontal pod autoscaler,它根据 BlueMedora 的 BindPlane 在 Stackdriver 上提供的外部指标进行缩放。
自动缩放功能完美无缺,但有时当需要缩小时,pods 会在完成一项永远无法完成的任务时精疲力尽。
pod 是 运行 一个 Celery worker,而作业队列由另一个带有 RabbitMQ 的 Pod 管理,我不确定是在 K8s 端还是在 rabbitMQ 端修复这个问题。
如何避免 HPA 在执行任务时缩小 pod 的尺寸?
我的 pod 规格(简体):
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-worker
labels:
component: worker
spec:
selector:
matchLabels:
app: pod-worker
replicas: 1
template:
metadata:
labels:
app: pod-worker
component: worker
spec:
containers:
- name: worker
image: custom-image:latest
imagePullPolicy: Always
command: ['celery']
args: ['worker','-A','celery_tasks.task','-l','info', '-Q', 'default,priority','-c','1', '-Ofair']
resources:
limits:
cpu: 500m
requests:
cpu: 150m
memory: 200Mi
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
restartPolicy: Always
---
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: pod-worker
labels:
component: worker
spec:
maxReplicas: 30
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: pod-worker
metrics:
- external:
metricName: external.googleapis.com|bluemedora|generic_node|rabbitmq|cluster|messages
targetAverageValue: "40"
type: External
要解决此问题,您有多种方法,首先,为了避免丢失要处理的消息,您需要使用 RabbitMQ 手动 ACK,您需要在工作成功后进行 ACK,如果失败,则任务将重新排队,并且然后重新加工。
其次,本质上,当自动缩放(缩减)开始时,它将发送一个 SIGTERM 信号并等待,直到变量(在 podSpec 中):
terminationGracePeriodSeconds: 90
因此您可以修改该变量并将其设置得高一些,以便它能够在任务完成后正常关闭。
在terminationGracePeriodSeconds时间过去后,pod会收到一个SIGKILL信号,这会杀死pod。
另外,你可以用python处理这些信号,这里是一个小例子:
import signal
import time
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self,signum, frame):
self.kill_now = True
if __name__ == '__main__':
killer = GracefulKiller()
while not killer.kill_now:
time.sleep(1)
print("doing something in a loop ...")
print "End of the program. I was killed gracefully :)"