成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在Kubernetes中部署高可用應(yīng)用程序的實(shí)踐

云計(jì)算
Kubernetes 可以提供所需的編排和管理功能,以便您針對(duì)這些工作負(fù)載大規(guī)模部署容器。借助 Kubernetes 編排功能,您可以構(gòu)建跨多個(gè)容器的應(yīng)用服務(wù)、跨集群調(diào)度、擴(kuò)展這些容器,并長(zhǎng)期持續(xù)管理這些容器的健康狀況。有了 Kubernetes,您便可切實(shí)采取一些措施來提高 IT 安全性。

[[432705]]

真正的生產(chǎn)型應(yīng)用會(huì)涉及多個(gè)容器。這些容器必須跨多個(gè)服務(wù)器主機(jī)進(jìn)行部署。容器安全性需要多層部署,因此可能會(huì)比較復(fù)雜。但 Kubernetes 有助于解決這一問題。

Kubernetes 可以提供所需的編排和管理功能,以便您針對(duì)這些工作負(fù)載大規(guī)模部署容器。借助 Kubernetes 編排功能,您可以構(gòu)建跨多個(gè)容器的應(yīng)用服務(wù)、跨集群調(diào)度、擴(kuò)展這些容器,并長(zhǎng)期持續(xù)管理這些容器的健康狀況。有了 Kubernetes,您便可切實(shí)采取一些措施來提高 IT 安全性。

高可用性(High Availability,HA)是指應(yīng)用系統(tǒng)無中斷運(yùn)行的能力,通常可通過提高該系統(tǒng)的容錯(cuò)能力來實(shí)現(xiàn)。一般情況下,通過設(shè)置 replicas 給應(yīng)用創(chuàng)建多個(gè)副本,可以適當(dāng)提高應(yīng)用容錯(cuò)能力,但這并不意味著應(yīng)用就此實(shí)現(xiàn)高可用性。

眾所周知,在Kubernetes環(huán)境中部署一個(gè)可用的應(yīng)用程序是一件輕而易舉的事。但另外一方面,如果要部署一個(gè)可容錯(cuò),高可靠且易用的應(yīng)用程序則不可避免地會(huì)遇到很多問題。在本文中,我們將討論在Kubernetes中部署高可用應(yīng)用程序并以簡(jiǎn)潔的方式給大家展示,本文也會(huì)重點(diǎn)介紹在Kubernetes部署高可用應(yīng)用所需要注意的原則以及相應(yīng)的方案。

請(qǐng)注意,我們不會(huì)使用任何現(xiàn)有的部署方案。我們也不會(huì)固定特定的CD解決方案,我們將省略模板生成 Kubernetes 清單的問題。在本文中,我們只討論部署到集群時(shí) Kubernetes 清單的最終內(nèi)容,其它的部分本文不作過多的討論。

一、副本數(shù)量

通常情況下,至少需要兩個(gè)副本才能保證應(yīng)用程序的最低高可用。但是,您可能會(huì)問,為什么單個(gè)副本無法做到高可用?問題在于 Kubernetes 中的許多實(shí)體(Node、Pod、ReplicaSet ,Deployment等)都是非持久化的,即在某些條件下,它們可能會(huì)被自動(dòng)刪除或者重新被創(chuàng)建。因此,Kubernetes 集群本身以及在其中運(yùn)行的應(yīng)用服務(wù)都必須要考慮到這一點(diǎn)。

例如,當(dāng)使用autoscaler服務(wù)縮減您的節(jié)點(diǎn)數(shù)量時(shí),其中一些節(jié)點(diǎn)將會(huì)被刪除,包括在該節(jié)點(diǎn)上運(yùn)行的 Pod。如果您的應(yīng)用只有一個(gè)實(shí)例且在運(yùn)行刪除的節(jié)點(diǎn)上,此時(shí),您可能會(huì)發(fā)現(xiàn)您的應(yīng)用會(huì)變的不可用,盡管這時(shí)間通常是比較短的,因?yàn)閷?duì)應(yīng)的Pod會(huì)在新的節(jié)點(diǎn)上重新被創(chuàng)建。

一般來說,如果你只有一個(gè)應(yīng)用程序副本,它的任何異常停服都會(huì)導(dǎo)致停機(jī)。換句話說,您必須為正在運(yùn)行的應(yīng)用程序保持至少兩個(gè)副本,從而防止單點(diǎn)故障。

副本越多,在某些副本發(fā)生故障的情況下,您的應(yīng)用程序的計(jì)算能力下降的幅度也就越小。例如,假設(shè)您有兩個(gè)副本,其中一個(gè)由于節(jié)點(diǎn)上的網(wǎng)絡(luò)問題而失敗。應(yīng)用程序可以處理的負(fù)載將減半(只有兩個(gè)副本中的一個(gè)可用)。當(dāng)然,新的副本會(huì)被調(diào)度到新的節(jié)點(diǎn)上,應(yīng)用的負(fù)載能力會(huì)完全恢復(fù)。但在那之前,增加負(fù)載可能會(huì)導(dǎo)致服務(wù)中斷,這就是為什么您必須保留一些副本。

上述建議與未使用 HorizontalPodAutoscaler 的情況相關(guān)。對(duì)于有多個(gè)副本的應(yīng)用程序,最好的替代方法是配置 HorizontalPodAutoscaler 并讓它管理副本的數(shù)量。本文的最后會(huì)詳細(xì)描述HorizontalPodAutoscaler。

二、更新策略

Deployment 的默認(rèn)更新策略需要減少舊+新的 ReplicaSet Pod 的數(shù)量,其Ready狀態(tài)為更新前數(shù)量的 75%。因此,在更新過程中,應(yīng)用程序的計(jì)算能力可能會(huì)下降到正常水平的 75%,這可能會(huì)導(dǎo)致部分故障(應(yīng)用程序性能下降)。

該strategy.RollingUpdate.maxUnavailable參數(shù)允許您配置更新期間可能變得不可用的Pod的最大百分比。因此,要么確保您的應(yīng)用程序在 25% 的Pod不可用的情況下也能順利運(yùn)行,要么降低該maxUnavailable參數(shù)。請(qǐng)注意,該maxUnavailable參數(shù)已四舍五入。

默認(rèn)更新策略 ( RollingUpdate)有一個(gè)小技巧:應(yīng)用程序在滾動(dòng)更新過程中,多副本策略依然有效,新舊版本會(huì)同時(shí)存在,一直到所有的應(yīng)用都更新完畢。但是,如果由于某種原因無法并行運(yùn)行不同的副本和不同版本的應(yīng)用程序,那么您可以使用strategy.type: Recreate參數(shù)。在Recreate策略下,所有現(xiàn)有Pod在創(chuàng)建新Pod之前都會(huì)被殺死。這會(huì)導(dǎo)致短暫的停機(jī)時(shí)間。

其他部署策略(藍(lán)綠、金絲雀等)通常可以為 RollingUpdate 策略提供更好的替代方案。但是,我們沒有在本文中考慮它們,因?yàn)樗鼈兊膶?shí)現(xiàn)取決于用于部署應(yīng)用程序的軟件。

三、跨節(jié)點(diǎn)的統(tǒng)一副本分布

Kubernetes 的設(shè)計(jì)理念為假設(shè)節(jié)點(diǎn)不可靠,節(jié)點(diǎn)越多,發(fā)生軟硬件故障導(dǎo)致節(jié)點(diǎn)不可用的幾率就越高。所以我們通常需要給應(yīng)用部署多個(gè)副本,并根據(jù)實(shí)際情況調(diào)整 replicas 的值。該值如果為1 ,就必然存在單點(diǎn)故障。該值如果大于1但所有副本都調(diào)度到同一個(gè)節(jié)點(diǎn),仍將無法避免單點(diǎn)故障。

