我让Celery工作人员在AWS EKS上的Kubernetes 1.20集群上运行,使用AWS Elasticache Redis作为代理。由于该项目的性质,大约80%的芹菜工人都在闲置,因此合理的做法是让他们自动伸缩。基于CPU/内存的缩放工作正常。在大约4个工人的情况下,节点缩放也需要启动,这也工作正常。一个明显的问题是,一个新节点需要一段时间才能启动并完全运行,然后该节点才能开始使用新的芹菜工人荚。因此,预计会有一些人在等待扩大规模。
在等待中的某个地方,一个新的芹菜工人吊舱开始接受新任务并执行它们,但由于某种未知的原因,startupProbe
没有完成。由于startupProbe
没有成功,整个吊舱可能在运行任务的过程中被杀死。
问题:在startupProbe
被认为成功之前,我可以阻止芹菜承担任务吗?
芹菜配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: celery-worker
labels:
app: celery-worker
spec:
selector:
matchLabels:
app: celery-worker
progressDeadlineSeconds: 900
template:
metadata:
labels:
app: celery-worker
spec:
containers:
- name: celery-worker
image: -redacted-
imagePullPolicy: Always
command: ["./scripts/celery_worker_entrypoint_infra.sh"]
env:
- name: CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: celery-broker-url-secret
key: broker-url
startupProbe:
exec:
command: ["/bin/bash", "-c", "celery -q -A app inspect -d celery@$HOSTNAME --timeout 10 ping"]
initialDelaySeconds: 20
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["/bin/bash", "-c", "celery -q -b $CELERY_BROKER_URL inspect -d celery@$HOSTNAME --timeout 10 ping"]
periodSeconds: 120
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 3
livenessProbe:
exec:
command: ["/bin/bash", "-c", "celery -q -b $CELERY_BROKER_URL inspect -d celery@$HOSTNAME --timeout 10 ping"]
periodSeconds: 120
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 5
resources:
requests:
memory: "384Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
terminationGracePeriodSeconds: 2400
芹菜HPA配置
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta2
metadata:
name: celery-worker
spec:
minReplicas: 2
maxReplicas: 40
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: celery-worker
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 90
芹菜启动脚本
python manage.py check
exec celery --quiet -A app worker
--loglevel info
--concurrency 1
--uid=nobody
--gid=nogroup
我正在分享完整的配置,包括readinessProbe
和livenessProbe
,它们的值有点膨胀,但是各种尝试和错误场景的结果。
编辑:这是第二十二条军规。
我定义了startupProbe
来检查芹菜是否在当前主机中运行,只有当芹菜工作程序正在运行时,这才是真的。如果芹菜工人正在运行,它将接受任务。如果它将接受任务,celery inspect
命令可能会花费太长时间,导致startupProbe
挂起并失败。如果startupProbe
失败太多次,它将杀死吊舱。
此外,如果我在没有定义目的地(主机(的情况下调用celery inspect
,startupProbe
将在初始部署时失败。
结论:CCD_ 12不是一个好的CCD_。
结论:
celery inspect
不是一个好的startupProbe
候选者。
我同意。
您还提到您有一个活动的healtcheck
我在另一个容器中有一个web服务,它使用Django框架,并在
/health
上公开健康检查
我认为用它来创建启动探针是值得的:
有时,您必须处理可能在首次初始化时需要额外启动时间的遗留应用程序。在这种情况下,在不影响对死锁的快速响应的情况下设置活跃度探测参数可能很棘手。诀窍是用相同的命令、HTTP或TCP检查设置一个启动探测器,
failureThreshold * periodSeconds
的长度足以覆盖最坏情况下的启动时间。
您还提到了一个示例攻击:
嗯,我不确定这样做是否明智。例如,如果我的
/health
网络服务遭到DDoS攻击,我的芹菜员工也会失败。
但是,这应该不是问题。启动探测将仅在容器启动时运行。当环境被启动时,有人攻击你的可能性几乎为零。在应用程序运行时,您应该使用就绪性或活动性探测来检查容器是否处于活动状态。
kubelet使用启动探测来知道容器应用程序何时启动。如果配置了这样的探测器,它将禁用活动性和就绪性检查,直到成功为止,以确保这些探测器不会干扰应用程序的启动。这可以用于对启动缓慢的容器进行活性检查,避免它们在启动和运行之前被kubelet杀死。
在这里你可以找到示例yaml
ports:
- name: liveness-port
containerPort: 8080
hostPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 1
periodSeconds: 10
startupProbe:
httpGet:
path: /healthz
port: liveness-port
failureThreshold: 30
periodSeconds: 10
在这种情况下,startupProbe
将在其第一次初始化时执行,然后将使用livenessProbe
。