使用Kubernetes常犯的一些錯誤

參考文章:

主要參考了網(wǎng)上的一些文章和自己日常使用的一些小結(jié),以下是一些我們經(jīng)??吹降腻e誤:

  1. 資源(resources)——requests和limits配置不合理
  2. Liveness和Readiness探針配置不合理
  3. 為每個http服務(wù)都設(shè)置負(fù)載均衡
  4. 使用非Kubernetes感知的集群自動擴(kuò)展
  5. 未定義pod的反親和性
  6. 沒有使用PodDisruptionBudget
  7. 多租戶或多環(huán)境共享集群
  8. 使用latest標(biāo)簽

1. 資源(resources)——requests和limits

這個絕對是最值得注意以及最先拿出來講解的。

使用建議:

  1. CPU通常只建議設(shè)置一個較為合理的 request,而無需設(shè)置limit;
  2. Memory通常建議設(shè)置成為 Guaranteed QoS,即request == limit

常見的錯誤場景及可能導(dǎo)致的結(jié)果
關(guān)于CPU的有:

  1. 不設(shè)置 CPU request; (會導(dǎo)致資源搶占,驅(qū)逐pod,乃至集群雪崩)
  2. 將CPU請求設(shè)置得很低;(這樣我們就可以在每個節(jié)點(diǎn)上容納很多Pod。但是當(dāng)pod負(fù)載過高時,pod僅能獲取他所請求的那部分資源,會導(dǎo)致資源的限制成為瓶頸)
  3. 給CPU 設(shè)置limit ; (在CPU負(fù)載高的時候,workload的CPU limit成為瓶頸,導(dǎo)致延遲、超時等問題;關(guān)于CPU的limit有一些圍繞CPU CFS和CPU limit的討論,但是通常認(rèn)為設(shè)置CPU limit會引發(fā)更多的問題)

關(guān)于Memory的有:

  1. 沒有把Memory設(shè)置成為 “Guaranteed QoS”
    Memory不像CPU,CPU不夠的時候會成為瓶頸,而Memory不夠的時候會導(dǎo)致OOM錯誤;如果想盡量保證服務(wù)的穩(wěn)定性,就設(shè)置成 “Guaranteed QoS”;

關(guān)于具體值的設(shè)置可以通過prometheus這類監(jiān)控工具查看集群狀態(tài)和pod的指標(biāo)來判斷。 GCP的VerticalPodAutoScaler 也可以幫助自動化這個過程。

2. Liveness和Readiness探針

使用建議:

  • 除非你有很明確的場景,或者非常了解后果的情況下,通常建議定義且只定義readiness,因?yàn)?a target="_blank">liveness prob是有風(fēng)險的
    • 確保readiness定義了
    • 確保readiness能真實(shí)的反映webserver以及對應(yīng)端口的可用情況
    • readiness包含了數(shù)據(jù)庫初始化和migration
    • 理解readiness的默認(rèn)行為:interval: 10s,timeout: 1s,successThreshold: 1, failureThreshold: 3
    • 使用一個不同的端口如果可能的話;與正常的流量區(qū)分開來
    • 可以使用readiness probe作為prewarming / cache loading, 預(yù)熱節(jié)點(diǎn)
  • Liveness和Readiness probe 盡量不要依賴于外部的dependencies(例如數(shù)據(jù)庫),
    • 避免導(dǎo)致級聯(lián)失效;
    • 低耦合,其他服務(wù)的狀態(tài)由他自己的探針負(fù)責(zé);
  • 如果非要設(shè)置Liveness,不要使用和Readiness同一個接口
  • 不要使用 "exec" probes

常見錯誤場景:

  • 沒有配置readiness
  • 錯誤的配置readiness探針
  • readiness == liveness
  • 沒有優(yōu)雅的關(guān)閉
  • 優(yōu)雅的關(guān)閉不夠優(yōu)雅

Liveness和Readiness probe的關(guān)系容易混淆。他們都在pod的全生命周期執(zhí)行

  • Liveness在探測失敗時候會重啟節(jié)點(diǎn);
  • Readiness在探針失敗時候,會斷開pod與k8s service的連接,并且不會把請求往pod上發(fā)送,直到再次探測成功;

如果一個配置了readiness的節(jié)點(diǎn)在請求量過大的時候,readiness可能失效,于是該節(jié)點(diǎn)暫時不再處理更多的請求;但是當(dāng)節(jié)點(diǎn)負(fù)載慢慢降低,readiness恢復(fù)時候,節(jié)點(diǎn)又能夠正常的處理請求。
但是如果該節(jié)點(diǎn)配置了相同的liveness 探針并且也失效了,那么該節(jié)點(diǎn)就會重啟。為什么你需要重啟一個健康的、并且正在處理很多請求的節(jié)點(diǎn)呢?

