View a markdown version of this page

Kubernetes 資料平面 - Amazon EKS

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

Kubernetes 資料平面

選取 EC2 執行個體類型可能是客戶面臨的最困難決策之一,因為在具有多個工作負載的叢集中。沒有one-size-fits解決方案。以下是一些秘訣,可協助您避免擴展運算的常見陷阱。

自動節點自動擴展

我們建議您使用節點自動調整規模,以減少混沌,並與 Kubernetes 深度整合。建議大規模叢集使用受管節點群組和 Karpenter。

受管節點群組將為您提供 Amazon EC2 Auto Scaling 群組的彈性,並為受管升級和組態提供額外優勢。它可以使用 Kubernetes Cluster Autoscaler 進行擴展,並且是具有各種運算需求的叢集的常見選項。

Karpenter 是由 AWS 建立的開放原始碼、工作負載原生節點自動擴展器。它會根據資源 (例如 GPU) 的工作負載需求,以及污點和容錯 (例如區域分散) 來擴展叢集中的節點,而無需管理節點群組。節點直接從 EC2 建立,可避免預設節點群組配額 - 每個群組 450 個節點 - 並提供更大的執行個體選擇彈性,並降低營運開銷。我們建議客戶盡可能使用 Karpenter。

使用許多不同的 EC2 執行個體類型

每個 AWS 區域每個執行個體類型的可用執行個體數量有限。如果您建立的叢集僅使用一種執行個體類型,並將節點數量擴展到超過區域的容量,您會收到沒有執行個體可用的錯誤。為了避免此問題,您不應任意限制叢集中可以使用的執行個體類型。

根據預設,Karpenter 將使用廣泛的相容執行個體類型,並根據待定工作負載需求、可用性和成本在佈建時挑選執行個體。您可以擴大 NodePools karpenter.k8s.aws/instance-category金鑰中使用的執行個體類型清單。

Kubernetes Cluster Autoscaler 需要類似大小的節點群組,才能持續擴展。您應該根據 CPU 和記憶體大小建立多個群組,並獨立擴展。使用 ec2-instance-selector 來識別節點群組大小相似的執行個體。

ec2-instance-selector --service eks --vcpus-min 8 --memory-min 16
a1.2xlarge
a1.4xlarge
a1.metal
c4.4xlarge
c4.8xlarge
c5.12xlarge
c5.18xlarge
c5.24xlarge
c5.2xlarge
c5.4xlarge
c5.9xlarge
c5.metal

偏好較大的節點來減少 API 伺服器負載

決定要使用的執行個體類型時,較少的大型節點會對 Kubernetes 控制平面造成較少的負載,因為會有較少的 kubelet 和執行中的 DaemonSets。不過,大型節點可能無法完全使用,就像較小的節點一樣。節點大小應根據您的工作負載可用性和擴展需求進行評估。

具有三個 u-24tb1.metal 執行個體 (24 TB 記憶體和 448 個核心) 的叢集有 3 個 kubelet,預設每個節點限制為 110 個 Pod。如果您的 Pod 各使用 4 個核心,則可能預期會發生這種情況 (4 個核心 x 110 = 440 個核心/節點)。使用 3 節點叢集時,處理執行個體事件的能力會很低,因為 1 個執行個體中斷可能會影響叢集的 1/3。您應該在工作負載中指定節點需求和 Pod,以便 Kubernetes 排程器可以正確放置工作負載。

工作負載應定義所需的資源,以及透過污點、容錯和 PodTopologySpread 所需的可用性。他們應該偏好可充分利用的最大節點,並符合可用性目標,以降低控制平面負載、降低操作並降低成本。

如果資源可用,Kubernetes 排程器會自動嘗試將工作負載分散到可用區域和主機。如果沒有可用的容量,Kubernetes Cluster Autoscaler 會嘗試在每個可用區域中平均新增節點。除非工作負載指定其他需求,否則 Karpenter 會嘗試盡可能快速且經濟實惠地新增節點。

若要強制工作負載隨著排程器和新節點分散到各個可用區域,您應該使用 topologySpreadConstraints:

spec:
  topologySpreadConstraints:
    - maxSkew: 3
      topologyKey: "topology.kubernetes.io/zone"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment
    - maxSkew: 2
      topologyKey: "kubernetes.io/hostname"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment

使用類似的節點大小來實現一致的工作負載效能

工作負載應該定義需要執行的節點大小,以允許一致的效能和可預測的擴展。請求 500 公尺 CPU 的工作負載在具有 4 個核心的執行個體上,與具有 16 個核心的執行個體上執行不同。避免使用爆量 CPUs執行個體類型,例如 T 系列執行個體。

