我关注了 http://rahmonov.me/posts/zero-downtime-deployment-with-kubernetes/博客,创建了两个带有索引的 docker 映像.html返回"应用程序的版本 1"和"应用程序的版本 2"。我想要实现的是零停机时间发布。我正在使用
kubectl apply -f mydeployment.yaml
里面有image: mynamespace/nodowntime-test:v1
。
要将 v1 版本部署到 K8s,然后运行:
while True
do
printf "n---------------------------------------------n"
curl "http://myhosthere"
sleep 1s
done
到目前为止,一切正常。短时间后,curl 返回"应用程序版本 1"。 然后我用image: mynamespace/nodowntime-test:v2
应用相同的 k8s 部署文件。好吧,它可以工作,但是在v1和v2之间有一个(总是一个(网关超时响应。所以它不是真的没有停机时间发布;( 它比没有滚动更新要好得多,但并不完美。
我正在使用RollingUpdate
策略和readinessProbe:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodowntime-deployment
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app: nodowntime-test
template:
metadata:
labels:
app: nodowntime-test
spec:
containers:
...
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 5
我能做得更好吗?与入口控制器同步所有这些是否有问题?我知道我可以通过使用minReadySeconds
所以旧的和新的 pod 重叠一段时间来调整它,但这是唯一的解决方案吗?
我重新创建了上述实验,并通过启动以下三个同时进程将请求数更改为每秒近 30 个:
While True
do
curl -s https://<NodeIP>:<NodePort>/ -m 0.1 --connect-timeout 0.1 | grep Version || echo "fail"
done
多次编辑部署和更改镜像版本后,在转换过程中完全没有丢包。 我什至捕捉到了同时通过两个图像提供请求的短暂时刻。
Version 1 of my awesome app! Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
因此,如果将请求直接发送到服务,它将按预期工作。
"网关超时"错误是来自 Traefik 代理的回复。它通过一组iptables规则打开与后端的TCP连接。
当你执行RollingUpdates时,iptables规则已经改变,但Traefic不知道这一点,所以从Traefik的角度来看,连接仍然被认为是开放的。在第一次尝试通过不存在的iptables规则失败后,Traefik报告"网关超时"并关闭tcp连接。在下一次尝试时,它通过新的 iptables 规则打开与后端的新连接,一切再次顺利。
可以通过在 Traefik 中启用重试来修复它。
# Enable retry sending request if network error
[retry]
# Number of attempts
#
# Optional
# Default: (number servers in backend) -1
#
# attempts = 3
更新:
最后,我们在不使用 traefik 的"重试"功能的情况下解决了它,该功能可能需要对所有服务进行幂等处理(无论如何这很好,但我们不能强迫所有项目都这样做(。您需要的是 kubernetes RollingUpdate 策略 + RereadynessProbe 配置并在您的应用程序中实现优雅关闭。