為了避免單點(diǎn)故障,我們需要有合理的副本數(shù)量,還需要讓不同副本調(diào)度到不同的節(jié)點(diǎn)。為此,您可以指示調(diào)度程序避免在同一節(jié)點(diǎn)上啟動(dòng)同一 Deployment 的多個(gè) Pod:

  1. affinity: 
  2.   PodAntiAffinity: 
  3.     preferredDuringSchedulingIgnoredDuringExecution: 
  4.     - PodAffinityTerm: 
  5.         labelSelector: 
  6.           matchLabels: 
  7.             app: testapp 
  8.         topologyKey: kubernetes.io/hostname 

最好使用preferredDuringSchedulingaffinity而不是requiredDuringScheduling。如果新Pod所需的節(jié)點(diǎn)數(shù)大于可用節(jié)點(diǎn)數(shù),后者可能會(huì)導(dǎo)致無法啟動(dòng)新 Pod。盡管如此,requiredDuringScheduling當(dāng)提前知道節(jié)點(diǎn)和應(yīng)用程序副本的數(shù)量并且您需要確保兩個(gè)Pod不會(huì)在同一個(gè)節(jié)點(diǎn)上結(jié)束時(shí),親和性也就會(huì)派上用場(chǎng)。

四、優(yōu)先級(jí)

priorityClassName代表您的Pod優(yōu)先級(jí)。調(diào)度器使用它來決定首先調(diào)度哪些 Pod,如果節(jié)點(diǎn)上沒有剩余Pod空間,應(yīng)該首先驅(qū)逐哪些 Pod。

您將需要添加多個(gè)PriorityClass(https://kubernetes.io/docs/concepts/configuration/Pod-priority-preemption/#priorityclass)類型資源并使用priorityClassName。以下是如何PriorityClasses變化的示例:

  • Cluster. Priority > 10000:集群關(guān)鍵組件,例如 kube-apiserver。
  • Daemonsets. Priority: 10000:通常不建議將 DaemonSet Pods 從集群節(jié)點(diǎn)中驅(qū)逐,并替換為普通應(yīng)用程序。
  • Production-high. Priority: 9000:有狀態(tài)的應(yīng)用程序。
  • Production-medium. Priority: 8000:無狀態(tài)應(yīng)用程序。
  • Production-low. Priority: 7000:不太重要的應(yīng)用程序。
  • Default. Priority: 0:非生產(chǎn)應(yīng)用程序。

設(shè)置優(yōu)先級(jí)將幫助您避免關(guān)鍵組件的突然被驅(qū)逐。此外,如果缺乏節(jié)點(diǎn)資源,關(guān)鍵應(yīng)用程序?qū)Ⅱ?qū)逐不太重要的應(yīng)用程序。

五、停止容器中的進(jìn)程

STOPSIGNAL中指定的信號(hào)(通常為TERM信號(hào))被發(fā)送到進(jìn)程以停止它。但是,某些應(yīng)用程序無法正確處理它并且無法正常停服。對(duì)于在 Kubernetes 中運(yùn)行的應(yīng)用程序也是如此。

例如下面描述,為了正確關(guān)閉 nginx,你需要一個(gè)preStop這樣的鉤子:

  1. lifecycle: 
  2. preStop: 
  3.   exec
  4.     command: 
  5.     - /bin/sh 
  6.     - -ec 
  7.     - | 
  8.       sleep 3 
  9.       nginx -s quit 

上述的簡(jiǎn)要說明:

  1. sleep 3 可防止因刪除端點(diǎn)而導(dǎo)致的競(jìng)爭(zhēng)狀況。
  2. nginx -s quit正確關(guān)閉nginx。鏡像中不需要配置此行,因?yàn)?STOPSIGNAL: SIGQUIT參數(shù)默認(rèn)設(shè)置在鏡像中。

STOPSIGNAL的處理方式依賴于應(yīng)用程序本身。實(shí)際上,對(duì)于大多數(shù)應(yīng)用程序,您必須通過谷歌搜索或者其它途徑來獲取處理STOPSIGNAL的方式。如果信號(hào)處理不當(dāng),preStop鉤子可以幫助您解決問題。另一種選擇是用應(yīng)用程序能夠正確處理的信號(hào)(并允許它正常關(guān)閉)從而來替換STOPSIGNAL。

terminationGracePeriodSeconds是關(guān)閉應(yīng)用程序的另一個(gè)重要參數(shù)。它指定應(yīng)用程序正常關(guān)閉的時(shí)間段。如果應(yīng)用程序未在此時(shí)間范圍內(nèi)終止(默認(rèn)為 30 秒),它將收到一個(gè)KILL信號(hào)。因此,如果您認(rèn)為運(yùn)行preStop鉤子和/或關(guān)閉應(yīng)用程序STOPSIGNAL可能需要超過 30 秒,您將需要增加 terminateGracePeriodSeconds 參數(shù)。例如,如果來自 Web 服務(wù)客戶端的某些請(qǐng)求需要很長(zhǎng)時(shí)間才能完成(比如涉及下載大文件的請(qǐng)求),您可能需要增加它。

值得注意的是,preStop hook 有一個(gè)鎖定機(jī)制,即只有在preStop hook 運(yùn)行完畢后才能發(fā)送STOPSIGNAL信號(hào)。同時(shí),在preStop鉤子執(zhí)行期間,terminationGracePeriodSeconds倒計(jì)時(shí)繼續(xù)進(jìn)行。所有由鉤子引起的進(jìn)程以及容器中運(yùn)行的進(jìn)程都將在TerminationSeconds結(jié)束后被終止。

此外,某些應(yīng)用程序具有特定設(shè)置,用于設(shè)置應(yīng)用程序必須終止的截止日期(例如,在Sidekiq 中的--timeout 選項(xiàng))。因此,您必須確保如果應(yīng)用程序有此配置,則它的值略應(yīng)該低于terminationGracePeriodSeconds。

六、預(yù)留資源

調(diào)度器使用 Pod的resources.requests來決定將Pod調(diào)度在哪個(gè)節(jié)點(diǎn)上。例如,無法在沒有足夠空閑(即非請(qǐng)求)資源來滿足Pod資源請(qǐng)求的節(jié)點(diǎn)上調(diào)度Pod。另一方面,resources.limits允許您限制嚴(yán)重超過其各自請(qǐng)求的Pod的資源消耗。

一個(gè)很好的方式是設(shè)置limits等于 requests。將limits設(shè)置為遠(yuǎn)高于requests可能會(huì)導(dǎo)致某些節(jié)點(diǎn)的Pod無法獲取請(qǐng)求的資源的情況。這可能會(huì)導(dǎo)致節(jié)點(diǎn)(甚至節(jié)點(diǎn)本身)上的其他應(yīng)用程序出現(xiàn)故障。Kubernetes 根據(jù)其資源方案為每個(gè)Pod分配一個(gè) QoS 類。然后,K8s 使用 QoS 類來決定應(yīng)該從節(jié)點(diǎn)中驅(qū)逐哪些 Pod。