3. 為每個http服務(wù)都設(shè)置負(fù)載均衡

使用建議:
如果需要對外暴露接口的時候,最好使用ingress;或者使用"type: NodePort" 類型的service。

不要把每個Service設(shè)置成"type: LoadBalancer" 類型,該類型會調(diào)用云提供商的接口創(chuàng)建額外的資源,通常包括IP以及一些額外的計算資源;如果所有Service都是用該類型通常會有很多額外的花費(fèi)

4. 使用非Kubernetes感知的集群自動擴(kuò)展

使用建議:
使用auto scaler的時候,使用官方或社區(qū)推薦的auto scaler

當(dāng)在集群里面添加/刪除node的時候,你不應(yīng)該只考慮CPU/Memory的限制這些指標(biāo),還要考慮k8s中一些調(diào)度的約束,比如:pod & node affinities,taints & tolerations, resource request, QoS等。Scaling-in 也就是移除節(jié)點(diǎn)的過程會更加的復(fù)雜,例如stateful的pod與pv有綁定,而pv通常又屬于某個特定的zone的時候。

在使用auto-scaler 時候,auto scaler也需要理解這些配置,否則會導(dǎo)致pod調(diào)度失敗。目前社區(qū)通常使用cluster-autoscaler 來做集群的自動擴(kuò)容縮容。

5. 未定義pod的反親和性

使用建議:
明確的聲明反親和性,確保pod會調(diào)度到不同的node上:

// omitted for brevity
      labels:
        app: zk
// omitted for brevity
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"
  • 因?yàn)橹皇钦{(diào)度時候需要檢查,因此requiredDuringSchedulingIgnoredDuringExecution。
  • 以上配置會根據(jù)"kubernetes.io/hostname"來適用反親和性,如果有更定制化的HA需求,比如多區(qū)域部署,可以go deeper。

常見錯誤場景:
如果一個deployment為了高可用聲明了三個pod,但是這三個pod被調(diào)度到一個node上了,那么當(dāng)這個node 掛掉的時候,這個deployment所有的服務(wù)都不可用了。

6. 沒有使用PodDisruptionBudget

使用建議:
對于有HA需求的pod, 設(shè)置PodDisruptionBudget
PodDisruptionBudget 控制器來保證在主動銷毀應(yīng)用POD的時候,不會一次性銷毀太多的應(yīng)用pod,從而保證業(yè)務(wù)不中斷或業(yè)務(wù)SLA不降級。
Cluster Managers 或者h(yuǎn)ost provider 應(yīng)當(dāng)使用能識別 PodDisruptionBudget 的eviction API 而不是直接刪除 pod, 例如kubectl drain 命令。當(dāng)要drain一個node的時候, kubectl drain 會嘗試不停的evict對應(yīng)機(jī)器上所有的pods, 請求也許會被temporarily的失敗,但是會不停的重試直到所有的pod都Terminated,或者達(dá)到了配置的timeout時間。
更多的細(xì)節(jié)介紹。

1、下面的例子使用了minAvailable參數(shù):

apiVersion: policy/v1beta1  
kind: PodDisruptionBudget  
metadata:  
  name: zk-pdb  
spec:  
  minAvailable: 2  
  selector:  
    matchLabels:  
      app: zookeeper

2、下面的例子使用了maxUnavailable參數(shù):

apiVersion: policy/v1beta1  
kind: PodDisruptionBudget  
metadata:  
  name: zk-pdb  
spec:  
  maxUnavailable: 1  
  selector:  
    matchLabels:  
      app: zookeeper

當(dāng)zk-pdb對象副本數(shù)是3的時候,上面這兩個例子所表達(dá)的意思是一樣的。

7. 多租戶或多環(huán)境共享集群

使用建議:
k8s的namespace并不提供很強(qiáng)的隔離性,因此盡量不要使用namespace來做多環(huán)境多租戶的隔離,例如不要把dev,qa,staging,sandbox這些環(huán)境和prod部署到一個集群里面。
盡管有一些資源公平性的配置,如: resource requests/limits, quotas, priorityClasses; 以及一些隔離性的配置,如: affinities,tolerations, taints;但是為了達(dá)到隔離,通常需要極為復(fù)雜的配置。
因此大部分時候,使用多個集群會更加的易于維護(hù)。

8. 使用latest標(biāo)簽

使用建議:
不要在deployment中的鏡像使用:latest標(biāo)簽,而是使用固定的版本。
否則可能會導(dǎo)致部署時候,k8s node使用本地的舊版本的image, 導(dǎo)致線上環(huán)境出現(xiàn)版本問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容