在 Day 13,我們透過 App-of-Apps 解決了「多應用管理」的問題;在 Day 14,我們用 Helm Manager 處理了「同一應用需要部署在多個 cluster」的挑戰。
接下來,我們的重點要轉到基礎設施層的 Helm Charts,也就是昨天在 Helm Manager 中介紹到的 infra charts。這些元件(像是 ingress-nginx、prometheus、karpenter)屬於所有專案 cluster 都需要安裝的基礎建設,因此會用 Helm Manager 架構來部署,確保多叢集之間的一致性。
今天的主角是 Karpenter —— 它能讓我們的 EKS 叢集從「固定 Node Group」進化到「動態調度與彈性節點供應」。
在我們的架構裡,最一開始是透過 EKS Managed Node Group 來提供節點。它背後其實就是一個 Auto Scaling Group (ASG),所以在擴縮容和彈性上會遇到一些常見限制:
相較之下,Karpenter 提供了更好的解法(這些優勢也在 AWS 官方文件中被強調):
簡單來說,Node Group 適合小規模、穩定需求;而 Karpenter 則是為大規模、變動性高的叢集而生。
在 v1.3+ 的版本中,Karpenter 把資源拆成三個物件:
NodeClass:AWS 層級的設定範本(AMI、AZ、Instance Type、Spot/OnDemand、網路配置)。舉例如下:
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: system
spec:
### KEY POINT: AMI 選擇設定
### K8s 各版本適合的 AMI 可參考:https://github.com/awslabs/amazon-eks-ami/releases
amiFamily: AL2
amiSelectorTerms:
- alias: al2@v20250304
### KEY POINT: Instance 的 EBS 設定
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
encrypted: true
volumeSize: 20Gi
volumeType: gp2
### KEY POINT: 我們會在 EKS module 裡面就寫好各個 infra-charts 的 IRSA terraform module,幫我們建出各個 infra charts 所需要的 IAM role,後續範例都會這樣直接填入哦
role: Karpenter-example-internal
securityGroupSelectorTerms:
### KEY POINT: 開啟新的 instance 時,掛載有這個 tag 的 security group
- tags:
karpenter.sh/discovery: example-internal
subnetSelectorTerms:
### KEY POINT: 將新的 instance 放到含有這個 tag 的 subnet 中
- tags:
karpenter.sh/discovery: example-internal
tags:
karpenter.sh/discovery: example-internal
NodePool:Kubernetes 層級的規則,描述哪些 Pod 可以使用、taints、labels。舉例如下:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: system
spec:
limits:
cpu: '10'
template:
metadata:
labels:
usage: system
spec:
expireAfter: 720h
### KEY POINT: Reference 到我們上面建立的 NodeClass
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: system
requirements:
### KEY POINT: 可以選擇使用 on-demand 或 spot instance
### Spot instance 通常會比 on-demand 再更便宜,但也相對更容易被收走
- key: karpenter.sh/capacity-type
operator: In
values:
- on-demand
### KEY POINT: 列出候選的機型
- key: node.kubernetes.io/instance-type
operator: In
values:
- t4g.small
- t4g.medium
### KEY POINT: NodePool level 可以設置 Node Taint 讓我們方便管理
taints:
- effect: NoSchedule
key: SystemOnly
value: 'true'
NodeClaim:Karpenter 實際建立的節點,可以看作是 NodeClass + NodePool 的具體結果。NodeClaim 並不需要手動建立,而是 Karpenter 根據 Pod 的需求,自動生成的節點物件。
Consolidation 概念:Karpenter 除了能自動擴容以外,還能自動縮容。我們可以在 NodePool level 設置 disruption budget 以及 consolidation policy,當某些節點變得空閒時,Karpenter 會:
Consolidation 的細節可以參考我寫過的文章:Karpenter Consolidation & Disruption Budget
延續 Day 14 的 Helm Manager 架構,Karpenter 是以 infra chart 的形式被管理:
infra-charts/karpenter/*-internal
目錄底下的 values.yaml,只要有新增 values file,對應 cluster 就會自動生成一個 Karpenter application。以下是我們在 ApplicationSet 裡的設定:
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: karpenter
### KEY POINT: 這邊的 Value 會從 Helm Manager 的 root app 注入
namespace: {{ .Values.applicationSetNs }}
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: {{ .Values.repoURL }}
revision: main
### KEY POINT: 讓 ArgoCD 根據什麼路徑來長出對應的 Application
directories:
- path: infra-charts/karpenter/*-internal
- path: infra-charts/karpenter/in-cluster/*-internal
template:
metadata:
### KEY POINT: ApplicationSet 的特殊寫法
name: '{{"{{"}} .path.basename {{"}}"}}-karpenter'
spec:
project: {{ .Values.project }}
sources:
- repoURL: {{ .Values.repoURL }}
path: "infra-charts/karpenter/chart"
targetRevision: main
helm:
valueFiles:
- /{{"{{"}} .path.path {{"}}"}}/values.yaml
destination:
name: '{{"{{"}} index .path.segments 2 {{"}}"}}'
namespace: kube-system
syncPolicy:
preserveResourcesOnDeletion: true
這樣,我們只需要把對應 cluster 的 values.yaml 放到正確目錄,ApplicationSet 就會在對應 cluster 裡自動建立出 Karpenter Application。
🔑 注意:ApplicationSet 使用上有些特殊語法,基本 template 細節可以參考文件。另外我們採用的是 Git Generator,這個 generator 可用的參數也可以參考這篇文件。
可以看到這邊 general NodePool 已經有長出兩個 NodeClaim 了,也就是 Karpenter 已經幫我們開好兩台 general 機型的節點、並且成功納管到 EKS 之下。
今天我們讓 Karpenter 納入 Helm Manager 架構,實現了:
透過這些特性,我們的叢集從節點層開始具備了更高的彈性與效率。但節點只是基礎,要讓外部流量能夠順利進入叢集,還需要 流量入口 (Ingress)。
因此在 Day 16,我們會來介紹 Ingress NGINX —— 最常見的 Kubernetes Ingress Controller,負責處理 HTTP/S 流量的 routing / reverse proxy / load balancing(別擔心這些明天都會講到),這也會回扣到我們 Day 6 聊到的 ingress & service 的概念,也能夠為我們後續了解 Load Balancer Controller 及 NLB/ALB 奠定穩固的基礎。