我试图让kubernetes Nginx部署零停机时间.该过程的一部分是启动rollingUpdate,确保至少有一个pod始终在运行Nginx.这非常有效.
当旧的Nginx pod终止时,我遇到了错误.
根据termination的kubernetes文档,kubernetes将:
>从服务的端点列表中删除pod,所以它是
终止开始时没有收到任何新的流量
>如果已定义,则调用预停止挂钩,并等待它完成
>将SIGTERM发送到所有剩余进程
>在宽限期到期后,将SIGKILL发送给任何剩余的进程.
我知道命令Nginx -s quit应该通过在主服务器终止之前等待所有worker完成请求来优雅地终止Nginx.它优雅地响应SIGQUIT命令,而SIGTERM导致暴力终止.其他论坛说它就像在部署中添加以下preStop挂钩一样简单:
lifecycle:
preStop:
exec:
command: ["/usr/sbin/Nginx","-s","quit"]
但是,通过测试此命令,我发现Nginx -s quit立即返回,而不是等待worker完成.它也不会返回主进程的PID,这是我希望D:
会发生什么,kubernetes调用Nginx -s quit,它会向工作人员发送一个正确的SIGQUIT,但不要等待它们完成.相反,它会直接跳到第3步,而SIGTERM会转向那些进程,导致暴力终止,从而导致连接丢失.
问题:有没有人想出一个在滚动部署期间优雅地关闭他们的Nginx控制器并且没有停机时间的好方法?睡眠解决方法不够好,我正在寻找更强大的东西.
以下是完整部署yaml:
apiVersion: extensions/v1beta1
kind: Deployment
Metadata:
name: Nginx-ingress-controller
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
template:
Metadata:
labels:
app: Nginx-ingress-lb
spec:
terminationGracePeriodSeconds: 60
serviceAccount: Nginx
containers:
- name: Nginx-ingress-controller
image: gcr.io/google_containers/Nginx-ingress-controller:0.9.0-beta.8
imagePullPolicy: Always
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 5
args:
- /Nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-backend
- --v=2
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: Metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: Metadata.namespace
ports:
- containerPort: 80
lifecycle:
preStop:
exec:
command: ["/usr/sbin/Nginx","quit"]
我创建了一个半阻塞的bash脚本,称为杀手:
#!/bin/bash
sleep 3
PID=$(cat /run/Nginx.pid)
Nginx -s quit
while [ -d /proc/$PID ]; do
sleep 0.1
done
我发现在Nginx pod中有一个文件/run/Nginx.pid,它有主进程的PID.如果你调用Nginx -s quit并启动等待直到进程消失,你基本上已经使quit命令“阻塞”了.
请注意,在发生任何事情之前有一个睡眠3.这是由于竞争条件导致Kubernetes将一个吊舱标记为终止,但需要一点时间(<1s)将该吊舱从指向其的流量的服务中移除. 我已将此脚本安装到我的pod中,并通过preStop指令调用它.它主要工作,但在测试期间仍然偶尔会出现一些问题,我发现卷曲错误表明连接是“由同行重置”.但这是朝着正确方向迈出的一步.