<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          在 Kubernetes 容器集群,微服務(wù)項目最佳實踐

          共 49605字,需瀏覽 100分鐘

           ·

          2022-07-05 13:51

          原文鏈接:https://thiscute.world/posts/kubernetes-best-practices/

          本文主要介紹我個人在使用 Kubernetes 的過程中,總結(jié)出的一套「Kubernetes 配置」,是我個人的「最佳實踐」。其中大部分內(nèi)容都經(jīng)歷過線上環(huán)境的考驗,但是也有少部分還只在我腦子里模擬過,請謹(jǐn)慎參考。

          閱讀前的幾個注意事項:

          • 這份文檔比較長,囊括了很多內(nèi)容,建議當(dāng)成參考手冊使用,先參照目錄簡單讀一讀,有需要再細(xì)讀相關(guān)內(nèi)容。
          • 這份文檔需要一定的 Kubernetes 基礎(chǔ)才能理解,而且如果沒有過實踐經(jīng)驗的話,看上去可能會比較枯燥。
          • 而有過實踐經(jīng)驗的大佬,可能會跟我有不同的見解,歡迎各路大佬評論~

          首先,這里給出一些本文遵守的前提,這些前提只是契合我遇到的場景,可靈活變通:

          • 這里只討論無狀態(tài)服務(wù),有狀態(tài)服務(wù)不在討論范圍內(nèi)
          • 我們不使用 Deployment 的滾動更新能力,而是為每個服務(wù)的每個版本,都創(chuàng)建不同的 Deployment + HPA + PodDisruptionBudget,這是為了方便做金絲雀/灰度發(fā)布
          • 我們的服務(wù)可能會使用 IngressController / Service Mesh 來進(jìn)行服務(wù)的負(fù)載均衡、流量切分

          下面先給出一個 Deployment + HPA + PodDisruptionBudget 的 demo,后面再拆開詳細(xì)說下:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: my-app-v3
            namespace: prod  # 建議按業(yè)務(wù)邏輯劃分名字空間,prod 僅為示例
            labels:
              app: my-app
          spec:
            replicas: 3
            strategy:
              type: RollingUpdate
              # 因為服務(wù)的每個版本都使用各自的 Deployment,服務(wù)更新時其實是用不上這里的滾動更新策略的
              # 這個配置應(yīng)該只在 SRE 手動修改 Deployment 配置時才會生效(通常不應(yīng)該發(fā)生這種事)
              rollingUpdate:
                maxSurge: 10%  # 滾動更新時,每次最多更新 10% 的 Pods
                maxUnavailable: 0  # 滾動更新時,不允許出現(xiàn)不可用的 Pods,也就是說始終要維持 3 個可用副本
            selector:
              matchLabels:
                app: my-app
                version: v3
            template:
              metadata:
                labels:
                  app: my-app
                  version: v3
              spec:
                affinity:
                  # 注意,podAffinity/podAntiAffinity 可能不是最佳方案,這部分配置待更新
                  # topologySpreadConstraints 可能是更好的選擇
                  podAffinity:
                    preferredDuringSchedulingIgnoredDuringExecution: # 非強(qiáng)制性條件
                    - weight: 100  # weight 用于為節(jié)點評分,會優(yōu)先選擇評分最高的節(jié)點(只有一條規(guī)則的情況下,這個值沒啥意義)
                      podAffinityTerm:
                        labelSelector:
                          matchExpressions:
                          - key: app
                            operator: In
                            values:
                            - my-app
                          - key: version
                            operator: In
                            values:
                            - v3
                        # pod 盡量使用同一種節(jié)點類型,也就是盡量保證節(jié)點的性能一致
                        topologyKey: node.kubernetes.io/instance-type
                  podAntiAffinity:
                    preferredDuringSchedulingIgnoredDuringExecution: # 非強(qiáng)制性條件
                    - weight: 100  # weight 用于為節(jié)點評分,會優(yōu)先選擇評分最高的節(jié)點(只有一條規(guī)則的情況下,這個值沒啥意義)
                      podAffinityTerm:
                        labelSelector:
                          matchExpressions:
                          - key: app
                            operator: In
                            values:
                            - my-app
                          - key: version
                            operator: In
                            values:
                            - v3
                        # 將 pod 盡量打散在多個可用區(qū)
                        topologyKey: topology.kubernetes.io/zone
                    requiredDuringSchedulingIgnoredDuringExecution:  # 強(qiáng)制性要求(這個建議按需添加)
                    # 注意這個沒有 weights,必須滿足列表中的所有條件
                    - labelSelector:
                        matchExpressions:
                        - key: app
                          operator: In
                          values:
                          - my-app
                        - key: version
                          operator: In
                          values:
                          - v3
                      # Pod 必須運行在不同的節(jié)點上
                      topologyKey: kubernetes.io/hostname
                securityContext:
                  # runAsUser: 1000  # 設(shè)定用戶
                  # runAsGroup: 1000  # 設(shè)定用戶組
                  runAsNonRoot: true  # Pod 必須以非 root 用戶運行
                  seccompProfile:  # security compute mode
                    type: RuntimeDefault
                nodeSelector:
                  nodegroup: common  # 使用專用節(jié)點組,如果希望使用多個節(jié)點組,可改用節(jié)點親和性
                volumes:
                - name: tmp-dir
                  emptyDir: {}
                containers:
                - name: my-app-v3
                  image: my-app:v3  # 建議使用私有鏡像倉庫,規(guī)避 docker.io 的鏡像拉取限制
                  imagePullPolicy: IfNotPresent
                  volumeMounts:
                  - mountPath: /tmp
                    name: tmp-dir
                  lifecycle:
                    preStop:  # 在容器被 kill 之前執(zhí)行
                      exec:
                        command:
                        - /bin/sh
                        - -c
                        - "while [ $(netstat -plunt | grep tcp | wc -l | xargs) -ne 0 ]; do sleep 1; done"
                  resources:  # 資源請求與限制
                    # 對于核心服務(wù),建議設(shè)置 requests = limits,避免資源競爭
                    requests:
                      # HPA 會使用 requests 計算資源利用率
                      # 建議將 requests 設(shè)為服務(wù)正常狀態(tài)下的 CPU 使用率,HPA 的目前指標(biāo)設(shè)為 80%
                      # 所有容器的 requests 總量不建議為 2c/4G 4c/8G 等常見值,因為節(jié)點通常也是這個配置,這會導(dǎo)致 Pod 只能調(diào)度到更大的節(jié)點上,適當(dāng)調(diào)小 requests 等擴(kuò)充可用的節(jié)點類型,從而擴(kuò)充節(jié)點池。
                      cpu: 1000m
                      memory: 1Gi
                    limits:
                      # limits - requests 為允許超賣的資源量,建議為 requests 的 1 到 2 倍,酌情配置。
                      cpu: 1000m
                      memory: 1Gi
                  securityContext:
                    # 將容器層設(shè)為只讀,防止容器文件被篡改
                    ## 如果需要寫入臨時文件,建議額外掛載 emptyDir 來提供可讀寫的數(shù)據(jù)卷
                    readOnlyRootFilesystem: true
                    # 禁止 Pod 做任何權(quán)限提升
                    allowPrivilegeEscalation: false
                    capabilities:
                      # drop ALL 的權(quán)限比較嚴(yán)格,可按需修改
                      drop:
                      - ALL
                  startupProbe:  # 要求 kubernetes 1.18+
                    httpGet:
                      path: /actuator/health  # 直接使用健康檢查接口即可
                      port: 8080
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 20  # 最多提供給服務(wù) 5s * 20 的啟動時間
                    successThreshold: 1
                  livenessProbe:
                    httpGet:
                      path: /actuator/health  # spring 的通用健康檢查路徑
                      port: 8080
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 5
                    successThreshold: 1
                  # Readiness probes are very important for a RollingUpdate to work properly,
                  readinessProbe:
                    httpGet:
                      path: /actuator/health  # 簡單起見可直接使用 livenessProbe 相同的接口,當(dāng)然也可額外定義
                      port: 8080
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 5
                    successThreshold: 1
          ---
          apiVersion: autoscaling/v2beta2
          kind: HorizontalPodAutoscaler
          metadata:
            labels:
              app: my-app
            name: my-app-v3
            namespace: prod
          spec:
            scaleTargetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: my-app-v3
            maxReplicas: 50
            minReplicas: 3
            metrics:
            - type: Resource
              resource:
                name: cpu
                target:
                  type: Utilization
                  averageUtilization: 70
          ---
          apiVersion: policy/v1
          kind: PodDisruptionBudget
          metadata:
            name: my-app-v3
            namespace: prod
            labels:
              app: my-app
          spec:
            minAvailable: 75%
            selector:
              matchLabels:
                app: my-app
                version: v3

          一、優(yōu)雅停止(Gracful Shutdown)與 502/504 報錯

          如果 Pod 正在處理大量請求(比如 1000 QPS+)時,因為節(jié)點故障或「競價節(jié)點」被回收等原因被重新調(diào)度, 你可能會觀察到在容器被 terminate 的一段時間內(nèi)出現(xiàn)少量 502/504。

          為了搞清楚這個問題,需要先理解清楚 terminate 一個 Pod 的流程:

          1. Pod 的狀態(tài)被設(shè)為 Terminating,(幾乎)同時該 Pod 被從所有關(guān)聯(lián)的 Service Endpoints 中移除
          2. preStop 鉤子被執(zhí)行
            1. 它的執(zhí)行階段很好理解:在容器被 stop 之前執(zhí)行
            2. 它可以是一個命令,或者一個對 Pod 中容器的 http 調(diào)用
            3. 如果在收到 SIGTERM 信號時,無法優(yōu)雅退出,要支持優(yōu)雅退出比較麻煩的話,用 preStop 實現(xiàn)優(yōu)雅退出是一個非常好的方式
            4. preStop 的定義位置:https://github.com/kubernetes/api/blob/master/core/v1/types.go#L2515
          3. preStop 執(zhí)行完畢后,SIGTERM 信號被發(fā)送給 Pod 中的所有容器
          4. 繼續(xù)等待,直到容器停止,或者超時 spec.terminationGracePeriodSeconds,這個值默認(rèn)為 30s
            1. 需要注意的是,這個優(yōu)雅退出的等待計時是與 preStop 同步開始的!而且它也不會等待 preStop 結(jié)束!
          5. 如果超過了 spec.terminationGracePeriodSeconds 容器仍然沒有停止,k8s 將會發(fā)送 SIGKILL 信號給容器
          6. 進(jìn)程全部終止后,整個 Pod 完全被清理掉
          7. Docker+K8s+Jenkins 主流技術(shù)全解視頻資料【干貨免費分享】

          注意:1 跟 2 兩個工作是異步發(fā)生的,所以在未設(shè)置 preStop 時,可能會出現(xiàn)「Pod 還在 Service Endpoints 中,但是 SIGTERM 已經(jīng)被發(fā)送給 Pod 導(dǎo)致容器都掛掉」的情況,我們需要考慮到這種狀況的發(fā)生。

          了解了上面的流程后,我們就能分析出兩種錯誤碼出現(xiàn)的原因:

          • 502:應(yīng)用程序在收到 SIGTERM 信號后直接終止了運行,導(dǎo)致部分還沒有被處理完的請求直接中斷,代理層返回 502 表示這種情況
          • 504:Service Endpoints 移除不夠及時,在 Pod 已經(jīng)被終止后,仍然有個別請求被路由到了該 Pod,得不到響應(yīng)導(dǎo)致 504

          通常的解決方案是,在 Pod 的 preStop 步驟加一個 15s 的等待時間。其原理是:在 Pod 處理 terminating 狀態(tài)的時候,就會被從 Service Endpoints 中移除,也就不會再有新的請求過來了。在 preStop 等待 15s,基本就能保證所有的請求都在容器死掉之前被處理完成(一般來說,絕大部分請求的處理時間都在 300ms 以內(nèi)吧)。

          一個簡單的示例如下,它使 Pod 被 Terminate 時,總是在 stop 前先等待 15s,再發(fā)送 SIGTERM 信號給容器:

              containers:
              - name: my-app
                # 添加下面這部分
                lifecycle:
                  preStop:
                    exec:
                      command:
                      - /bin/sleep
                      - "15"

          更好的解決辦法,是直接等待所有 tcp 連接都關(guān)閉(需要鏡像中有 netstat):

              containers:
              - name: my-app
                # 添加下面這部分
                lifecycle:
                preStop:
                    exec:
                      command:
                      - /bin/sh
                      - -c
                      - "while [ $(netstat -plunt | grep tcp | wc -l | xargs) -ne 0 ]; do sleep 1; done"

          如果我的服務(wù)還使用了 Sidecar 代理網(wǎng)絡(luò)請求,該怎么處理?

          以服務(wù)網(wǎng)格 Istio 為例,在 Envoy 代理了 Pod 流量的情況下,502/504 的問題會變得更復(fù)雜一點——還需要考慮 Sidecar 與主容器的關(guān)閉順序:

          • 如果在 Envoy 已關(guān)閉后,有新的請求再進(jìn)來,將會導(dǎo)致 504(沒人響應(yīng)這個請求了)
            • 所以 Envoy 最好在 Terminating 至少 3s 后才能關(guān),確保 Istio 網(wǎng)格配置已完全更新
          • 如果在 Envoy 還沒停止時,主容器先關(guān)閉,然后又有新的請求再進(jìn)來,Envoy 將因為無法連接到 upstream 導(dǎo)致 503
            • 所以主容器也最好在 Terminating 至少 3s 后,才能關(guān)閉。
          • 如果主容器處理還未處理完遺留請求時,Envoy 或者主容器的其中一個停止了,會因為 tcp 連接直接斷開連接導(dǎo)致 502
            • 因此 Envoy 必須在主容器處理完遺留請求后(即沒有 tcp 連接時),才能關(guān)閉

          所以總結(jié)下:Envoy 及主容器的 preStop 都至少得設(shè)成 3s,并且在「沒有 tcp 連接」時,才能關(guān)閉,避免出現(xiàn) 502/503/504.

          主容器的修改方法在前文中已經(jīng)寫過了,下面介紹下 Envoy 的修改方法。

          和主容器一樣,Envoy 也能直接加 preStop,修改 istio-sidecar-injector 這個 configmap,在 sidecar 里添加 preStop sleep 命令:

              containers:
              - name: istio-proxy
                # 添加下面這部分
                lifecycle:
                preStop:
                    exec:
                      command:
                      - /bin/sh
                      - -c
                      - "while [ $(netstat -plunt | grep tcp | grep -v envoy | wc -l | xargs) -ne 0 ]; do sleep 1; done"

          參考

          • Kubernetes best practices: terminating with grace
          • Graceful shutdown in Kubernetes is not always trivial

          二、服務(wù)的伸縮配置 - HPA

          Kubernetes 官方主要支持基于 Pod CPU 的伸縮,這是應(yīng)用最為廣泛的伸縮指標(biāo),需要部署 metrics-server 才可使用。

          先回顧下前面給出的,基于 Pod CPU 使用率進(jìn)行伸縮的示例:

          apiVersion: autoscaling/v2beta2  # k8s 1.23+ 此 API 已經(jīng) GA
          kind: HorizontalPodAutoscaler
          metadata:
            labels:
              app: my-app
            name: my-app-v3
            namespace: prod
          spec:
            scaleTargetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: my-app-v3
            maxReplicas: 50
            minReplicas: 3
            metrics:
            - type: Resource
              resource:
                name: cpu
                target:
                  type: Utilization
                  averageUtilization: 70

          1. 當(dāng)前指標(biāo)值的計算方式

          提前總結(jié):每個 Pod 的指標(biāo)是其中所有容器指標(biāo)之和,如果計算百分比,就再除以 Pod 的 requests.

          HPA 默認(rèn)使用 Pod 的當(dāng)前指標(biāo)進(jìn)行計算,以 CPU 使用率為例,其計算公式為:

          「Pod 的 CPU 使用率」= 100% * 「所有 Container 的 CPU 用量之和」/「所有 Container 的 CPU requests 之和」

          注意分母是總的 requests 量,而不是 limits.

          1.1 存在的問題與解決方法

          在 Pod 只有一個容器時這沒啥問題,但是當(dāng) Pod 注入了 envoy 等 sidecar 時,這就會有問題了。

          因為 Istio 的 Sidecar requests 默認(rèn)為 100m 也就是 0.1 核。在未 tuning 的情況下,服務(wù)負(fù)載一高,sidecar 的實際用量很容易就能漲到 0.2-0.4 核。把這兩個值代入前面的公式,會發(fā)現(xiàn) 對于 QPS 較高的服務(wù),添加 Sidecar 后,「Pod 的 CPU 利用率」可能會高于「應(yīng)用容器的 CPU 利用率」,造成不必要的擴(kuò)容。

          即使改用「Pod 的 CPU 用量」而非百分比來進(jìn)行擴(kuò)縮容,也解決不了這個問題。

          解決方法:

          • 最佳解決方案:使用絕對度量指標(biāo),而非百分比。
          • 方法一:針對每個服務(wù)的 CPU 使用情況,為每個服務(wù)的 sidecar 設(shè)置不同的 requests/limits.
            • 感覺這個方案太麻煩了
          • 方法二:使用 KEDA 等第三方組件,獲取到應(yīng)用程序的 CPU 利用率(排除掉 Sidecar),使用它進(jìn)行擴(kuò)縮容
          • 方法三:使用 k8s 1.20 提供的 alpha 特性:Container Resourse Metrics.

          2. HPA 的擴(kuò)縮容算法

          HPA 什么時候會擴(kuò)容,這一點是很好理解的。但是 HPA 的縮容策略,會有些迷惑,下面簡單分析下。

          1. HPA 的「目標(biāo)指標(biāo)」可以使用兩種形式:絕對度量指標(biāo)和資源利用率。
            • 絕對度量指標(biāo):比如 CPU,就是指 CPU 的使用量
            • 資源利用率(資源使用量/資源請求 * 100%):在 Pod 設(shè)置了資源請求時,可以使用資源利用率進(jìn)行 Pod 伸縮
          2. HPA 的「當(dāng)前指標(biāo)」是一段時間內(nèi)所有 Pods 的平均值,不是峰值。

          HPA 的擴(kuò)縮容算法為:

          期望副本數(shù) = ceil[當(dāng)前副本數(shù) * ( 當(dāng)前指標(biāo) / 目標(biāo)指標(biāo) )]

          從上面的參數(shù)可以看到:

          1. 只要「當(dāng)前指標(biāo)」超過了目標(biāo)指標(biāo),就一定會發(fā)生擴(kuò)容。
          2. 當(dāng)前指標(biāo) / 目標(biāo)指標(biāo)要小到一定的程度,才會觸發(fā)縮容。
            1. 比如雙副本的情況下,上述比值要小于等于 1/2,才會縮容到單副本。
            2. 三副本的情況下,上述比值的臨界點是 2/3。
            3. 五副本時臨界值是 4/5,100 副本時臨界值是 99/100,依此類推。
            4. 如果 當(dāng)前指標(biāo) / 目標(biāo)指標(biāo) 從 1 降到 0.5,副本的數(shù)量將會減半。(雖然說副本數(shù)越多,發(fā)生這么大變化的可能性就越小。)
          3. 當(dāng)前副本數(shù) / 目標(biāo)指標(biāo)的值越大,「當(dāng)前指標(biāo)」的波動對「期望副本數(shù)」的影響就越大。

          為了防止擴(kuò)縮容過于敏感,HPA 有幾個相關(guān)參數(shù):

          1. Hardcoded 參數(shù)
            1. HPA Loop 延時:默認(rèn) 15 秒,每 15 秒鐘進(jìn)行一次 HPA 掃描。
            2. 縮容冷卻時間:默認(rèn) 5 分鐘。
          2. 對于 K8s 1.18+,HPA 通過 spec.behavior 提供了多種控制擴(kuò)縮容行為的參數(shù),后面會具體介紹。

          3. HPA 的期望值設(shè)成多少合適

          這個需要針對每個服務(wù)的具體情況,具體分析。

          以最常用的按 CPU 值伸縮為例,

          • 核心服務(wù)
            • 需要注意 CPU 跟 Memory 的 limits 限制策略是不同的,CPU 是真正地限制了上限,而 Memory 是用超了就干掉容器(OOMKilled)
            • k8s 一直使用 cgroups v1 (cpu_shares/memory.limit_in_bytes)來限制 cpu/memory,但是對于 Guaranteed 的 Pods 而言,內(nèi)存并不能完全預(yù)留,資源競爭總是有可能發(fā)生的。1.22 有 alpha 特性改用 cgroups v2,可以關(guān)注下。
            • requests/limits 值: 建議設(shè)成相等的,保證服務(wù)質(zhì)量等級為 Guaranteed
            • HPA: 一般來說,期望值設(shè)為 60% 到 70% 可能是比較合適的,最小副本數(shù)建議設(shè)為 2 - 5. (僅供參考)
            • PodDisruptionBudget: 建議按服務(wù)的健壯性與 HPA 期望值,來設(shè)置 PDB,后面會詳細(xì)介紹,這里就先略過了
          • 非核心服務(wù)
            • 也就是超賣了資源,這樣做主要的考量點是,很多非核心服務(wù)負(fù)載都很低,根本跑不到 limits 這么高,降低 requests 可以提高集群資源利用率,也不會損害服務(wù)穩(wěn)定性。
            • requests/limits 值: 建議 requests 設(shè)為 limits 的 0.6 - 0.9 倍(僅供參考),對應(yīng)的服務(wù)質(zhì)量等級為 Burstable
            • HPA: 因為 requests 降低了,而 HPA 是以 requests 為 100% 計算使用率的,我們可以提高 HPA 的期望值(如果使用百分比為期望值的話),比如 80% ~ 90%,最小副本數(shù)建議設(shè)為 1 - 3. (僅供參考)
            • PodDisruptionBudget: 非核心服務(wù)嘛,保證最少副本數(shù)為 1 就行了。

          4. HPA 的常見問題

          4.1. Pod 擴(kuò)容 - 預(yù)熱陷阱

          預(yù)熱:Java/C# 這類運行在虛擬機(jī)上的語言,第一次使用到某些功能時,往往需要初始化一些資源,例如「JIT 即時編譯」。如果代碼里還應(yīng)用了動態(tài)類加載之類的功能,就很可能導(dǎo)致微服務(wù)某些 API 第一次被調(diào)用時,響應(yīng)特別慢(要動態(tài)編譯 class)。因此 Pod 在提供服務(wù)前,需要提前「預(yù)熱(slow_start)」一次這些接口,將需要用到的資源提前初始化好。

          在負(fù)載很高的情況下,HPA 會自動擴(kuò)容。但是如果擴(kuò)容的 Pod 需要預(yù)熱,就可能會遇到「預(yù)熱陷阱」。

          在有大量用戶訪問的時候,不論使用何種負(fù)載均衡策略,只要請求被轉(zhuǎn)發(fā)到新建的 Pod 上,這個請求就會「卡住」。如果請求速度太快,Pod 啟動的瞬間「卡住」的請求就越多,這將會導(dǎo)致新建 Pod 因為壓力過大而垮掉。然后 Pod 一重啟就被壓垮,進(jìn)入 CrashLoopBackoff 循環(huán)。

          如果是在使用多線程做負(fù)載測試時,效果更明顯:50 個線程在不間斷地請求, 別的 Pod 響應(yīng)時間是「毫秒級」,而新建的 Pod 的首次響應(yīng)是「秒級」。幾乎是一瞬間,50 個線程就會全部陷在新建的 Pod 這里。而新建的 Pod 在啟動的瞬間可能特別脆弱,瞬間的 50 個并發(fā)請求就可以將它壓垮。然后 Pod 一重啟就被壓垮,進(jìn)入 CrashLoopBackoff 循環(huán)。

          解決方法

          可以在「應(yīng)用層面」解決:

          1. 在啟動探針 API 的后端控制器里面,依次調(diào)用所有需要預(yù)熱的接口或者其他方式,提前初始化好所有資源。
            1. 啟動探針的控制器中,可以通過 localhost 回環(huán)地址調(diào)用它自身的接口。
          2. 使用「AOT 預(yù)編譯」技術(shù):預(yù)熱,通常都是因為「JIT 即時編譯」導(dǎo)致的問題,在需要用到時它才編譯。而 AOT 是預(yù)先編譯,在使用前完成編譯,因此 AOT 能解決預(yù)熱的問題。

          也可以在「基礎(chǔ)設(shè)施層面」解決:

          1. 像 AWS ALB TargetGroup 以及其他云服務(wù)商的 ALB 服務(wù),通常都可以設(shè)置 slow_start 時長,即對新加入的實例,使用一定時間慢慢地把流量切過去,最終達(dá)到預(yù)期的負(fù)載均衡狀態(tài)。這個可以解決服務(wù)預(yù)熱問題。
          2. Envoy 也已經(jīng)支持 slow_start 模式,支持在一個設(shè)置好的時間窗口內(nèi),把流量慢慢負(fù)載到新加入的實例上,達(dá)成預(yù)熱效果。

          4.2. HPA 擴(kuò)縮容過于敏感,導(dǎo)致 Pod 數(shù)量震蕩

          通常來講,K8s 上絕大部分負(fù)載都應(yīng)該選擇使用 CPU 進(jìn)行擴(kuò)縮容。因為 CPU 通常能很好的反映服務(wù)的負(fù)載情況

          但是有些服務(wù)會存在其他影響 CPU 使用率的因素,導(dǎo)致使用 CPU 擴(kuò)縮容變得不那么可靠,比如:

          • 有些 Java 服務(wù)堆內(nèi)存設(shè)得很大,GC pause 也設(shè)得比較長,因此內(nèi)存 GC 會造成 CPU 間歇性飆升,CPU 監(jiān)控會有大量的尖峰。
          • 有些服務(wù)有定時任務(wù),定時任務(wù)一運行 CPU 就漲,但是這跟服務(wù)的 QPS 是無關(guān)的
          • 有些服務(wù)可能一運行 CPU 就會立即處于一個高位狀態(tài),它可能希望使用別的業(yè)務(wù)側(cè)指標(biāo)來進(jìn)行擴(kuò)容,而不是 CPU.

          因為上述問題存在,使用 CPU 擴(kuò)縮容,就可能會造成服務(wù)頻繁的擴(kuò)容然后縮容,或者無限擴(kuò)容。而有些服務(wù)(如我們的「推薦服務(wù)」),對「擴(kuò)容」和「縮容」都是比較敏感的,每次擴(kuò)縮都會造成服務(wù)可用率抖動。

          對這類服務(wù)而言,HPA 有這幾種調(diào)整策略:

          • 選擇使用 QPS 等相對比較平滑,沒有 GC 這類干擾的指標(biāo)來進(jìn)行擴(kuò)縮容,這需要借助 KEDA 等社區(qū)組件。
          • 對 kubernetes 1.18+,可以直接使用 HPA 的 behavior.scaleDownbehavior.scaleUp 兩個參數(shù),控制每次擴(kuò)縮容的最多 pod 數(shù)量或者比例。示例如下:
          ---
          apiVersion: autoscaling/v2beta2
          kind: HorizontalPodAutoscaler
          metadata:
            name: podinfo
            namespace: default
          spec:
            scaleTargetRef:
              apiVersion: apps/v1
              kind: Deployment
              name: podinfo
            minReplicas: 3
            maxReplicas: 50
            metrics:
            - type: Resource
              resource:
                name: cpu
                target:
                  type: Utilization
                  averageUtilization: 50  # 期望的 CPU 平均值
            behavior:
              scaleUp:
                stabilizationWindowSeconds: 0  # 默認(rèn)為 0,只使用當(dāng)前值進(jìn)行擴(kuò)縮容
                policies:
                - periodSeconds: 180  # 每 3 分鐘最多擴(kuò)容 5% 的 Pods
                  type: Percent
                  value: 5
                - periodSeconds: 60  # 每分鐘最多擴(kuò)容 1 個 Pod,擴(kuò)的慢一點主要是為了一個個地預(yù)熱,避免一次擴(kuò)容太多未預(yù)熱的 Pods 導(dǎo)致服務(wù)可用率劇烈抖動
                  type: Pods
                  value: 1
                selectPolicy: Min  # 選擇最小的策略
              # 以下的一切配置,都是為了更平滑地縮容
              scaleDown:
                stabilizationWindowSeconds: 600  # 使用過去 10 mins 的最大 cpu 值進(jìn)行縮容計算,避免過快縮容
                policies:
                - type: Percent  # 每 3 mins 最多縮容 `ceil[當(dāng)前副本數(shù) * 5%]` 個 pod(20 個 pod 以內(nèi),一次只縮容 1 個 pod)
                  value: 5
                  periodSeconds: 180
                - type: Pods  # 每 1 mins 最多縮容 1 個 pod
                  value: 1
                  periodSeconds: 60
                selectPolicy: Min  # 上面的 policies 列表,只生效其中最小的值作為縮容限制(保證平滑縮容)

          而對于擴(kuò)容不夠平滑這個問題,可以考慮提供類似 AWS ALB TargetGroup slow_start 的功能,在擴(kuò)容時緩慢將流量切到新 Pod 上,以實現(xiàn)預(yù)熱服務(wù)(JVM 預(yù)熱以及本地緩存預(yù)熱),這樣就能達(dá)到比較好的平滑擴(kuò)容效果。

          5. HPA 注意事項

          注意 kubectl 1.23 以下的版本,默認(rèn)使用 hpa.v1.autoscaling 來查詢 HPA 配置,v2beta2 相關(guān)的參數(shù)會被編碼到 metadata.annotations 中。

          比如 behavior 就會被編碼到 autoscaling.alpha.kubernetes.io/behavior 這個 key 所對應(yīng)的值中。

          因此如果使用了 v2beta2 的 HPA,一定要明確指定使用 v2beta2 版本的 HPA:

          kubectl get hpa.v2beta2.autoscaling

          否則不小心動到 annotations 中編碼的某些參數(shù),可能會產(chǎn)生意料之外的效果,甚至直接把控制面搞崩… 比如這個 issue: Nil pointer dereference in KCM after v1 HPA patch request

          6. 參考

          • Pod 水平自動伸縮 - Kubernetes Docs
          • Horizontal Pod Autoscaler 演練 - Kubernetes Docs

          三、節(jié)點維護(hù)與 Pod 干擾預(yù)算

          在我們通過 kubectl drain 將某個節(jié)點上的容器驅(qū)逐走的時候, kubernetes 會依據(jù) Pod 的「PodDistruptionBuget」來進(jìn)行 Pod 的驅(qū)逐。

          如果不設(shè)置任何明確的 PodDistruptionBuget,Pod 將會被直接殺死,然后在別的節(jié)點重新調(diào)度,這可能導(dǎo)致服務(wù)中斷!

          PDB 是一個單獨的 CR 自定義資源,示例如下:

          apiVersion: policy/v1beta1
          kind: PodDisruptionBudget
          metadata:
            name: podinfo-pdb
          spec:
            # 如果不滿足 PDB,Pod 驅(qū)逐將會失??!
            minAvailable: 1      # 最少也要維持一個 Pod 可用
          #   maxUnavailable: 1  # 最大不可用的 Pod 數(shù),與 minAvailable 不能同時配置!二選一
            selector:
              matchLabels:
                app: podinfo

          如果在進(jìn)行節(jié)點維護(hù)時(kubectl drain),Pod 不滿足 PDB,drain 將會失敗,示例:

          > kubectl drain node-205 --ignore-daemonsets --delete-local-data
          node/node-205 cordoned
          WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-nfhj7, kube-system/kube-proxy-94dz5
          evicting pod default/podinfo-7c84d8c94d-h9brq
          evicting pod default/podinfo-7c84d8c94d-gw6qf
          error when evicting pod "podinfo-7c84d8c94d-h9brq" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
          evicting pod default/podinfo-7c84d8c94d-h9brq
          error when evicting pod "podinfo-7c84d8c94d-h9brq" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
          evicting pod default/podinfo-7c84d8c94d-h9brq
          error when evicting pod "podinfo-7c84d8c94d-h9brq" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
          evicting pod default/podinfo-7c84d8c94d-h9brq
          pod/podinfo-7c84d8c94d-gw6qf evicted
          pod/podinfo-7c84d8c94d-h9brq evicted
          node/node-205 evicted

          上面的示例中,podinfo 一共有兩個副本,都運行在 node-205 上面。我給它設(shè)置了干擾預(yù)算 PDB minAvailable: 1。

          然后使用 kubectl drain 驅(qū)逐 Pod 時,其中一個 Pod 被立即驅(qū)逐走了,而另一個 Pod 大概在 15 秒內(nèi)一直驅(qū)逐失敗。因為第一個 Pod 還沒有在新的節(jié)點上啟動完成,它不滿足干擾預(yù)算 PDB minAvailable: 1 這個條件。

          大約 15 秒后,最先被驅(qū)逐走的 Pod 在新節(jié)點上啟動完成了,另一個 Pod 滿足了 PDB 所以終于也被驅(qū)逐了。這才完成了一個節(jié)點的 drain 操作。

          ClusterAutoscaler 等集群節(jié)點伸縮組件,在縮容節(jié)點時也會考慮 PodDisruptionBudget. 如果你的集群使用了 ClusterAutoscaler 等動態(tài)擴(kuò)縮容節(jié)點的組件,強(qiáng)烈建議設(shè)置為所有服務(wù)設(shè)置 PodDisruptionBudget.

          在 PDB 中使用百分比的注意事項

          在使用百分比時,計算出的實例數(shù)都會被向上取整,這會造成兩個現(xiàn)象:

          • 如果使用 minAvailable,實例數(shù)較少的情況下,可能會導(dǎo)致 ALLOWED DISRUPTIONS 為 0,所有實例都無法被驅(qū)逐了。
          • 如果使用 maxUnavailable,因為是向上取整,ALLOWED DISRUPTIONS 的值一定不會低于 1,至少有 1 個實例可以被驅(qū)逐。

          因此從「便于驅(qū)逐」的角度看,如果你的服務(wù)至少有 2-3 個實例,建議在 PDB 中使用百分比配置 maxUnavailable,而不是 minAvailable. 相對的從「確保服務(wù)穩(wěn)定性」的角度看,我們則應(yīng)該使用 minAvailable,確保至少有 1 個實例可用。

          最佳實踐 Deployment + HPA + PodDisruptionBudget

          一般而言,一個服務(wù)的每個版本,都應(yīng)該包含如下三個資源:

          • Deployment: 管理服務(wù)自身的 Pods 嘛
          • HPA: 負(fù)責(zé) Pods 的擴(kuò)縮容,通常使用 CPU 指標(biāo)進(jìn)行擴(kuò)縮容
          • PodDisruptionBudget(PDB): 建議按照 HPA 的目標(biāo)值,來設(shè)置 PDB.
            • 比如 HPA CPU 目標(biāo)值為 60%,就可以考慮設(shè)置 PDB minAvailable=65%,保證至少有 65% 的 Pod 可用。這樣理論上極限情況下 QPS 均攤到剩下 65% 的 Pods 上也不會造成雪崩(這里假設(shè) QPS 和 CPU 是完全的線性關(guān)系)

          四、節(jié)點親和性與節(jié)點組

          我們一個集群,通常會使用不同的標(biāo)簽為節(jié)點組進(jìn)行分類,比如 kubernetes 自動生成的一些節(jié)點標(biāo)簽:

          • kubernetes.io/os: 通常都用 linux
          • kubernetes.io/arch: amd64, arm64
          • topology.kubernetes.io/regiontopology.kubernetes.io/zone: 云服務(wù)的區(qū)域及可用區(qū)

          我們使用得比較多的,是「節(jié)點親和性」以及「Pod 反親和性」,另外兩個策略視情況使用。

          1. 節(jié)點親和性

          如果你使用的是 aws,那 aws 有一些自定義的節(jié)點標(biāo)簽:

          • eks.amazonaws.com/nodegroup: aws eks 節(jié)點組的名稱,同一個節(jié)點組使用同樣的 aws ec2 實例模板
            • 比如 arm64 節(jié)點組、amd64/x64 節(jié)點組
            • 內(nèi)存比例高的節(jié)點組如 m 系實例,計算性能高的節(jié)點組如 c 系列
            • 競價實例節(jié)點組:這個省錢啊,但是動態(tài)性很高,隨時可能被回收
            • 按量付費節(jié)點組:這類實例貴,但是穩(wěn)定。

          假設(shè)你希望優(yōu)先選擇競價實例跑你的 Pod,如果競價實例暫時跑滿了,就選擇按量付費實例。那 nodeSelector 就滿足不了你的需求了,你需要使用 nodeAffinity,示例如下:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: xxx
            namespace: xxx
          spec:
            # ...
            template:
              # ...
              spec:
                affinity:
                  nodeAffinity:
                    # 優(yōu)先選擇 spot-group-c 的節(jié)點
                    preferredDuringSchedulingIgnoredDuringExecution:
                    - preference:
                        matchExpressions:
                        - key: eks.amazonaws.com/nodegroup
                          operator: In
                          values:
                          - spot-group-c
                      weight: 80  # weight 用于為節(jié)點評分,會優(yōu)先選擇評分最高的節(jié)點
                    - preference:
                        matchExpressions:
                        # 優(yōu)先選擇 aws c6i 的機(jī)器
                        - key: node.kubernetes.io/instance-type
                          operator: In
                          values:
                          - "c6i.xlarge"
                          - "c6i.2xlarge"
                          - "c6i.4xlarge"
                          - "c6i.8xlarge"
                      weight: 70
                    - preference:
                        matchExpressions:
                        # 其次選擇 aws c5 的機(jī)器
                        - key: node.kubernetes.io/instance-type
                          operator: In
                          values:
                          - "c5.xlarge"
                          - "c5.2xlarge"
                          - "c5.4xlarge"
                          - "c5.9xlarge"
                      weight: 60
                   # 如果沒 spot-group-c 可用,也可選擇 ondemand-group-c 的節(jié)點跑
                    requiredDuringSchedulingIgnoredDuringExecution:
                      nodeSelectorTerms:
                      - matchExpressions:
                        - key: eks.amazonaws.com/nodegroup
                          operator: In
                          values:
                          - spot-group-c
                          - ondemand-group-c
                containers:
                  # ...

          2. Pod 反親和性

          Pod 親和性與反親和性可能不是最佳的實現(xiàn)手段,這部分內(nèi)容待更新

          相關(guān) Issue: https://github.com/kubernetes/kubernetes/issues/72479

          相關(guān)替代方案:https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/

          通常建議為每個 Deployment 的 template 配置 Pod 反親和性,把 Pods 打散在所有節(jié)點上:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: xxx
            namespace: xxx
          spec:
            # ...
            template:
              # ...
              spec:
                replicas: 3
                affinity:
                  podAntiAffinity:
                    preferredDuringSchedulingIgnoredDuringExecution: # 非強(qiáng)制性條件
                    - weight: 100  # weight 用于為節(jié)點評分,會優(yōu)先選擇評分最高的節(jié)點
                      podAffinityTerm:
                        labelSelector:
                          matchExpressions:
                          - key: app
                            operator: In
                            values:
                            - xxx
                          - key: version
                            operator: In
                            values:
                            - v12
                        # 將 pod 盡量打散在多個可用區(qū)
                        topologyKey: topology.kubernetes.io/zone
                    requiredDuringSchedulingIgnoredDuringExecution:  # 強(qiáng)制性要求
                    # 注意這個沒有 weights,必須滿足列表中的所有條件
                    - labelSelector:
                        matchExpressions:
                        - key: app
                          operator: In
                          values:
                          - xxx
                        - key: version
                          operator: In
                          values:
                          - v12
                      # Pod 必須運行在不同的節(jié)點上
                      topologyKey: kubernetes.io/hostname

          五、Pod 的就緒探針、存活探針與啟動探針

          Pod 提供如下三種探針,均支持使用 Command、HTTP API、TCP Socket 這三種手段來進(jìn)行服務(wù)可用性探測。

          • startupProbe 啟動探針(Kubernetes v1.18 [beta]): 此探針通過后,「就緒探針」與「存活探針」才會進(jìn)行存活性與就緒檢查
            • startupProbe 顯然比 livenessProbe 的 initialDelaySeconds 參數(shù)更靈活。
            • 同時它也能延遲 readinessProbe 的生效時間,這主要是為了避免無意義的探測。容器都還沒 startUp,顯然是不可能就緒的。
            • 用于對慢啟動容器進(jìn)行存活性檢測,避免它們在啟動運行之前就被殺掉
            • 程序?qū)⒆疃嘤?failureThreshold * periodSeconds 的時間用于啟動,比如設(shè)置 failureThreshold=20、periodSeconds=5,程序啟動時間最長就為 100s,如果超過 100s 仍然未通過「啟動探測」,容器會被殺死。
          • readinessProbe 就緒探針:
            • 就緒探針失敗次數(shù)超過 failureThreshold 限制(默認(rèn)三次),服務(wù)將被暫時從 Service 的 Endpoints 中踢出,直到服務(wù)再次滿足 successThreshold.
          • livenessProbe 存活探針: 檢測服務(wù)是否存活,它可以捕捉到死鎖等情況,及時殺死這種容器。
            • kubectl describe pod 會顯示重啟原因為 State.Last State.Reason = Error, Exit Code=137,同時 Events 中會有 Liveness probe failed: ... 這樣的描述。
            • 服務(wù)發(fā)生死鎖,對所有請求均無響應(yīng)
            • 服務(wù)線程全部卡在對外部 redis/mysql 等外部依賴的等待中,導(dǎo)致請求無響應(yīng)
            • 存活探針失敗可能的原因:
            • 存活探針失敗次數(shù)超過 failureThreshold 限制(默認(rèn)三次),容器將被殺死,隨后根據(jù)重啟策略執(zhí)行重啟。

          上述三類探測器的參數(shù)都是通用的,五個時間相關(guān)的參數(shù)列舉如下:

          # 下面的值就是 k8s 的默認(rèn)值
          initialDelaySeconds: 0  # 默認(rèn)沒有 delay 時間
          periodSeconds: 10
          timeoutSeconds: 1
          failureThreshold: 3
          successThreshold: 1

          示例:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: my-app-v3
          spec:
            # ...
            template:
              #  ...
              spec:
                containers:
                - name: my-app-v3
                  image: xxx.com/app/my-app:v3
                  imagePullPolicy: IfNotPresent
                  # ... 省略若干配置
                  startupProbe:
                    httpGet:
                      path: /actuator/health  # 直接使用健康檢查接口即可
                      port: 8080
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 20  # 最多提供給服務(wù) 5s * 20 的啟動時間
                    successThreshold: 1
                  livenessProbe:
                    httpGet:
                      path: /actuator/health  # spring 的通用健康檢查路徑
                      port: 8080
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 5
                    successThreshold: 1
                  # Readiness probes are very important for a RollingUpdate to work properly,
                  readinessProbe:
                    httpGet:
                      path: /actuator/health  # 簡單起見可直接使用 livenessProbe 相同的接口,當(dāng)然也可額外定義
                      port: 8080
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 5
                    successThreshold: 1

          在 Kubernetes 1.18 之前,通用的手段是為「就緒探針」添加較長的 initialDelaySeconds 來實現(xiàn)類似「啟動探針」的功能動,避免容器因為啟動太慢,存活探針失敗導(dǎo)致容器被重啟。示例如下:

          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: my-app-v3
          spec:
            # ...
            template:
              #  ...
              spec:
                containers:
                - name: my-app-v3
                  image: xxx.com/app/my-app:v3
                  imagePullPolicy: IfNotPresent
                  # ... 省略若干配置
                  livenessProbe:
                    httpGet:
                      path: /actuator/health  # spring 的通用健康檢查路徑
                      port: 8080
                    initialDelaySeconds: 120  # 前兩分鐘,都假設(shè)服務(wù)健康,避免 livenessProbe 失敗導(dǎo)致服務(wù)重啟
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 5
                    successThreshold: 1
                  # 容器一啟動,Readiness probes 就會不斷進(jìn)行檢測
                  readinessProbe:
                    httpGet:
                      path: /actuator/health
                      port: 8080
                    initialDelaySeconds: 3  # readiness probe 不需要設(shè)太長時間,使 Pod 盡快加入到 Endpoints.
                    periodSeconds: 5
                    timeoutSeconds: 1
                    failureThreshold: 5
                    successThreshold: 1

          六、Pod 安全

          這里只介紹 Pod 中安全相關(guān)的參數(shù),其他諸如集群全局的安全策略,不在這里討論。


          Pod SecurityContext

          通過設(shè)置 Pod 的 SecurityContext,可以為每個 Pod 設(shè)置特定的安全策略。

          SecurityContext 有兩種類型:

          1. spec.securityContext: 這是一個 PodSecurityContext 對象
            • 顧名思義,它對 Pod 中的所有 contaienrs 都有效。
          2. spec.containers[*].securityContext: 這是一個 SecurityContext 對象
            • container 私有的 SecurityContext

          這兩個 SecurityContext 的參數(shù)只有部分重疊,重疊的部分 spec.containers[*].securityContext 優(yōu)先級更高。

          我們比較常遇到的一些提升權(quán)限的安全策略:

          1. 特權(quán)容器:spec.containers[*].securityContext.privileged
          2. 添加(Capabilities)可選的系統(tǒng)級能力: spec.containers[*].securityContext.capabilities.add
            1. 只有 ntp 同步服務(wù)等少數(shù)容器,可以開啟這項功能。請注意這非常危險。
          3. Sysctls: 系統(tǒng)參數(shù): spec.securityContext.sysctls

          權(quán)限限制相關(guān)的安全策略有(強(qiáng)烈建議在所有 Pod 上按需配置如下安全策略!):

          1. spec.volumes: 所有的數(shù)據(jù)卷都可以設(shè)定讀寫權(quán)限
          2. spec.securityContext.runAsNonRoot: true Pod 必須以非 root 用戶運行
          3. spec.containers[*].securityContext.readOnlyRootFileSystem:true 將容器層設(shè)為只讀,防止容器文件被篡改。
            1. 如果微服務(wù)需要讀寫文件,建議額外掛載 emptydir 類型的數(shù)據(jù)卷。
          4. spec.containers[*].securityContext.allowPrivilegeEscalation: false 不允許 Pod 做任何權(quán)限提升!
          5. spec.containers[*].securityContext.capabilities.drop: 移除(Capabilities)可選的系統(tǒng)級能力

          還有其他諸如指定容器的運行用戶(user)/用戶組(group)等功能未列出,請自行查閱 Kubernetes 相關(guān)文檔。

          一個無狀態(tài)的微服務(wù) Pod 配置舉例:

          apiVersion: v1
          kind: Pod
          metadata:
            name: <Pod name>
          spec:
            containers:
            - name: <container name>
              image: <image>
              imagePullPolicy: IfNotPresent
              # ......此處省略 500 字
              securityContext:
                readOnlyRootFilesystem: true  # 將容器層設(shè)為只讀,防止容器文件被篡改。
                allowPrivilegeEscalation: false  # 禁止 Pod 做任何權(quán)限提升
                capabilities:
                  drop:
                  # 禁止容器使用 raw 套接字,通常只有 hacker 才會用到 raw 套接字。
                  # raw_socket 可自定義網(wǎng)絡(luò)層數(shù)據(jù),避開 tcp/udp 協(xié)議棧,直接操作底層的 ip/icmp 數(shù)據(jù)包。可實現(xiàn) ip 偽裝、自定義協(xié)議等功能。
                  # 去掉 net_raw 會導(dǎo)致 tcpdump 無法使用,無法進(jìn)行容器內(nèi)抓包。需要抓包時可臨時去除這項配置
                  - NET_RAW
                  # 更好的選擇:直接禁用所有 capabilities
                  # - ALL
            securityContext:
              # runAsUser: 1000  # 設(shè)定用戶
              # runAsGroup: 1000  # 設(shè)定用戶組
              runAsNonRoot: true  # Pod 必須以非 root 用戶運行
              seccompProfile:  # security compute mode
                type: RuntimeDefault

          2. seccomp: security compute mode

          seccomp 和 seccomp-bpf 允許對系統(tǒng)調(diào)用進(jìn)行過濾,可以防止用戶的二進(jìn)制文對主機(jī)操作系統(tǒng)件執(zhí)行通常情況下并不需要的危險操作。它和 Falco 有些類似,不過 Seccomp 沒有為容器提供特別的支持。

          視頻:

          • Seccomp: What Can It Do For You? - Justin Cormack, Docker

          六、隔離性

          • 推薦按業(yè)務(wù)線或者業(yè)務(wù)團(tuán)隊進(jìn)行名字空間劃分,方便對每個業(yè)務(wù)線/業(yè)務(wù)團(tuán)隊分別進(jìn)行資源限制
          • 推薦使用 network policy 對服務(wù)實施強(qiáng)力的網(wǎng)絡(luò)管控,避免長期發(fā)展過程中,業(yè)務(wù)服務(wù)之間出現(xiàn)混亂的跨業(yè)務(wù)線相互調(diào)用關(guān)系,也避免服務(wù)被黑后,往未知地址發(fā)送數(shù)據(jù)。

          其他問題

          • 不同節(jié)點類型的性能有差距,導(dǎo)致 QPS 均衡的情況下,CPU 負(fù)載不均衡
            • 盡量使用性能相同的實例類型:通過 podAffinitynodeAffinity 添加節(jié)點類型的親和性
            • 解決辦法(未驗證):

          - END -


           推薦閱讀 











          2022年最火的 Kubernetes 認(rèn)證 
          2022 年要考慮的 7 種 Docker 替代方案
          Linux 運維工程師的 6 類好習(xí)慣和 23 個教訓(xùn)
          Keepalived+HAProxy 搭建高可用負(fù)載均衡
          網(wǎng)絡(luò)丟包,網(wǎng)絡(luò)延遲?這款神器幫你搞定所有!
          頂級 DevOps 工具鏈大盤點
          某外企從 0 建設(shè) SRE 運維體系經(jīng)驗分享
          Nginx+Redis:高性能緩存利器
          主流監(jiān)控系統(tǒng) Prometheus 學(xué)習(xí)指南
          基于 eBPF 的 Kubernetes 問題排查全景圖發(fā)布
          一文掌握 Ansible 自動化運維
          Linux的10個最危險命令
          Kubernetes網(wǎng)絡(luò)難懂?可能是沒看到這篇文章
          24 個 Docker 常見問題處理技巧
          這篇文章帶你全面掌握 Nginx !
          一文搞懂 Kubernetes 網(wǎng)絡(luò)通信原理
          搭建一套完整的企業(yè)級 K8s 集群(kubeadm方式)


          點亮,服務(wù)器三年不宕機(jī)
          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久伊人青青 | 操美少妇母亲aV | 天天日天天色天天干 | 免费做爱网站在线观看 | 无码人妻一区二区三区精品不付款 |