因此,您必須同時(shí)為 CPU 和內(nèi)存設(shè)置requests 和 limits。如果Linux 內(nèi)核版本早于 5.4(https://engineering.indeedblog.com/blog/2019/12/cpu-throttling-regression-fix/)。在某些情況下,您唯一可以省略的是 CPU 限制(在 EL7/CentOS7 的情況下,如果要支持limits,則內(nèi)核版本必須大于 3.10.0-1062.8.1.el7)。

此外,某些應(yīng)用程序的內(nèi)存消耗往往以無限的方式增長(zhǎng)。一個(gè)很好的例子是用于緩存的 Redis 或基本上“獨(dú)立”運(yùn)行的應(yīng)用程序。為了限制它們對(duì)節(jié)點(diǎn)上其他應(yīng)用程序的影響,您可以(并且應(yīng)該)為要消耗的內(nèi)存量設(shè)置限制。

唯一的問題是,當(dāng)應(yīng)用程序達(dá)到此限制時(shí)應(yīng)用程序?qū)?huì)被KILL。應(yīng)用程序無法預(yù)測(cè)/處理此信號(hào),這可能會(huì)阻止它們正常關(guān)閉。這就是為什么除了 Kubernetes 限制之外,我們強(qiáng)烈建議使用專門針對(duì)于應(yīng)用程序本身的機(jī)制來限制內(nèi)存消耗,使其不會(huì)超過(或接近)在 Pod的limits.memory參數(shù)中設(shè)置的數(shù)值。

這是一個(gè)Redis配置案例,可以幫助您解決這個(gè)問題:

  1. maxmemory 500mb   # if the amount of data exceeds 500 MB... 
  2. maxmemory-policy allkeys-lru   # ...Redis would delete rarely used keys 

至于 Sidekiq,你可以使用 Sidekiq worker killer(https://github.com/klaxit/sidekiq-worker-killer):

  1. require 'sidekiq/worker_killer' 
  2. Sidekiq.configure_server do |config| 
  3. config.server_middleware do |chain| 
  4.   # Terminate Sidekiq correctly when it consumes 500 MB 
  5.   chain.add Sidekiq::WorkerKiller, max_rss: 500 
  6. end 
  7. end 

很明顯,在所有這些情況下,limits.memory需要高于觸發(fā)上述機(jī)制的閾值。

七、探針

在 Kubernetes 中,探針(健康檢查)用于確定是否可以將流量切換到應(yīng)用程序(readiness probes)以及應(yīng)用程序是否需要重新啟動(dòng)(liveness probes)。它們?cè)诟虏渴鸷蛦?dòng)新Pod方面發(fā)揮著重要作用。

首先,我們想為所有探頭類型提供一個(gè)建議:為timeoutSeconds參數(shù)設(shè)置一個(gè)較高的值 。一秒的默認(rèn)值太低了,它將對(duì) readiness Probe 和 liveness probes 產(chǎn)生嚴(yán)重影響。

如果timeoutSeconds太低,應(yīng)用程序響應(yīng)時(shí)間的增加(由于服務(wù)負(fù)載均衡,所有Pod通常同時(shí)發(fā)生)可能會(huì)導(dǎo)致這些Pod從負(fù)載均衡中刪除(在就緒探測(cè)失敗的情況下),或者,更糟糕的是,在級(jí)聯(lián)容器重新啟動(dòng)時(shí)(在活動(dòng)探測(cè)失敗的情況下)。

7.1. 活性探針(liveness probes)

在實(shí)踐中,活性探針的使用并不像您想象的那樣廣泛。它的目的是在應(yīng)用程序被凍結(jié)時(shí)重新啟動(dòng)容器。然而,在現(xiàn)實(shí)生活中,應(yīng)用程序出現(xiàn)死鎖是一個(gè)意外情況,而不是常規(guī)的現(xiàn)象。如果應(yīng)用程序出于某種原因?qū)е逻@種異常的現(xiàn)象(例如,它在數(shù)據(jù)庫(kù)斷開后無法恢復(fù)與數(shù)據(jù)庫(kù)的連接),您必須在應(yīng)用程序中修復(fù)它,而不是“增加”基于 liveness probes 的解決方法。

雖然您可以使用 liveness probes 來檢查這些狀態(tài),但我們建議默認(rèn)情況下不使用 liveness Probe或僅執(zhí)行一些基本的存活的探測(cè),例如探測(cè) TCP 連接(記住設(shè)置大一點(diǎn)的超時(shí)值)。這樣,應(yīng)用程序?qū)⒅匦聠?dòng)以響應(yīng)明顯的死鎖,而不會(huì)進(jìn)入不停的重新啟動(dòng)的死循環(huán)(即重新啟動(dòng)它也無濟(jì)于事)。

不合理的 liveness probes 配置引起的風(fēng)險(xiǎn)是非常嚴(yán)重的。在最常見的情況下, liveness probes 失敗是由于應(yīng)用程序負(fù)載增加(它根本無法在 timeout 參數(shù)指定的時(shí)間內(nèi)完成)或由于當(dāng)前正在檢查(直接或間接)的外部依賴項(xiàng)的狀態(tài)。

在后一種情況下,所有容器都將重新啟動(dòng)。

在最好的情況下,這不會(huì)導(dǎo)致任何結(jié)果,但在最壞的情況下,這將使應(yīng)用程序完全不可用,也可能是長(zhǎng)期不可用。如果大多數(shù)Pod的容器在短時(shí)間內(nèi)重新啟動(dòng),可能會(huì)導(dǎo)致應(yīng)用程序長(zhǎng)期完全不可用(如果它有大量副本)。一些容器可能比其他容器更快地變?yōu)? READY,并且整個(gè)負(fù)載將分布在這個(gè)有限數(shù)量的運(yùn)行容器上。這最終會(huì)導(dǎo)致 liveness probes 超時(shí),也將觸發(fā)更多的重啟。

另外,如果應(yīng)用程序?qū)σ呀⒌倪B接數(shù)有限制并且已達(dá)到該限制,請(qǐng)確保liveness probes不會(huì)停止響應(yīng)。通常,您必須為liveness probes指定一個(gè)單獨(dú)的應(yīng)用程序線程/進(jìn)程來避免此類問題。例如,如果應(yīng)用程序有11個(gè)線程(每個(gè)客戶端一個(gè)線程),則可以將客戶端數(shù)量限制為10個(gè),以確保liveness probes有一個(gè)空閑線程可用。

另外,當(dāng)然,不要向 liveness Probe 添加任何外部依賴項(xiàng)檢查。

7.2. 就緒探針(Readiness probe)

事實(shí)證明,readinessProbe 的設(shè)計(jì)并不是很成功。readinessProbe 結(jié)合了兩個(gè)不同的功能:

  • 它會(huì)在容器啟動(dòng)期間找出應(yīng)用程序是否可用;
  • 它檢查容器成功啟動(dòng)后應(yīng)用程序是否仍然可用。

在實(shí)踐中,絕大多數(shù)情況下都需要第一個(gè)功能,而第二個(gè)功能的使用頻率僅與 liveness Probe 一樣。配置不當(dāng)?shù)?readiness Probe 可能會(huì)導(dǎo)致類似于 liveness Probe 的問題。在最壞的情況下,它們最終還可能導(dǎo)致應(yīng)用程序長(zhǎng)期不可用。

當(dāng) readiness Probe 失敗時(shí),Pod 停止接收流量。在大多數(shù)情況下,這種行為沒什么用,因?yàn)榱髁客ǔ;蚨嗷蛏俚卦?Pod 之間均勻分布。因此,一般來說,readiness Probe 要么在任何地方都有效,要么不能同時(shí)在大量 Pod 上工作。在某些情況下,此類行為可能有用。但是,根據(jù)我的經(jīng)驗(yàn),這也主要是在某些特殊情況下才有用。

盡管如此,readiness Probe 還具有另一個(gè)關(guān)鍵功能:它有助于確定新創(chuàng)建的容器何時(shí)可以處理流量,以免將負(fù)載轉(zhuǎn)發(fā)到尚未準(zhǔn)備好的應(yīng)用程序。這個(gè) readiness Probe 功能在任何時(shí)候都是必要的。

