kubernetes 最佳實踐:優雅熱更新

當kubernetes對服務滾動更新的期間,默認配置的情況下可能會讓部分連接異常(比如連接被拒絕),我們來分析下原因並給出最佳實踐

滾動更新場景

使用 deployment 部署服務並關聯 service

  • 修改 deployment 的 replica 調整副本數量來滾動更新
  • 升級程序版本(修改鏡像tag)觸發 deployment 新建 replicaset 啓動新版本的 pod
  • 使用 HPA (HorizontalPodAutoscaler) 來對 deployment 自動擴縮容

更新過程連接異常的原因

滾動更新時,service 對應的 pod 會被創建或銷燬,也就是 service 對應的 endpoint 列表會新增或移除endpoint,更新期間可能讓部分連接異常,主要原因是:

  1. pod 被創建,還沒完全啓動就被 endpoint controller 加入到 service 的 endpoint 列表,然後 kube-proxy 配置對應的路由規則(iptables/ipvs),如果請求被路由到還沒完全啓動完成的 pod,這時 pod 還不能正常處理請求,就會導致連接異常
  2. pod 被銷燬,但是從 endpoint controller watch 到變化並更新 service 的 endpoint 列表到 kube-proxy 更新路由規則這期間有個時間差,pod可能已經完全被銷燬了,但是路由規則還沒來得及更新,造成請求依舊還能被轉發到已經銷燬的 pod ip,導致連接異常

最佳實踐

  • 針對第一種情況,可以給 pod 裏的 container 加 readinessProbe (就緒檢查),這樣可以讓容器完全啓動了才被endpoint controller加進 service 的 endpoint 列表,然後 kube-proxy 再更新路由規則,這時請求被轉發到的所有後端 pod 都是正常運行,避免了連接異常
  • 針對第二種情況,可以給 pod 裏的 container 加 preStop hook,讓 pod 真正銷燬前先 sleep 等待一段時間,留點時間給 endpoint controller 和 kube-proxy 清理 endpoint 和路由規則,這段時間 pod 處於 Terminating 狀態,在路由規則更新完全之前如果有請求轉發到這個被銷燬的 pod,請求依然可以被正常處理,因爲它還沒有被真正銷燬

最佳實踐 yaml 示例:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      component: nginx
  template:
    metadata:
      labels:
        component: nginx
    spec:
      containers:
      - name: nginx
        image: "nginx"
        ports:
        - name: http
          hostPort: 80
          containerPort: 80
          protocol: TCP
        readinessProbe:
          httpGet:
            path: /healthz
            port: 80
            httpHeaders:
            - name: X-Custom-Header
              value: Awesome
          initialDelaySeconds: 15
          timeoutSeconds: 1
        lifecycle:
          preStop:
            exec:
              command: ["/bin/bash", "-c", "sleep 30"]

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章