為了確保工作負載獲得一致的效能,工作負載可以使用支援的 Karpenter 標籤來鎖定特定執行個體大小。

kind: deployment
...
spec:
  template:
    spec:
    containers:
    nodeSelector:
      karpenter.k8s.aws/instance-size: 8xlarge

使用 Kubernetes Cluster Autoscaler 在叢集中排程的工作負載,應根據標籤比對將節點選擇器與節點群組進行比對。

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/nodegroup
            operator: In
            values:
            - 8-core-node-group    # match your node group name

有效率地使用運算資源

運算資源包括 EC2 執行個體和可用區域。有效使用運算資源可提高您的可擴展性、可用性、效能,並降低您的總成本。在具有多個應用程式的自動擴展環境中,高效的資源使用非常困難。建立 Karpenter 是為了根據工作負載需求隨需佈建執行個體,以最大化使用率和彈性。

Karpenter 允許工作負載宣告所需的運算資源類型,而無需先建立節點群組或設定特定節點的標籤污點。如需詳細資訊,請參閱 Karpenter 最佳實務。請考慮在 Karpenter 佈建器中啟用整合,以取代使用率不足的節點。

自動化 Amazon Machine Image (AMI) 更新

將工作者節點元件保持在最新狀態,將確保您擁有最新的安全修補程式和與 Kubernetes API 相容的功能。更新 kubelet 是 Kubernetes 功能最重要的元件,但自動化作業系統、核心和本機安裝的應用程式修補程式將減少您擴展時的維護。

建議您為節點映像使用最新的 Amazon EKS 最佳化 Amazon Linux 2 或 Amazon EKS 最佳化 Bottlerocket AMI。Karpenter 將自動使用最新的可用 AMI 來佈建叢集中的新節點。受管節點群組會在節點群組更新期間更新 AMI,但不會在節點佈建時間更新 AMI ID。

對於受管節點群組,當新 AMI IDs 可用於修補程式版本時,您需要更新 Auto Scaling 群組 (ASG) 啟動範本。AMI 次要版本 (例如 1.23.5 到 1.24.3) 將可在 EKS 主控台和 API 中做為節點群組的升級。修補程式發行版本 (例如 1.23.5 到 1.23.6) 不會顯示為節點群組的升級。如果您想要讓節點群組與 AMI 修補程式版本保持最新狀態,您需要建立新的啟動範本版本,並讓節點群組將執行個體取代為新的 AMI 版本。

您可以從此頁面找到最新的可用 AMI,或使用 AWS CLI。

aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.24/amazon-linux-2/recommended/image_id \
  --query "Parameter.Value" \
  --output text

針對容器使用多個 EBS 磁碟區

重要

僅 AL2 支援此功能;AL2023 尚未支援此功能。

EBS 磁碟區具有根據磁碟區類型 (例如 gp3) 和磁碟大小的輸入/輸出 (I/O) 配額。如果您的應用程式與主機共用單一 EBS 根磁碟區,這可能會耗盡整個主機的磁碟配額,並導致其他應用程式等待可用容量。如果應用程式將檔案寫入其浮水印分割區、從主機掛載本機磁碟區,以及根據所使用的記錄代理程式登入標準輸出 (STDOUT),則會寫入磁碟。

為了避免磁碟 I/O 耗盡,您應該將第二個磁碟區掛載到容器狀態資料夾 (例如 /run/containerd),請使用個別的 EBS 磁碟區進行工作負載儲存,並停用不必要的本機記錄。

若要使用 eksctl 將第二個磁碟區掛載到您的 EC2 執行個體,您可以使用具有此組態的節點群組:

managedNodeGroups:
  - name: al2-workers
    amiFamily: AmazonLinux2
    desiredCapacity: 2
    volumeSize: 80
    additionalVolumes:
      - volumeName: '/dev/sdz'
        volumeSize: 100
    preBootstrapCommands:
    - |
      "systemctl stop containerd"
      "mkfs -t ext4 /dev/nvme1n1"
      "rm -rf /var/lib/containerd/*"
      "mount /dev/nvme1n1 /var/lib/containerd/"
      "systemctl start containerd"

如果您使用 terraform 佈建節點群組,請參閱 EKS terraform 藍圖中的範例。如果您使用 Karpenter 佈建節點,則可以blockDeviceMappings搭配使用節點使用者資料來新增其他磁碟區。

若要將 EBS 磁碟區直接掛載到您的 Pod,您應該使用 AWS EBS CSI 驅動程式,並使用具有儲存類別的磁碟區。

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: public.ecr.aws/docker/library/nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