換句話說,readiness Probe的一個(gè)功能需求量很大,而另一個(gè)功能根本不需要。startup Probe的引入解決了這一難題。它最早出現(xiàn)在Kubernetes 1.16中,在v1.18中成為beta版,在v1.20中保持穩(wěn)定。因此,最好使用readiness Probe檢查應(yīng)用程序在Kubernetes 1.18以下版本中是否已就緒,而在Kubernetes 1.18及以上版本中是否已就緒則推薦使用startup Probe。同樣,如果在應(yīng)用程序啟動(dòng)后需要停止單個(gè)Pod的流量,可以使用Kubernetes 1.18+中的readiness Probe。

7.3. 啟動(dòng)探針

startup Probe 檢查容器中的應(yīng)用程序是否準(zhǔn)備就緒。然后它將當(dāng)前 Pod 標(biāo)記為準(zhǔn)備好接收流量或繼續(xù)更新/重新啟動(dòng)部署。與 readiness Probe 不同,startup Probe 在容器啟動(dòng)后停止工作。

我們不建議使用 startup Probe 來檢查外部依賴:它的失敗會(huì)觸發(fā)容器重啟,這最終可能導(dǎo)致 Pod 處于CrashLoopBackOff狀態(tài)。在這種狀態(tài)下,嘗試重新啟動(dòng)失敗的容器之間的延遲可能高達(dá)五分鐘。這可能會(huì)導(dǎo)致不必要的停機(jī)時(shí)間,因?yàn)楸M管應(yīng)用程序已準(zhǔn)備好重新啟動(dòng),但容器會(huì)繼續(xù)等待,直到因CrashLoopBackOff而嘗試重新啟動(dòng)的時(shí)間段結(jié)束。

如果您的應(yīng)用程序接收流量并且您的 Kubernetes 版本為 1.18 或更高版本,則您應(yīng)該使用 startup Probe。

另請(qǐng)注意,增加failureThreshold配置而不是設(shè)置initialDelaySeconds是配置探針的首選方法。這將使容器盡快可用。

八、檢查外部依賴

如您所知,readiness Probe 通常用于檢查外部依賴項(xiàng)(例如數(shù)據(jù)庫(kù))。雖然這種方法理應(yīng)存在,但建議您將檢查外部依賴項(xiàng)的方法與檢查 Pod 中的應(yīng)用程序是否滿負(fù)荷運(yùn)行(并切斷向其發(fā)送流量)的方法分開也是個(gè)好主意)。

您可以使用initContainers在運(yùn)行主容器的 startupProbe/readinessProbe 之前檢查外部依賴項(xiàng)。很明顯,在這種情況下,您將不再需要使用 readiness Probe 檢查外部依賴項(xiàng)。initContainers不需要更改應(yīng)用程序代碼。您不需要嵌入額外的工具來使用它們來檢查應(yīng)用程序容器中的外部依賴項(xiàng)。通常,它們相當(dāng)容易實(shí)現(xiàn):

  1. initContainers: 
  2.   - name: wait-postgres 
  3.     image: postgres:12.1-alpine 
  4.     command: 
  5.     - sh 
  6.     - -ec 
  7.     - | 
  8.       until (pg_isready -h example.org -p 5432 -U postgres); do 
  9.         sleep 1 
  10.       done 
  11.     resources: 
  12.       requests: 
  13.         cpu: 50m 
  14.         memory: 50Mi 
  15.       limits: 
  16.         cpu: 50m 
  17.         memory: 50Mi 
  18.   - name: wait-redis 
  19.     image: redis:6.0.10-alpine3.13 
  20.     command: 
  21.     - sh 
  22.     - -ec 
  23.     - | 
  24.       until (redis-cli -u redis://redis:6379/0 ping); do 
  25.         sleep 1 
  26.       done 
  27.     resources: 
  28.       requests: 
  29.         cpu: 50m 
  30.         memory: 50Mi 
  31.       limits: 
  32.         cpu: 50m 
  33.         memory: 50Mi 

九、完整示例

下面是無狀態(tài)應(yīng)用程序的生產(chǎn)級(jí)部署的完整示例,其中包含上面提供的所有建議。可以作為大家生成的參考。

您將需要 Kubernetes 1.18 或更高版本以及內(nèi)核版本為 5.4 或更高版本的基于 Ubuntu/Debian 的Kubernetes節(jié)點(diǎn)。

  1. apiVersion: apps/v1 
  2. kind: Deployment 
  3. metadata: 
  4. name: testapp 
  5. spec: 
  6. replicas: 10 
  7. selector: 
  8.   matchLabels: 
  9.     app: testapp 
  10. template: 
  11.   metadata: 
  12.     labels: 
  13.       app: testapp 
  14.   spec: 
  15.     affinity: 
  16.       PodAntiAffinity: 
  17.         preferredDuringSchedulingIgnoredDuringExecution: 
  18.         - PodAffinityTerm: 
  19.             labelSelector: 
  20.               matchLabels: 
  21.                 app: testapp 
  22.             topologyKey: kubernetes.io/hostname 
  23.     priorityClassName: production-medium 
  24.     terminationGracePeriodSeconds: 40 
  25.     initContainers: 
  26.     - name: wait-postgres 
  27.       image: postgres:12.1-alpine 
  28.       command: 
  29.       - sh 
  30.       - -ec 
  31.       - | 
  32.         until (pg_isready -h example.org -p 5432 -U postgres); do 
  33.           sleep 1 
  34.         done 
  35.       resources: 
  36.         requests: 
  37.           cpu: 50m 
  38.           memory: 50Mi 
  39.         limits: 
  40.           cpu: 50m 
  41.           memory: 50Mi 
  42.     containers: 
  43.     - name: backend 
  44.       image: my-app-image:1.11.1 
  45.       command: 
  46.       - run 
  47.       - app 
  48.       - --trigger-graceful-shutdown-if-memory-usage-is-higher-than 
  49.       - 450Mi 
  50.       - --timeout-seconds-for-graceful-shutdown 
  51.       - 35s 
  52.       startupProbe: 
  53.         httpGet: 
  54.           path: /simple-startup-check-no-external-dependencies 
  55.           port: 80 
  56.         timeoutSeconds: 7 
  57.         failureThreshold: 12 
  58.       lifecycle: 
  59.         preStop: 
  60.           exec
  61.             ["sh""-ec""#command to shutdown gracefully if needed"
  62.       resources: 
  63.         requests: 
  64.           cpu: 200m 
  65.           memory: 500Mi 
  66.         limits: 
  67.           cpu: 200m 
  68.           memory: 500Mi 

十、PodDisruptionBudget

PodDisruptionBudget(PDB:https://kubernetes.io/docs/concepts/workloads/Pods/disruptions/#Pod-disruption-budgets)機(jī)制是在生產(chǎn)環(huán)境中運(yùn)行的應(yīng)用程序的必備工具。它為您提供了一種方法,可以指定同時(shí)不可用的應(yīng)用程序Pod數(shù)量的最大限制。在上文中,我們討論了一些有助于避免潛在風(fēng)險(xiǎn)情況的方法:運(yùn)行多個(gè)應(yīng)用程序副本,指定PodAntiAffinity(以防止多個(gè)Pod被分配到同一節(jié)點(diǎn)),等等。

但是,您可能會(huì)遇到多個(gè) K8s 節(jié)點(diǎn)同時(shí)不可用的情況。例如,假設(shè)您決定將實(shí)例節(jié)點(diǎn)切換升級(jí)到更高配置的的實(shí)例節(jié)點(diǎn)。除此之外可能還有其他原因,本文不做更詳細(xì)的描述。最終的問題都是多個(gè)節(jié)點(diǎn)同時(shí)被刪除。你可能會(huì)認(rèn)為,Kubernetes里的一切都是曇花一現(xiàn)的!哪怕節(jié)點(diǎn)異常或被刪除,節(jié)點(diǎn)上面的Pod 將會(huì)被自動(dòng)重建到其他節(jié)點(diǎn)上,因此,這又會(huì)有什么關(guān)系呢?好吧,讓我們來繼續(xù)往下看看。

假設(shè)應(yīng)用程序有三個(gè)副本。負(fù)載在它們之間均勻分布,而 Pod 則分布在節(jié)點(diǎn)之間。在這種情況下,即使其中一個(gè)副本出現(xiàn)故障,應(yīng)用程序也將繼續(xù)運(yùn)行。然而,兩個(gè)副本的故障則會(huì)導(dǎo)致服務(wù)整體降級(jí):一個(gè)單獨(dú)的 Pod 根本無法單獨(dú)處理整個(gè)負(fù)載。客戶端將開始收到 5XX 錯(cuò)誤。(當(dāng)然,您可以在 nginx 容器中設(shè)置速率限制;在這種情況下,錯(cuò)誤將是429 Too Many Requests。不過,服務(wù)仍然會(huì)降級(jí))。

這就是 PodDisruptionBudget 可以提供幫助的地方。我們來看看它的配置清單:

  1. apiVersion: policy/v1beta1 
  2. kind: PodDisruptionBudget 
  3. metadata: 
  4. name: app-pdb 
  5. spec: 
  6. maxUnavailable: 1 
  7. selector: 
  8.   matchLabels: 
  9.     app: app 

上述的配置清單非常簡(jiǎn)單;你可能熟悉它的大部分配置,maxUnavailable是其中最有趣的。此字段描述可同時(shí)不可用的最大 Pod 數(shù)。這可以是數(shù)字也可以是百分比。

假設(shè)為應(yīng)用程序配置了 PDB。如果出于某種原因,兩個(gè)或多個(gè)節(jié)點(diǎn)開始驅(qū)逐應(yīng)用程序 Pod,會(huì)發(fā)生什么?上述 PDB 一次只允許驅(qū)逐一個(gè) Pod。因此,第二個(gè)節(jié)點(diǎn)會(huì)等到副本數(shù)量恢復(fù)到驅(qū)逐前的水平,然后才會(huì)驅(qū)逐第二個(gè)副本。

作為替代方案,您還可以設(shè)置minAvailable參數(shù)。例如:

  1. apiVersion: policy/v1beta1 
  2. kind: PodDisruptionBudget 
  3. metadata: 
  4. name: app-pdb 
  5. spec: 
  6. minAvailable: 80% 
  7. selector: 
  8.   matchLabels: 
  9.     app: app 

此參數(shù)可確保集群中至少有 80% 的副本始終可用。因此,如有必要,只能驅(qū)逐 20% 的副本。minAvailable可以是絕對(duì)數(shù)或百分比。

但有一個(gè)問題:集群中必須有足夠的節(jié)點(diǎn)滿足PodAntiAffinity條件。否則,您可能會(huì)遇到副本被逐出的情況,但由于缺少合適的節(jié)點(diǎn),調(diào)度程序無法重新部署它。因此,排空一個(gè)節(jié)點(diǎn)將需要很長(zhǎng)時(shí)間才能完成,并且會(huì)為您提供兩個(gè)應(yīng)用程序副本而不是三個(gè)。當(dāng)然,你可以使用用命令kubectl describe來查看一個(gè)一致在等待中的Pod,看看發(fā)生了什么事情,并解決問題。但是,最好還是盡量去避免這種情況發(fā)生。

總而言之,請(qǐng)始終為系統(tǒng)的關(guān)鍵組件配置 PDB。

十一、HorizontalPodAutoscaler

讓我們考慮另一種情況:如果應(yīng)用程序的意外負(fù)載明顯高于平時(shí),會(huì)發(fā)生什么情況?是的,您可以手動(dòng)擴(kuò)展集群,但這不是我們推薦使用的方法。

這就是HorizontalPodAutoscaler(HPA,https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/)的用武之地。借助 HPA,您可以選擇一個(gè)指標(biāo)并將其用作觸發(fā)器,根據(jù)指標(biāo)的值自動(dòng)向上/向下擴(kuò)展集群。想象一下,在一個(gè)安靜的夜晚,您的集群突然因流量大幅上升而爆炸,例如,Reddit 用戶發(fā)現(xiàn)了您的服務(wù),CPU 負(fù)載(或其他一些 Pod 指標(biāo))增加,達(dá)到閾值,然后 HPA 開始發(fā)揮作用。它擴(kuò)展了集群,從而在大量 Pod 之間均勻分配負(fù)載。

也正是多虧了這一點(diǎn),所有傳入的請(qǐng)求都被成功處理。同樣重要的是,在負(fù)載恢復(fù)到平均水平后,HPA 會(huì)縮小集群以降低基礎(chǔ)設(shè)施成本。這聽起來很不錯(cuò),不是嗎?

讓我們看看 HPA 是如何計(jì)算要添加的副本數(shù)量的。這是官方文檔中提供的公式:

  1. desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )] 

現(xiàn)在假設(shè):

  • 當(dāng)前副本數(shù)為3;
  • 當(dāng)前度量值為 100;
  • 度量閾值為 60。

在這種情況下,結(jié)果則為3 * ( 100 / 60 ),即“大約”5 個(gè)副本(HPA 會(huì)將結(jié)果向上舍入)。因此,應(yīng)用程序?qū)@得額外的另外兩個(gè)副本。當(dāng)然,HPA操作還會(huì)繼續(xù):如果負(fù)載減少,HPA 將繼續(xù)計(jì)算所需的副本數(shù)(使用上面的公式)來縮小集群。

