Kubernetes Nginx:如何实现零停机部署?
我正在尝试零停机时间的kubernetes nginx部署。该过程的一部分是启动rollingUpdate,它确保至少有一个pod始终运行nginx。这非常有效 当旧的nginx吊舱终止时,我遇到了错误。 根据kubernetes在上的文件,kubernetes将:Kubernetes Nginx:如何实现零停机部署?,nginx,kubernetes,termination,Nginx,Kubernetes,Termination,我正在尝试零停机时间的kubernetes nginx部署。该过程的一部分是启动rollingUpdate,它确保至少有一个pod始终运行nginx。这非常有效 当旧的nginx吊舱终止时,我遇到了错误。 根据kubernetes在上的文件,kubernetes将: 从服务的终结点列表中删除pod,这样就可以了 终止开始时不接收任何新流量 如果定义了预停止挂钩,则调用它,并等待它完成 将SIGTERM发送到所有剩余进程 在宽限期到期后,将SIGKILL发送到任何剩余进程 我知道命令nginx-s
nginx-s quit
应该通过等待所有工作人员在主机终止之前完成请求来优雅地终止nginx。它优雅地响应SIGQUIT命令,而SIGTERM导致暴力终止。其他论坛表示,只需在部署中添加以下预停止挂钩即可:
lifecycle:
preStop:
exec:
command: ["/usr/sbin/nginx", "-s", "quit"]
但是,通过测试这个命令,我发现nginx-s quit
会立即返回,而不是等待工作人员完成。它也不会返回主进程的PID,这正是我所希望的:
发生的情况是,kubernetes调用nginx-s quit
,这将向工作者子级发送正确的SIGQUIT,但不等待它们完成。相反,它将直接跳转到步骤3,并替换这些进程,导致暴力终止,从而丢失连接
问题:是否有人想出了一个好办法,可以在滚动部署期间优雅地关闭他们的nginx控制器,并实现零停机?sleep
解决方案不够好,我正在寻找更强大的解决方案
以下是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", "-s", "quit"]
我讨厌回答我自己的问题,但经过一点磨蹭,这就是我到目前为止所拥有的 我创建了一个半阻塞的bash脚本,名为
killer
:
#!/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将一个pod标记为终止,但需要一点时间(<1s)才能将该pod从指向它的流量的服务中删除的竞争条件造成的
我已将此脚本装入pod,并通过
preStop
指令调用它。它基本上是有效的,但在测试过程中仍然偶尔会出现旋涡错误,即连接“被对等方重置”。但这是朝着正确方向迈出的一步。适用于即将尝试相同操作的任何人。由于@Lindsay Landry提到的比赛条件,在nginx docker图像中使用停止信号SIGQUIT
不起作用。您将暂时失去连接,因此请继续使用上面的bash脚本。@Niels-OleSTOPSIGNAL-SIGQUIT
似乎工作正常,但仍需要sleep 3
来处理竞争条件