2

我关注了http://rahmonov.me/posts/zero-downtime-deployment-with-kubernetes/博客,创建了两个带有 index.html 的 docker 图像,返回“应用程序的版本 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”。然后我将相同的 k8s 部署文件与image: mynamespace/nodowntime-test:v2. 好吧,它可以工作,但是在 v1 和 v2 之间有一个(总是一个)网关超时响应。所以它并不是真的没有停机时间释放;) 它比没有 RollingUpdate 要好得多,但并不完美。

我正在使用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 重叠一段时间来调整它,但它是唯一的解决方案吗?

4

1 回答 1

3

我重新创建了上述实验,并通过启动以下三个同时处理的进程将请求数更改为接近每秒 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!

因此,如果您直接将请求发送到服务,它将按预期工作。

“网关超时”</a> 错误是 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 策略 + ReadinessProbe 配置并在您的应用程序中实现优雅关闭。

于 2018-08-09T15:36:53.523 回答