另外,還有一個(gè)是我們最關(guān)心的部分。你應(yīng)該使用什么指標(biāo)?首先想到的是主要指標(biāo),例如 CPU 或內(nèi)存利用率。如果您的 CPU 和內(nèi)存消耗與負(fù)載成正比,這將起作用。但是如果 Pod 處理不同的請(qǐng)求呢?有些請(qǐng)求需要較大的 CPU 周期,有些可能會(huì)消耗大量?jī)?nèi)存,還有一些只需要最少的資源。

例如,讓我們看一看RabbitMQ隊(duì)列和處理它的實(shí)例。假設(shè)隊(duì)列中有十條消息。監(jiān)控顯示消息正在穩(wěn)定且定期地退出隊(duì)列(按照RabbitMQ的術(shù)語)。也就是說,我們覺得隊(duì)列中平均有10條消息是可以的。但是負(fù)載突然增加,隊(duì)列增加到100條消息。然而,worker的CPU和內(nèi)存消耗保持不變:他們穩(wěn)定地處理隊(duì)列,在隊(duì)列中留下大約80-90條消息。

但是如果我們使用一個(gè)自定義指標(biāo)來描述隊(duì)列中的消息數(shù)量呢?讓我們按如下方式配置我們的自定義指標(biāo):

  • 當(dāng)前副本數(shù)為3;
  • 當(dāng)前度量值為 80;
  • 度量閾值為 15。

因此,3 * ( 80 / 15 ) = 16。在這種情況下,HPA 可以將 worker 的數(shù)量增加到 16,并且它們會(huì)快速處理隊(duì)列中的所有消息(此時(shí) HPA 將再次減少它們的數(shù)量)。但是,必須準(zhǔn)備好所有必需的基礎(chǔ)架構(gòu)以容納此數(shù)量的 Pod。也就是說,它們必須適合現(xiàn)有節(jié)點(diǎn),或者在使用Cluster Autoscaler(https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler)的情況下,必須由基礎(chǔ)設(shè)施供應(yīng)商(云提供商)提供新節(jié)點(diǎn)。換句話說,我們又回到規(guī)劃集群資源了。

現(xiàn)在讓我們來看看一些清單:

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: php-apache 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: php-apache 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. targetCPUUtilizationPercentage: 50 

這個(gè)很簡(jiǎn)單。一旦 CPU 負(fù)載達(dá)到 50%,HPA 就會(huì)開始將副本數(shù)量擴(kuò)展到最多 10 個(gè)。