如果工作負載使用 EBS 磁碟區,請避免具有低 EBS 連接限制的執行個體

EBS 是工作負載擁有持久性儲存的最簡單方法之一,但也附帶可擴展性限制。每個執行個體類型都有可連接的 EBS 磁碟區數量上限。工作負載需要宣告應該在哪些執行個體類型上執行,並限制具有 Kubernetes 污點的單一執行個體上的複本數量。

停用不必要的磁碟記錄

避免不必要的本機記錄,方法是不要在生產環境中使用偵錯記錄執行應用程式,並停用經常讀取和寫入磁碟的記錄。日誌記錄是本機日誌記錄服務,可將日誌緩衝區保留在記憶體中,並定期排清至磁碟。日誌優先於將每行立即記錄到磁碟的 syslog。停用 syslog 也會降低您需要的總儲存量,並避免需要複雜的日誌輪換規則。若要停用 syslog,您可以將下列程式碼片段新增至 cloud-init 組態:

runcmd:
  - [ systemctl, disable, --now, syslog.service ]

需要作業系統更新速度時,已備妥修補程式執行個體

重要

只有在需要時才應完成就地修補執行個體。Amazon 建議將基礎設施視為不可變且徹底測試透過較低環境提升的更新,就像應用程式一樣。本節適用於無法做到的情況。

在現有的 Linux 主機上安裝套件需要幾秒鐘的時間,而不會中斷容器化工作負載。套件可以安裝和驗證,無需封鎖、耗盡或取代執行個體。

若要取代執行個體,您必須先建立、驗證和分發新的 AMIs。執行個體需要建立替換,且舊執行個體需要封鎖和耗盡。然後,需要在新執行個體上建立工作負載,並針對所有需要修補的執行個體進行驗證和重複。安全地取代執行個體需要數小時、數天或數週的時間,而不會中斷工作負載。

Amazon 建議使用從自動化宣告式系統建置、測試和提升的不可變基礎設施,但如果您需要快速修補系統,則需要修補系統,並在新的 AMIs 可用時予以取代。由於修補和取代系統之間的時間差異很大,我們建議您在需要時使用 AWS Systems Manager Patch Manager 自動修補節點。

修補節點可讓您快速推出安全性更新,並在 AMI 更新後定期取代執行個體。如果您使用作業系統搭配唯讀根檔案系統,例如 Flatcar Container Linux 或 Bottlerocket OS,我們建議您使用適用於這些作業系統的更新運算子。Flatcar Linux 更新運算子和 Bottlerocket 更新運算子會重新啟動執行個體,讓節點自動保持最新狀態。

Karpenter 上自訂 AMIs Kubelet 組態

搭配 Karpenter 使用自訂 AMI 時,請務必仔細設定kubelet設定以確保最佳的資料平面可擴展性。與 EKS 最佳化 AMIs 不同,Karpenter 不具備自訂作業系統映像預設資源需求的內建知識。如果kubelet組態未正確調校,這可能會導致kubelet資源匱乏等問題。

為了解決此問題,建議的最佳實務是在使用自訂 AMI 時,在NodeClass組態中完整指定 kubelet 設定。這包括根據安裝在自訂 AMI 上的特定作業系統和套件,為 system-reserved和資源kube-reserved請求設定適當的值。此外,請仔細設定移出閾值,以確保 kubelet可以在資源壓力下有效地管理 Pod 移出。如需可用的組態選項和正確設定這些值的指引,請參閱 Karpenter 文件中的spec.kubelet一節。在部署後監控節點的資源使用率對於驗證kubelet設定和進行任何必要的調整也至關重要。透過遵循這些最佳實務,您可以確保 kubelet 已正確設定,以處理使用自訂 AMI 佈建之節點的工作負載需求。

kubelet: podsPerCore: 2 maxPods: 20 systemReserved: cpu: 100m memory: 100Mi ephemeral-storage: 1Gi kubeReserved: cpu: 200m memory: 100Mi ephemeral-storage: 3Gi evictionHard: memory.available: 5% nodefs.available: 10% nodefs.inodesFree: 10% evictionSoft: memory.available: 500Mi nodefs.available: 15% nodefs.inodesFree: 15% evictionSoftGracePeriod: memory.available: 1m nodefs.available: 1m30s nodefs.inodesFree: 2m evictionMaxPodGracePeriod: 60 imageGCHighThresholdPercent: 85 imageGCLowThresholdPercent: 80 cpuCFSQuota: true clusterDNS: ["10.0.1.100"]