Kubernetes服務部署中如何提高服務可用性

這篇文章將為大家詳細講解有關Kubernetes 服務部署中如何提高服務可用性,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

創(chuàng)新互聯(lián)主要從事網(wǎng)站設計制作、做網(wǎng)站、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務澧縣,10余年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18980820575

怎樣提高我們部署服務的可用性呢?K8S 設計本身就考慮到了各種故障的可能性,并提供了一些自愈機制以提高系統(tǒng)的容錯性,但有些情況還是可能導致較長時間不可用,拉低服務可用性的指標。下面將結(jié)合生產(chǎn)實踐經(jīng)驗,為大家提供一些最佳實踐來最大化的提高服務可用性。

如何避免單點故障?

K8S 的設計就是假設節(jié)點是不可靠的。節(jié)點越多,發(fā)生軟硬件故障導致節(jié)點不可用的幾率就越高,所以我們通常需要給服務部署多個副本,根據(jù)實際情況調(diào)整 replicas 的值,如果值為 1 就必然存在單點故障,如果大于 1 但所有副本都調(diào)度到同一個節(jié)點了,那還是有單點故障,有時候還要考慮到災難,比如整個機房不可用。

所以我們不僅要有合理的副本數(shù)量,還需要讓這些不同副本調(diào)度到不同的拓撲域(節(jié)點、可用區(qū)),打散調(diào)度以避免單點故障,這個可以利用 Pod 反親和性來做到,反親和主要分強反親和與弱反親和兩種。更多親和與反親和信息可參考官方文檔Affinity and anti-affinity。

先來看個強反親和的示例,將 DNS 服務強制打散調(diào)度到不同節(jié)點上:

affinity: podAntiAffinity:   requiredDuringSchedulingIgnoredDuringExecution:   - labelSelector:       matchExpressions:       - key: k8s-app         operator: In         values:         - kube-dns     topologyKey: kubernetes.io/hostname
  • labelSelector.matchExpressions 寫該服務對應 pod 中 labels 的 key 與 value,因為 Pod 反親和性是通過判斷 replicas 的 pod label 來實現(xiàn)的。

  • topologyKey 指定反親和的拓撲域,即節(jié)點 label 的 key。這里用的 kubernetes.io/hostname 表示避免 pod 調(diào)度到同一節(jié)點,如果你有更高的要求,比如避免調(diào)度到同一個可用區(qū),實現(xiàn)異地多活,可以用 failure-domain.beta.kubernetes.io/zone。通常不會去避免調(diào)度到同一個地域,因為一般同一個集群的節(jié)點都在一個地域,如果跨地域,即使用專線時延也會很大,所以 topologyKey 一般不至于用 failure-domain.beta.kubernetes.io/region。

  • requiredDuringSchedulingIgnoredDuringExecution 調(diào)度時必須滿足該反親和性條件,如果沒有節(jié)點滿足條件就不調(diào)度到任何節(jié)點 (Pending)。

如果不用這種硬性條件可以使用 preferredDuringSchedulingIgnoredDuringExecution 來指示調(diào)度器盡量滿足反親和性條件,即弱反親和性,如果實在沒有滿足條件的,只要節(jié)點有足夠資源,還是可以讓其調(diào)度到某個節(jié)點,至少不會 Pending。

我們再來看個弱反親和的示例:

affinity:  podAntiAffinity:    preferredDuringSchedulingIgnoredDuringExecution:    - weight: 100      podAffinityTerm:        labelSelector:          matchExpressions:          - key: k8s-app            operator: In            values:            - kube-dns      topologyKey: kubernetes.io/hostname

注意到了嗎?相比強反親和有些不同哦,多了一個 weight,表示此匹配條件的權重,而匹配條件被挪到了 podAffinityTerm 下面。

如何避免節(jié)點維護或升級時導致服務不可用?

有時候我們需要對節(jié)點進行維護或進行版本升級等操作,操作之前需要對節(jié)點執(zhí)行驅(qū)逐 (kubectl drain),驅(qū)逐時會將節(jié)點上的 Pod 進行刪除,以便它們漂移到其它節(jié)點上,當驅(qū)逐完畢之后,節(jié)點上的 Pod 都漂移到其它節(jié)點了,這時我們就可以放心的對節(jié)點進行操作了。

有一個問題就是,驅(qū)逐節(jié)點是一種有損操作,驅(qū)逐的原理:

  1. 封鎖節(jié)點 (設為不可調(diào)度,避免新的 Pod 調(diào)度上來)。

  2. 將該節(jié)點上的 Pod 刪除。

  3. ReplicaSet 控制器檢測到 Pod 減少,會重新創(chuàng)建一個 Pod,調(diào)度到新的節(jié)點上。

這個過程是先刪除,再創(chuàng)建,并非是滾動更新,因此更新過程中,如果一個服務的所有副本都在被驅(qū)逐的節(jié)點上,則可能導致該服務不可用。

我們再來下什么情況下驅(qū)逐會導致服務不可用:

  1. 服務存在單點故障,所有副本都在同一個節(jié)點,驅(qū)逐該節(jié)點時,就可能造成服務不可用。

  2. 服務沒有單點故障,但剛好這個服務涉及的 Pod 全部都部署在這一批被驅(qū)逐的節(jié)點上,所以這個服務的所有 Pod 同時被刪,也會造成服務不可用。

  3. 服務沒有單點故障,也沒有全部部署到這一批被驅(qū)逐的節(jié)點上,但驅(qū)逐時造成這個服務的一部分 Pod 被刪,短時間內(nèi)服務的處理能力下降導致服務過載,部分請求無法處理,也就降低了服務可用性。