下面是一個(gè)比較有趣的案例:

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: worker 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: worker 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. metrics: 
  13. - type: External 
  14.   external: 
  15.     metric: 
  16.       name: queue_messages 
  17.     target: 
  18.       type: AverageValue 
  19.       averageValue: 15 

請(qǐng)注意,在此示例中,HPA 使用自定義指標(biāo)(https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#support-for-custom-metrics)。它將根據(jù)隊(duì)列的大小(queue_messages指標(biāo))做出擴(kuò)展決策。鑒于隊(duì)列中的平均消息數(shù)為 10,我們將閾值設(shè)置為 15。這樣可以更準(zhǔn)確地管理副本數(shù)。如您所見,與基于 CPU 的指標(biāo)相比,自定義指標(biāo)可實(shí)現(xiàn)更準(zhǔn)確的集群自動(dòng)縮放。

附加的功能:

HPA 配置選項(xiàng)是多樣化。例如,您可以組合不同的指標(biāo)。在下面的清單中,同時(shí)使用CPU 利用率和隊(duì)列大小來觸發(fā)擴(kuò)展決策。

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: worker 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: worker 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. metrics: 
  13. - type: Resource 
  14.   resource: 
  15.     name: cpu 
  16.     target: 
  17.       type: Utilization 
  18.       averageUtilization: 50 
  19. - type: External 
  20.   external: 
  21.     metric: 
  22.       name: queue_messages 
  23.     target: 
  24.       type: AverageValue 
  25.       averageValue: 15 

這種情況下,HPA又該采用什么計(jì)算算法?好吧,它使用計(jì)算出的最高副本數(shù),而不考慮所利用的指標(biāo)如何。例如,如果基于 CPU 指標(biāo)的值顯示需要添加 5 個(gè)副本,而基于隊(duì)列大小的指標(biāo)值僅給出 3 個(gè) Pod,則 HPA 將使用較大的值并添加 5 個(gè) Pod。

隨著Kubernetes 1.18的發(fā)布,你現(xiàn)在有能力來定義scaleUp和scaleDown方案(https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#support-for-configurable-scaling-behavior)。例如:

  1. behavior: 
  2. scaleDown: 
  3.   stabilizationWindowSeconds: 60 
  4.   policies: 
  5.   - type: Percent 
  6.     value: 5 
  7.     periodSeconds: 20 
  8.   - type: Pods 
  9.     value: 5 
  10.     periodSeconds: 60 
  11.   selectPolicy: Min 
  12. scaleUp: 
  13.   stabilizationWindowSeconds: 0 
  14.   policies: 
  15.   - type: Percent 
  16.     value: 100 
  17.     periodSeconds: 10 

正如您在上面的清單中看到的,它有兩個(gè)部分。第一個(gè) ( scaleDown) 定義縮小參數(shù),而第二個(gè) ( scaleUp) 用于放大。每個(gè)部分都有stabilizationWindowSeconds. 這有助于防止在副本數(shù)量持續(xù)波動(dòng)時(shí)出現(xiàn)所謂的“抖動(dòng)”(或不必要的縮放)。這個(gè)參數(shù)本質(zhì)上是作為副本數(shù)量改變后的超時(shí)時(shí)間。

現(xiàn)在讓我們談?wù)勥@兩者的策略。scaleDown策略允許您指定在type: Percent特定時(shí)間段內(nèi)縮減的 Pod 百分比 。如果負(fù)載具有周期性現(xiàn)象,您必須做的是降低百分比并增加持續(xù)時(shí)間。在這種情況下,隨著負(fù)載的減少,HPA 不會(huì)立即殺死大量 Pod(根據(jù)其公式),而是會(huì)逐漸殺死對(duì)應(yīng)的Pod。此外,您可以設(shè)置type: Pods在指定時(shí)間段內(nèi)允許 HPA 殺死的最大 Pod 數(shù)量 。

注意selectPolicy: Min參數(shù)。這意味著 HPA 使用影響最小 Pod 數(shù)量的策略。因此,如果百分比值(上例中的 5%)小于數(shù)字替代值(上例中的 5 個(gè) Pod),HPA 將選擇百分比值。相反,selectPolicy: Max策略會(huì)產(chǎn)生相反的效果。

scaleUp部分中使用了類似的參數(shù)。請(qǐng)注意,在大多數(shù)情況下,集群必須(幾乎)立即擴(kuò)容,因?yàn)榧词故禽p微的延遲也會(huì)影響用戶及其體驗(yàn)。因此,在本節(jié)中StabilizationWindowsSeconds設(shè)置為0。如果負(fù)載具有循環(huán)模式,HPA可以在必要時(shí)將副本計(jì)數(shù)增加到maxReplicas(如HPA清單中定義的)。我們的策略允許HPA每10秒(periodSeconds:10)向當(dāng)前運(yùn)行的副本添加多達(dá)100%的副本。

最后,您可以將selectPolicy參數(shù)設(shè)置Disabled為關(guān)閉給定方向的縮放:

  1. behavior: 
  2. scaleDown: 
  3.   selectPolicy: Disabled 

大多數(shù)情況下,當(dāng) HPA 未按預(yù)期工作時(shí),才會(huì)使用策略。策略帶來了靈活性的同時(shí),也使配置清單更難掌握。

