當kubernetes對服務滾動更新的期間,默認配置的狀況下可能會讓部分鏈接異常(好比鏈接被拒絕),咱們來分析下緣由並給出最佳實踐nginx
滾動更新場景
使用 deployment 部署服務並關聯 service後端
- 修改 deployment 的 replica 調整副本數量來滾動更新
- 升級程序版本(修改鏡像tag)觸發 deployment 新建 replicaset 啓動新版本的 pod
- 使用 HPA (HorizontalPodAutoscaler) 來對 deployment 自動擴縮容更新過程鏈接異常的緣由滾動更新時,service 對應的 pod 會被建立或銷燬,也就是 service 對應的 endpoint 列表會新增或移除endpoint,更新期間可能讓部分鏈接異常,主要緣由是:
- pod 被建立,還沒徹底啓動就被 endpoint controller 加入到 service 的 endpoint 列表,而後 kube-proxy 配置對應的路由規則(iptables/ipvs),若是請求被路由到還沒徹底啓動完成的 pod,這時 pod 還不能正常處理請求,就會致使鏈接異常
- 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 示例:api
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"]
參考資料