針對第一點,我們可以使用前面講的反親和性來避免單點故障。

針對第二和第三點,我們可以通過配置 PDB (PodDisruptionBudget) 來避免所有副本同時被刪除,驅(qū)逐時 K8S 會 "觀察" nginx 的當前可用與期望的副本數(shù),根據(jù)定義的 PDB 來控制 Pod 刪除速率,達到閥值時會等待 Pod 在其它節(jié)點上啟動并就緒后再繼續(xù)刪除,以避免同時刪除太多的 Pod 導致服務不可用或可用性降低,下面給出兩個示例。

示例一 (保證驅(qū)逐時 nginx 至少有 90% 的副本可用):

apiVersion: policy/v1beta1kind: PodDisruptionBudgetmetadata:  name: zk-pdbspec:  minAvailable: 90%  selector:    matchLabels:      app: zookeeper

示例二 (保證驅(qū)逐時 zookeeper 最多有一個副本不可用,相當于逐個刪除并等待在其它節(jié)點完成重建):

apiVersion: policy/v1beta1kind: PodDisruptionBudgetmetadata:  name: zk-pdbspec:  maxUnavailable: 1  selector:    matchLabels:      app: zookeeper

如何讓服務進行平滑更新?

解決了服務單點故障和驅(qū)逐節(jié)點時導致的可用性降低問題后,我們還需要考慮一種可能導致可用性降低的場景,那就是滾動更新。為什么服務正常滾動更新也可能影響服務的可用性呢?別急,下面我來解釋下原因。

假如集群內(nèi)存在服務間調(diào)用:

Kubernetes 服務部署中如何提高服務可用性

當 server 端發(fā)生滾動更新時:

Kubernetes 服務部署中如何提高服務可用性

發(fā)生兩種尷尬的情況:

  1. 舊的副本很快銷毀,而 client 所在節(jié)點 kube-proxy 還沒更新完轉(zhuǎn)發(fā)規(guī)則,仍然將新連接調(diào)度給舊副本,造成連接異常,可能會報 "connection refused" (進程停止過程中,不再接受新請求) 或 "no route to host" (容器已經(jīng)完全銷毀,網(wǎng)卡和 IP 已不存在)。

  2. 新副本啟動,client 所在節(jié)點 kube-proxy 很快 watch 到了新副本,更新了轉(zhuǎn)發(fā)規(guī)則,并將新連接調(diào)度給新副本,但容器內(nèi)的進程啟動很慢 (比如 Tomcat 這種 java 進程),還在啟動過程中,端口還未監(jiān)聽,無法處理連接,也造成連接異常,通常會報 "connection refused" 的錯誤。

針對第一種情況,可以給 container 加 preStop,讓 Pod 真正銷毀前先 sleep 等待一段時間,等待 client 所在節(jié)點 kube-proxy 更新轉(zhuǎn)發(fā)規(guī)則,然后再真正去銷毀容器。這樣能保證在 Pod Terminating 后還能繼續(xù)正常運行一段時間,這段時間如果因為 client 側(cè)的轉(zhuǎn)發(fā)規(guī)則更新不及時導致還有新請求轉(zhuǎn)發(fā)過來,Pod 還是可以正常處理請求,避免了連接異常的發(fā)生。聽起來感覺有點不優(yōu)雅,但實際效果還是比較好的,分布式的世界沒有銀彈,我們只能盡量在當前設計現(xiàn)狀下找到并實踐能夠解決問題的最優(yōu)解。

針對第二種情況,可以給 container 加 ReadinessProbe (就緒檢查),讓容器內(nèi)進程真正啟動完成后才更新 Service 的 Endpoint,然后 client 所在節(jié)點 kube-proxy 再更新轉(zhuǎn)發(fā)規(guī)則,讓流量進來。這樣能夠保證等 Pod 完全就緒了才會被轉(zhuǎn)發(fā)流量,也就避免了鏈接異常的發(fā)生。

健康檢查怎么配才好?

我們都知道,給 Pod 配置健康檢查也是提高服務可用性的一種手段,配置 ReadinessProbe (就緒檢查) 可以避免將流量轉(zhuǎn)發(fā)給還沒啟動完全或出現(xiàn)異常的 Pod;配置 LivenessProbe (存活檢查) 可以讓存在 bug 導致死鎖或 hang 住的應用重啟來恢復。但是,如果配置配置不好,也可能引發(fā)其它問題,這里根據(jù)一些踩坑經(jīng)驗總結(jié)了一些指導性的建議:

  • 不要輕易使用 LivenessProbe,除非你了解后果并且明白為什么你需要它,參考 Liveness Probes are Dangerous

  • 如果使用 LivenessProbe,不要和 ReadinessProbe 設置成一樣 (failureThreshold 更大)

  • 探測邏輯里不要有外部依賴 (db, 其它 pod 等),避免抖動導致級聯(lián)故障

  • 業(yè)務程序應盡量暴露 HTTP 探測接口來適配健康檢查,避免使用 TCP 探測,因為程序 hang 死時, TCP 探測仍然能通過 (TCP 的 SYN 包探測端口是否存活在內(nèi)核態(tài)完成,應用層不感知)

關于Kubernetes 服務部署中如何提高服務可用性就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

當前題目:Kubernetes服務部署中如何提高服務可用性
文章路徑:http://muchs.cn/article26/ghsejg.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁設計公司、標簽優(yōu)化軟件開發(fā)、ChatGPT、面包屑導航、建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)