最近,HPA能夠跟蹤一組 Pod 中單個(gè)容器的資源使用情況(在 Kubernetes 1.20 中作為 alpha 功能引入)(https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#container-resource-metrics)。

HPA:總結(jié)

讓我們以完整的 HPA 清單示例結(jié)束本段:

  1. apiVersion: autoscaling/v1 
  2. kind: HorizontalPodAutoscaler 
  3. metadata: 
  4. name: worker 
  5. spec: 
  6. scaleTargetRef: 
  7.   apiVersion: apps/v1 
  8.   kind: Deployment 
  9.   name: worker 
  10. minReplicas: 1 
  11. maxReplicas: 10 
  12. metrics: 
  13. - type: External 
  14.   external: 
  15.     metric: 
  16.       name: queue_messages 
  17.     target: 
  18.       type: AverageValue 
  19.       averageValue: 15 
  20. behavior: 
  21.   scaleDown: 
  22.     stabilizationWindowSeconds: 60 
  23.     policies: 
  24.     - type: Percent 
  25.       value: 5 
  26.       periodSeconds: 20 
  27.     - type: Pods 
  28.       value: 5 
  29.       periodSeconds: 60 
  30.     selectPolicy: Min 
  31.   scaleUp: 
  32.     stabilizationWindowSeconds: 0 
  33.     policies: 
  34.     - type: Percent 
  35.       value: 100 
  36.       periodSeconds: 10 

請(qǐng)注意,此示例僅供參考。您將需要對(duì)其進(jìn)行調(diào)整以適應(yīng)您自己的操作的具體情況。

Horizontal Pod Autoscaler 簡(jiǎn)介:HPA 非常適合生產(chǎn)環(huán)境。但是,在為 HPA 選擇指標(biāo)時(shí),您必須謹(jǐn)慎并盡量多的考慮現(xiàn)狀。錯(cuò)誤的度量標(biāo)準(zhǔn)或錯(cuò)誤的閾值將導(dǎo)致資源浪費(fèi)(來自不必要的副本)或服務(wù)降級(jí)(如果副本數(shù)量不夠)。密切監(jiān)視應(yīng)用程序的行為并對(duì)其進(jìn)行測(cè)試,直到達(dá)到正確的平衡。

十二、VerticalPodAutoscaler

VPA(https://github.com/kubernetes/autoscaler/tree/master/vertical-Pod-autoscaler)分析容器的資源需求并設(shè)置(如果啟用了相應(yīng)的模式)它們的限制和請(qǐng)求。

假設(shè)您部署了一個(gè)新的應(yīng)用程序版本,其中包含一些新功能,結(jié)果發(fā)現(xiàn),比如說,導(dǎo)入的庫(kù)是一個(gè)巨大的資源消耗者,或者代碼沒有得到很好的優(yōu)化。換句話說,應(yīng)用程序資源需求增加了。您在測(cè)試期間沒有注意到這一點(diǎn)(因?yàn)楹茈y像在生產(chǎn)中那樣加載應(yīng)用程序)。

當(dāng)然,在更新開始之前,相關(guān)的請(qǐng)求和限制已經(jīng)為應(yīng)用程序設(shè)置好了。現(xiàn)在,應(yīng)用程序達(dá)到內(nèi)存限制,其Pod由于OOM而被殺死。VPA可以防止這種情況!乍一看,VPA看起來是一個(gè)很好的工具,應(yīng)該是被廣泛的使用的。但在現(xiàn)實(shí)生活中,情況并非是如此,下面會(huì)簡(jiǎn)單說明一下。

主要問題(尚未解決)是Pod需要重新啟動(dòng)才能使資源更改生效。在未來,VPA將在不重啟Pod的情況下對(duì)其進(jìn)行修改,但目前,它根本無法做到這一點(diǎn)。但是不用擔(dān)心。如果您有一個(gè)“編寫良好”的應(yīng)用程序,并且隨時(shí)準(zhǔn)備重新部署(例如,它有大量副本;它的PodAntiAffinity、PodDistributionBudget、HorizontalPodAutoscaler都經(jīng)過仔細(xì)配置,等等),那么這并不是什么大問題。在這種情況下,您(可能)甚至不會(huì)注意到VPA活動(dòng)。

遺憾的是,可能會(huì)出現(xiàn)其他不太令人愉快的情況,如:應(yīng)用程序重新部署得不太好,由于缺少節(jié)點(diǎn),副本的數(shù)量受到限制,應(yīng)用程序作為StatefulSet運(yùn)行,等等。在最壞的情況下,Pod的資源消耗會(huì)因負(fù)載增加而增加,HPA開始擴(kuò)展集群,然后突然,VPA開始修改資源參數(shù)并重新啟動(dòng)Pod。因此,高負(fù)載分布在其余的Pod中。其中一些可能會(huì)崩潰,使事情變得更糟,并導(dǎo)致失敗的連鎖反應(yīng)。

這就是為什么深入了解各種 VPA 操作模式很重要。讓我們從最簡(jiǎn)單的開始——“Off模式”。

Off模式:

該模式所做的只是計(jì)算Pod的資源消耗并提出建議。我們?cè)诖蠖鄶?shù)情況下都使用這種模式(我們建議使用這種模式)。但首先,讓我們看幾個(gè)例子。

一些基本清單如下:

  1. apiVersion: autoscaling.k8s.io/v1 
  2. kind: VerticalPodAutoscaler 
  3. metadata: 
  4. name: my-app-vpa 
  5. spec: 
  6. targetRef: 
  7.   apiVersion: "apps/v1" 
  8.   kind: Deployment 
  9.   name: my-app 
  10. updatePolicy:  
  11.   updateMode: "Recreate" 
  12.   containerPolicies: 
  13.     - containerName: "*" 
  14.       minAllowed: 
  15.         cpu: 100m 
  16.         memory: 250Mi 
  17.       maxAllowed: 
  18.         cpu: 1 
  19.         memory: 500Mi 
  20.       controlledResources: ["cpu""memory"
  21.       controlledValues: RequestsAndLimits 

我們不會(huì)詳細(xì)介紹此清單的參數(shù):文章(https://povilasv.me/vertical-Pod-autoscaling-the-definitive-guide/)詳細(xì)描述了 VPA 的功能和細(xì)節(jié)。簡(jiǎn)而言之,我們指定 VPA 目標(biāo) ( targetRef) 并選擇更新策略。

此外,我們指定了 VPA 可以使用的資源的上限和下限。主要關(guān)注updateMode部分。在“重新創(chuàng)建”或“自動(dòng)”模式下,VPA 將重新創(chuàng)建 Pod ,因此需要考慮由此帶來的短暫停服風(fēng)險(xiǎn)(直到上述用于 Pod的 資源參數(shù)更新的補(bǔ)丁可用)。由于我們不想要它,我們使用“off”模式:

  1. apiVersion: autoscaling.k8s.io/v1 
  2. kind: VerticalPodAutoscaler 
  3. metadata: 
  4. name: my-app-vpa 
  5. spec: 
  6. targetRef: 
  7.   apiVersion: "apps/v1" 
  8.   kind: Deployment 
  9.   name: my-app 
  10. updatePolicy:  
  11.   updateMode: "Off"   # !!! 
  12. resourcePolicy: 
  13.   containerPolicies: 
  14.     - containerName: "*" 
  15.       controlledResources: ["cpu""memory"

VPA 開始收集指標(biāo)。您可以使用kubectl describe vpa命令查看建議(只需讓 VPA 運(yùn)行幾分鐘即可):

  1. Recommendation: 
  2.   Container Recommendations: 
  3.     Container Name: nginx 
  4.     Lower Bound: 
  5.       Cpu:     25m 
  6.       Memory: 52428800 
  7.     Target: 
  8.       Cpu:     25m 
  9.       Memory: 52428800 
  10.     Uncapped Target: 
  11.       Cpu:     25m 
  12.       Memory: 52428800 
  13.     Upper Bound: 
  14.       Cpu:     25m 
  15.       Memory: 52428800 

運(yùn)行幾天(一周、一個(gè)月等)后,VPA 建議將更加準(zhǔn)確。然后是在應(yīng)用程序清單中調(diào)整限制的最佳時(shí)機(jī)。這樣,您可以避免由于缺乏資源而導(dǎo)致的 OOM 終止并節(jié)省基礎(chǔ)設(shè)施(如果初始請(qǐng)求/限制太高)。

現(xiàn)在,讓我們談?wù)勈褂?VPA 的一些細(xì)節(jié)。

其他 VPA 模式:

請(qǐng)注意,在“Initial”模式下,VPA 在 Pod 啟動(dòng)時(shí)分配資源,以后不再更改它們。因此,如果過去一周的負(fù)載相對(duì)較低,VPA 將為新創(chuàng)建的 Pod 設(shè)置較低的請(qǐng)求/限制。如果負(fù)載突然增加,可能會(huì)導(dǎo)致問題,因?yàn)檎?qǐng)求/限制將遠(yuǎn)低于此類負(fù)載所需的數(shù)量。如果您的負(fù)載均勻分布并以線性方式增長(zhǎng),則此模式可能會(huì)派上用場(chǎng)。

在“Auto”模式下,VPA 重新創(chuàng)建 Pod。因此,應(yīng)用程序必須正確處理重新啟動(dòng)。如果它不能正常關(guān)閉(即通過正確關(guān)閉現(xiàn)有連接等),您很可能會(huì)捕獲一些可避免的 5XX 錯(cuò)誤。很少建議使用帶有 StatefulSet 的 Auto 模式:想象一下 VPA 試圖將 PostgreSQL 資源添加到生產(chǎn)中……

至于開發(fā)環(huán)境,您可以自由試驗(yàn)以找到您可以接受的(稍后)在生產(chǎn)中使用的資源級(jí)別。假設(shè)您想在“Initial”模式下使用 VPA,并且我們?cè)赗edis集群中使用maxmemory參數(shù) 。您很可能需要更改它以根據(jù)您的需要進(jìn)行調(diào)整。問題是 Redis 不關(guān)心 cgroups 級(jí)別的限制。

換句話說,如果您的 Pod 的內(nèi)存上限為 1GB,那么maxmemory 設(shè)置的是2GB ,您將面臨很大的風(fēng)險(xiǎn)。但是你怎么能設(shè)置maxmemory成和limit一樣呢?嗯,有辦法!您可以使用 VPA 推薦的值:

  1. apiVersion: apps/v1 
  2. kind: Deployment 
  3. metadata: 
  4. name: redis 
  5. labels: 
  6.   app: redis 
  7. spec: 
  8. replicas: 1 
  9. selector: 
  10.   matchLabels: 
  11.     app: redis 
  12. template: 
  13.   metadata: 
  14.     labels: 
  15.       app: redis 
  16.   spec: 
  17.     containers: 
  18.     - name: redis 
  19.       image: redis:6.2.1 
  20.       ports: 
  21.       - containerPort: 6379 
  22.       resources: 
  23.           requests: 
  24.             memory: "100Mi" 
  25.             cpu: "256m" 
  26.           limits: 
  27.             memory: "100Mi" 
  28.             cpu: "256m" 
  29.       env: 
  30.         - name: MY_MEM_REQUEST 
  31.           valueFrom: 
  32.             resourceFieldRef: 
  33.               containerName: app 
  34.               resource: requests.memory 
  35.         - name: MY_MEM_LIMIT 
  36.           valueFrom: 
  37.             resourceFieldRef: 
  38.               containerName: app 
  39.               resource: limits.memory 

您可以使用環(huán)境變量來獲取內(nèi)存限制(并從應(yīng)用程序需求中減去 10%)并將結(jié)果值設(shè)置為maxmemory。您可能需要對(duì)sed用于處理 Redis 配置的 init 容器做一些事情,因?yàn)槟J(rèn)的 Redis 容器映像不支持maxmemory使用環(huán)境變量進(jìn)行傳遞。盡管如此,這個(gè)解決方案還是很實(shí)用的。

最后,我想將您的注意力轉(zhuǎn)移到 VPA 一次性驅(qū)逐所有 DaemonSet Pod 的事實(shí)。我們目前正在開發(fā)修復(fù)此問題的補(bǔ)丁(https://github.com/kubernetes/kubernetes/pull/98307)。

最終的 VPA 建議:

“OFF”模式適用于大多數(shù)情況。您可以在開發(fā)環(huán)境中嘗試“Auto”和“Initial”模式。

只有在您已經(jīng)積累了大量的經(jīng)驗(yàn)并對(duì)其進(jìn)行了徹底測(cè)試的情況下,才能在生產(chǎn)中使用VPA。此外,你必須清楚地了解你在做什么以及為什么要這樣做。

與此同時(shí),我們熱切期待 Pod 資源的熱(免重啟)更新功能。

請(qǐng)注意,同時(shí)使用 HPA 和 VPA 存在一些限制。例如,如果基于 CPU 或基于內(nèi)存的指標(biāo)用作觸發(fā)器,則 VPA 不應(yīng)與 HPA 一起使用。原因是當(dāng)達(dá)到閾值時(shí),VPA 會(huì)增加資源請(qǐng)求/限制,而 HPA 會(huì)添加新副本。

因此,負(fù)載將急劇下降,并且該過程將反向進(jìn)行,從而導(dǎo)致“抖動(dòng)”。官方文件(https://github.com/kubernetes/autoscaler/tree/master/vertical-Pod-autoscaler#known-limitations)更清楚地說明了現(xiàn)有的限制。。

結(jié)論:

我們分享了一些 Kubernetes 高可用部署應(yīng)用的的一些建議以及相關(guān)的案例,這些機(jī)制有助于部署高可用性應(yīng)用程序。我們討論了調(diào)度器操作、更新策略、優(yōu)先級(jí)、探針等方面。最后一部分我們深入討論了剩下的三個(gè)關(guān)鍵主題:PodDisruptionBudget、HorizontalPodAutoscaler 和 VerticalPodAutoscaler。

問題中提到的大量案例都是基于我們生成的真實(shí)場(chǎng)景,如使用,請(qǐng)根據(jù)自生的環(huán)境進(jìn)行調(diào)整。

通過本文,我們也希望讀者能夠根據(jù)自有的環(huán)境進(jìn)行驗(yàn)證,能夠一起分享各自的生成經(jīng)驗(yàn),能偶一起推進(jìn)Kubernetes相關(guān)技術(shù)的發(fā)展與進(jìn)步。再次也感謝讀者能夠花費(fèi)大量的時(shí)間認(rèn)真讀完本文。

參考文章: 

  • https://blog.flant.com/best-practices-for-deploying-highly-available-apps-in-kubernetes-part-1/
  • https://blog.flant.com/best-practices-for-deploying-highly-available-apps-in-kubernetes-part-2/
  • Migrating your app to Kubernetes: what to do with files?
  • ConfigMaps in Kubernetes: how they work and what you should remember
  • Best practices for deploying highly available apps in Kubernetes. Part 1
  • Comparing Ingress controllers for Kubernetes
  • How we enjoyed upgrading a bunch of Kubernetes clusters from v1.16 to v1.19
  • Best practices for deploying highly available apps in Kubernetes. Part 2
責(zé)任編輯:武曉燕 來源: 新鈦云服
相關(guān)推薦

2011-11-25 09:55:00

MPLSWeb應(yīng)用加速WAN優(yōu)化

2020-12-11 19:06:03

Kubernetes工具應(yīng)用程序

2023-06-04 17:28:19

數(shù)字驅(qū)動(dòng)開發(fā)Azure

2017-08-08 11:14:47

AzureKubernetes多容器應(yīng)用程序

2021-03-17 10:05:42

KubernetesRedis數(shù)據(jù)庫(kù)

2021-07-30 10:11:14

HelmKubernetes包管理

2022-07-08 14:17:18

Kubernetes集群高可用Linux

2024-03-05 08:00:00

人工智能Kuberneste

2022-08-31 08:30:32

kubernetesMetalLB

2020-03-24 14:45:17

程序員技能開發(fā)者

2020-11-25 15:49:38

Kubernetes程序技巧

2025-04-28 01:22:00

2025-03-19 09:04:39

2023-05-25 16:20:03

Kubernetes集群

2021-03-04 13:10:32

KubernetesRedisLinux

2012-05-29 11:02:23

ibmdw

2023-08-21 15:28:36

云原生Kubernetes

2010-03-09 13:27:23

Web 2.0應(yīng)用程序

2023-10-27 12:11:33

2009-08-05 10:16:54

部署ASP.NET應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩视频 中文字幕 | 日本黄色大片免费 | 日韩av一区二区在线观看 | 欧美久久天堂 | va精品 | 人人看人人草 | 亚洲欧美中文字幕在线观看 | 青青草视频免费观看 | 7777奇米影视 | 91久久| 精品久 | 国产精品免费一区二区三区四区 | 色妞av| 视频一区中文字幕 | 成人午夜免费视频 | 天堂成人av| 亚洲欧美在线视频 | 亚洲顶级毛片 | 国产丝袜一区二区三区免费视频 | 国产高清在线精品一区二区三区 | 亚洲一一在线 | 国产一区二区在线视频 | 91精品久久久久久久久中文字幕 | 欧美精品在线播放 | 一本一道久久a久久精品蜜桃 | 先锋影音资源网站 | japanhd成人 | 高清人人天天夜夜曰狠狠狠狠 | 国产亚洲一区二区在线观看 | 欧美激情a∨在线视频播放 成人免费共享视频 | 精品欧美一区二区久久久伦 | 中文字幕在线观看视频一区 | 欧美国产视频 | 成人教育av | 性国产xxxx乳高跟 | 在线观看你懂的网站 | 久久激情视频 | 99精品久久久久 | 无码国模国产在线观看 | 成人亚洲综合 | 日韩不卡在线 |