前言:一個讓人懷疑人生的 Pending 狀態
最近部署 Strapi CMS 到 AWS EKS 時,遇到一個詭異的情況:
$ kubectl get pods -n default
NAME READY STATUS RESTARTS AGE
mycompany-strapi-prod-695854fbd4-dzw66 0/1 Pending 0 3h42m
一個 Pod 卡在 Pending 狀態超過三小時,CPU 和 Memory 明明還很充足,但就是起不來。
如果你曾經盯著 kubectl get pods 看著那個永遠不會變成 Running 的 Pending 狀態,同時懷疑是不是 Kubernetes 在跟你開玩笑——恭喜你,你不孤單。
在嘗試了 Google 前五個搜尋結果、檢查了三次 YAML 設定、並認真考慮是否該轉行當咖啡師之後,我終於找到了問題的根源…
⚠️ 劇透警告:問題的根源不是 CPU、不是 Memory,而是一個你可能從沒注意過的限制——網卡(ENI)和 IP 數量。
問題診斷:一步步找出真兇
Step 1:查看 Pod 事件
遇到 Pending 狀態,第一步當然是看看 Kubernetes 到底在抱怨什麼:
$ kubectl describe pod mycompany-strapi-prod-695854fbd4-dzw66 -n default
輸出內容很長,但最重要的是 Events 區塊:
Name: mycompany-strapi-prod-695854fbd4-dzw66
Namespace: default
Priority: 0
Node: <none>
Labels: app=strapi
pod-template-hash=695854fbd4
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Controlled By: ReplicaSet/mycompany-strapi-prod-695854fbd4
Containers:
strapi:
Image: mycompany/strapi:v1.2.3
Port: 1337/TCP
Host Port: 0/TCP
Requests:
cpu: 250m
memory: 512Mi
Limits:
cpu: 500m
memory: 1Gi
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3h default-scheduler 0/1 nodes are available:
1 Too many pods.
「Too many pods」?我只跑了十幾個 Pod,怎麼可能太多?
這個錯誤訊息極具誤導性。它讓你以為是 Pod 數量的「軟限制」問題,實際上是硬性的網路限制。
Step 2:檢查 Node 資源使用狀況
既然說 Pod 太多,那來看看 Node 的資源狀況:
$ kubectl describe node ip-10-0-1-xxx.ap-northeast-1.compute.internal
Name: ip-10-0-1-xxx.ap-northeast-1.compute.internal
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/instance-type=t3.medium
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=ip-10-0-1-xxx.ap-northeast-1.compute.internal
kubernetes.io/os=linux
node.kubernetes.io/instance-type=t3.medium
topology.kubernetes.io/region=ap-northeast-1
topology.kubernetes.io/zone=ap-northeast-1a
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 680m (35%) 1200m (61%)
memory 756Mi (22%) 1536Mi (44%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
CPU 使用 35%、Memory 使用 22%,資源明明還很充裕!
Step 3:發現關鍵線索——Pod 容量限制
繼續往下看 Node 的詳細資訊:
$ kubectl describe node <node-name> | grep -A 10 "Capacity"
Capacity:
attachable-volumes-aws-ebs: 25
cpu: 2
ephemeral-storage: 20959212Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3943376Ki
pods: 17 # 👈 注意這裡!
Allocatable:
attachable-volumes-aws-ebs: 25
cpu: 1930m
ephemeral-storage: 19316009748
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3388496Ki
pods: 17 # 👈 最大 Pod 數量是 17!
再查看目前執行中的 Pod 數量:
$ kubectl get pods -A --field-selector spec.nodeName=ip-10-0-1-xxx --no-headers | wc -l
17
真相大白:Node 上已經有 17 個 Pod,而這個 Node 的 Pod 上限剛好是 17!
但問題來了:為什麼 t3.medium 這種看起來還不錯的 Instance,Pod 上限只有 17 個?
深入理解:AWS VPC CNI 的運作機制
為什麼 EKS 要用 VPC CNI?
在深入 ENI 限制之前,我們先了解 EKS 的網路架構選擇。
Kubernetes 本身不處理 Pod 網路,而是依賴 CNI(Container Network Interface) 插件。常見的 CNI 插件包括:
- Calico:使用 BGP 或 VXLAN 建立虛擬網路
- Flannel:使用 VXLAN 或 host-gw 模式
- Weave:使用自己的虛擬網路協定
- AWS VPC CNI:直接使用 VPC 原生 IP
AWS EKS 預設使用 AWS VPC CNI,它的特別之處在於:
每個 Pod 都會獲得一個真實的 VPC IP 位址
VPC CNI 的優缺點
優點:
| 特性 | 說明 |
|---|---|
| ✅ 原生 VPC 整合 | Pod 可直接與 RDS、ElastiCache 等 VPC 資源通訊 |
| ✅ 無需 NAT | Pod IP 就是真實 VPC IP,不需要轉換 |
| ✅ 安全群組支援 | 可以直接對 Pod 套用 Security Groups |
| ✅ 網路效能 | 沒有 overlay 網路的額外開銷 |
| ✅ 除錯簡單 | IP 直接對應,方便追蹤網路問題 |
缺點:
| 特性 | 說明 |
|---|---|
| ❌ IP 數量限制 | 受限於 ENI 和 IP 配額 |
| ❌ Subnet 規劃 | 需要足夠大的 CIDR 區塊 |
| ❌ Pod 數量限制 | 比其他 CNI 方案更嚴格 |
ENI 是什麼?為什麼會有限制?
ENI(Elastic Network Interface) 是 AWS EC2 的虛擬網路卡。每個 ENI 可以:
- 綁定一個 Primary IP(主要 IP)
- 綁定多個 Secondary IP(次要 IP)
- 附加到 EC2 Instance
AWS 對每種 EC2 Instance 類型都有 ENI 和 IP 的限制,這些限制是硬性的,由底層硬體和網路架構決定。
Pod 數量計算公式
AWS VPC CNI 的 Pod 數量上限計算公式為:
Max Pods = (ENI 數量 × 每個 ENI 的 IP 數) - ENI 數量
為什麼要減掉 ENI 數量?
因為每個 ENI 的 Primary IP 是保留給 ENI 本身使用的,不能分配給 Pod。只有 Secondary IP 可以用於 Pod。
以 t3.medium 為例
t3.medium 的限制:
├─ 最大 ENI 數量:3
└─ 每個 ENI 的 IPv4 數量:6
計算過程:
├─ 總 IP 數:3 × 6 = 18 個
├─ Primary IP(保留):3 個
└─ 可用於 Pod:18 - 3 = 15 個
實際上 EKS 顯示的是 17,這是因為:
└─ AWS 有一些額外的優化和 CNI 版本差異
常見 Instance 類型的 Pod 限制
| Instance 類型 | vCPU | Memory | ENI 數量 | 每 ENI IP 數 | Max Pods | 適用場景 |
|---|---|---|---|---|---|---|
| t3.micro | 2 | 1 GB | 2 | 2 | 4 | 學習/測試 |
| t3.small | 2 | 2 GB | 3 | 4 | 11 | 小型開發 |
| t3.medium | 2 | 4 GB | 3 | 6 | 17 | 開發/小型生產 |
| t3.large | 2 | 8 GB | 3 | 12 | 35 | 中型生產 |
| t3.xlarge | 4 | 16 GB | 4 | 15 | 58 | 大型生產 |
| t3.2xlarge | 8 | 32 GB | 4 | 15 | 58 | 高負載生產 |
| m5.large | 2 | 8 GB | 3 | 10 | 29 | 生產環境 |
| m5.xlarge | 4 | 16 GB | 4 | 15 | 58 | 高負載生產 |
| m5.2xlarge | 8 | 32 GB | 4 | 15 | 58 | 大型應用 |
| c5.large | 2 | 4 GB | 3 | 10 | 29 | 運算密集 |
| c5.xlarge | 4 | 8 GB | 4 | 15 | 58 | 高運算需求 |
| r5.large | 2 | 16 GB | 3 | 10 | 29 | 記憶體密集 |
視覺化診斷流程
當你遇到 Pod Pending 問題時,可以按照以下流程進行診斷:
快速診斷指令
#!/bin/bash
# quick-diagnosis.sh - EKS Pod Capacity 快速診斷腳本
echo "======================================"
echo "EKS Pod Capacity 診斷報告"
echo "======================================"
echo ""
# 取得所有 Node
for node in $(kubectl get nodes -o name); do
node_name=$(echo $node | cut -d'/' -f2)
echo "📍 Node: $node_name"
echo "-----------------------------------"
# 取得 Instance 類型
instance_type=$(kubectl get $node -o jsonpath='{.metadata.labels.node\.kubernetes\.io/instance-type}')
echo " Instance Type: $instance_type"
# 取得 Pod 容量
max_pods=$(kubectl get $node -o jsonpath='{.status.allocatable.pods}')
echo " Max Pods: $max_pods"
# 取得目前 Pod 數
current_pods=$(kubectl get pods -A --field-selector spec.nodeName=$node_name --no-headers 2>/dev/null | wc -l)
echo " Current Pods: $current_pods"
# 計算使用率
if [ "$max_pods" -gt 0 ]; then
usage=$((current_pods * 100 / max_pods))
echo " Usage: ${usage}%"
# 警告訊息
if [ $usage -ge 90 ]; then
echo " ⚠️ WARNING: Pod 容量即將耗盡!"
elif [ $usage -ge 80 ]; then
echo " ⚡ NOTICE: Pod 容量使用率較高"
else
echo " ✅ OK: Pod 容量充足"
fi
fi
echo ""
done
echo "======================================"
echo "診斷完成"
echo "======================================"
執行結果範例:
======================================
EKS Pod Capacity 診斷報告
======================================
📍 Node: ip-10-0-1-101.ap-northeast-1.compute.internal
-----------------------------------
Instance Type: t3.medium
Max Pods: 17
Current Pods: 17
Usage: 100%
⚠️ WARNING: Pod 容量即將耗盡!
📍 Node: ip-10-0-1-102.ap-northeast-1.compute.internal
-----------------------------------
Instance Type: t3.medium
Max Pods: 17
Current Pods: 12
Usage: 70%
✅ OK: Pod 容量充足
======================================
診斷完成
======================================
五種解決方案詳解
方案一:水平擴展(增加 Node 數量)
適用場景:
- 需要快速解決問題
- 預算允許
- 希望同時增加整體運算能力
使用 eksctl 擴展:
# 查看目前的 Node Group
eksctl get nodegroup --cluster=my-cluster
# 擴展 Node 數量
eksctl scale nodegroup \
--cluster=my-cluster \
--name=my-nodegroup \
--nodes=3 \
--nodes-min=2 \
--nodes-max=5
使用 AWS CLI 擴展:
aws eks update-nodegroup-config \
--cluster-name my-cluster \
--nodegroup-name my-nodegroup \
--scaling-config minSize=2,maxSize=5,desiredSize=3
優缺點分析:
| 優點 | 缺點 |
|---|---|
| ✅ 最直接的解決方案 | ❌ 成本增加 |
| ✅ 同時增加運算能力 | ❌ 可能造成資源浪費 |
| ✅ 提高整體可用性 | ❌ 需要更多管理 |
| ✅ 無需修改應用程式 | ❌ Subnet IP 消耗增加 |
方案二:垂直擴展(升級 Instance 類型)
適用場景:
- 單個 Pod 資源需求大
- 希望在較少 Node 上運行更多 Pod
- 需要更高的單機效能
Instance 升級建議路徑:
使用 eksctl 更新 Node Group:
# nodegroup-config.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: ap-northeast-1
managedNodeGroups:
- name: production-ng
instanceType: t3.large # 從 t3.medium 升級
desiredCapacity: 2
minSize: 1
maxSize: 4
volumeSize: 50
volumeType: gp3
labels:
role: production
environment: prod
tags:
Owner: DevOps
Project: MyApp
iam:
withAddonPolicies:
autoScaler: true
cloudWatch: true
# 建立新的 Node Group
eksctl create nodegroup -f nodegroup-config.yaml
# 刪除舊的 Node Group(確保 Pod 已遷移後)
eksctl delete nodegroup \
--cluster=my-cluster \
--name=old-nodegroup
方案三:啟用 Cluster Autoscaler
適用場景:
- Pod 數量會動態變化
- 希望自動調整成本
- 需要應對流量高峰
架構圖:
Step 1:設定 Node Group Tags
# 在 AWS Console 或使用 CLI 為 Auto Scaling Group 加上這些 tag
aws autoscaling create-or-update-tags \
--tags \
"ResourceId=my-asg-name,ResourceType=auto-scaling-group,Key=k8s.io/cluster-autoscaler/enabled,Value=true,PropagateAtLaunch=true" \
"ResourceId=my-asg-name,ResourceType=auto-scaling-group,Key=k8s.io/cluster-autoscaler/my-cluster,Value=owned,PropagateAtLaunch=true"
Step 2:部署 Cluster Autoscaler
# cluster-autoscaler.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
labels:
app: cluster-autoscaler
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
spec:
serviceAccountName: cluster-autoscaler
containers:
- name: cluster-autoscaler
image: registry.k8s.io/autoscaling/cluster-autoscaler:v1.28.0
command:
- ./cluster-autoscaler
- --v=4
- --stderrthreshold=info
- --cloud-provider=aws
- --skip-nodes-with-local-storage=false
- --expander=least-waste
- --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/my-cluster
- --balance-similar-node-groups
- --skip-nodes-with-system-pods=false
resources:
limits:
cpu: 100m
memory: 600Mi
requests:
cpu: 100m
memory: 600Mi
env:
- name: AWS_REGION
value: ap-northeast-1
kubectl apply -f cluster-autoscaler.yaml
Step 3:建立 IAM 權限
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeScalingActivities",
"autoscaling:DescribeTags",
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup",
"ec2:DescribeLaunchTemplateVersions",
"ec2:DescribeInstanceTypes"
],
"Resource": "*"
}
]
}
方案四:啟用 VPC CNI Prefix Delegation(進階)
適用場景:
- 需要在同一個 Node 上運行大量小型 Pod
- 希望最大化單一 Node 的 Pod 密度
- Subnet 有足夠的 IP 空間
什麼是 Prefix Delegation?
原本 VPC CNI 是為每個 Pod 分配單一 IP,Prefix Delegation 改為分配一個 /28 的 IP 前綴(16 個 IP)給每個 ENI slot。
比較:
| 模式 | 每個 ENI slot | t3.medium Max Pods |
|---|---|---|
| 傳統模式 | 1 個 IP | 17 |
| Prefix Delegation | 16 個 IP (/28) | 110 |
啟用步驟:
# Step 1: 更新 VPC CNI 到最新版本
kubectl describe daemonset aws-node -n kube-system | grep Image
# Step 2: 啟用 Prefix Delegation
kubectl set env daemonset aws-node \
-n kube-system \
ENABLE_PREFIX_DELEGATION=true
# Step 3: 設定 warm pool(預先分配的 IP prefix 數量)
kubectl set env daemonset aws-node \
-n kube-system \
WARM_PREFIX_TARGET=1
# Step 4: 驗證設定
kubectl get ds aws-node -n kube-system -o yaml | grep -A 5 "env:"
注意事項:
⚠️ 重要考量:
- 需要 VPC CNI 版本 1.9.0 以上
- 需要 Nitro-based Instance(大多數新型 Instance 都支援)
- Subnet 需要足夠大的 CIDR(建議至少 /19)
- 現有 Node 需要 drain 並重新加入
驗證腳本:
#!/bin/bash
# verify-prefix-delegation.sh
echo "檢查 VPC CNI 設定..."
# 檢查 CNI 版本
cni_version=$(kubectl get ds aws-node -n kube-system -o jsonpath='{.spec.template.spec.containers[0].image}' | grep -oP 'v\d+\.\d+\.\d+')
echo "VPC CNI 版本: $cni_version"
# 檢查 Prefix Delegation 狀態
prefix_enabled=$(kubectl get ds aws-node -n kube-system -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="ENABLE_PREFIX_DELEGATION")].value}')
echo "Prefix Delegation: ${prefix_enabled:-未啟用}"
# 檢查 Node 的 max-pods
for node in $(kubectl get nodes -o name); do
node_name=$(echo $node | cut -d'/' -f2)
max_pods=$(kubectl get $node -o jsonpath='{.status.allocatable.pods}')
echo "Node $node_name - Max Pods: $max_pods"
done
方案五:使用 AWS Fargate(無伺服器)
適用場景:
- Stateless 服務
- 測試環境
- 不想管理 Node
- 需要快速擴展
架構比較:
建立 Fargate Profile:
# fargate-profile.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: ap-northeast-1
fargateProfiles:
- name: fp-default
selectors:
# Namespace 選擇器
- namespace: staging
labels:
compute-type: fargate
- namespace: dev
# 特定 workload 選擇器
- namespace: production
labels:
workload-type: stateless
eksctl create fargateprofile -f fargate-profile.yaml
將 Pod 部署到 Fargate:
# deployment-fargate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: staging # 匹配 Fargate Profile 的 namespace
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
compute-type: fargate # 匹配 Fargate Profile 的 label
spec:
containers:
- name: app
image: my-app:latest
resources:
requests:
cpu: "256m"
memory: "512Mi"
limits:
cpu: "512m"
memory: "1Gi"
Fargate 優缺點分析:
| 優點 | 缺點 |
|---|---|
| ✅ 無需管理 Node | ❌ 啟動時間較長(30-60 秒) |
| ✅ 按實際使用付費 | ❌ 不支援 DaemonSet |
| ✅ 自動擴展 | ❌ 不支援 GPU |
| ✅ 無 Pod 數量限制 | ❌ 某些 CSI Driver 不支援 |
| ✅ 安全隔離(每 Pod 獨立 VM) | ❌ 無法 SSH 進入 Node |
| ✅ 自動套用安全更新 | ❌ 成本可能較高 |
快速解法:清理不需要的 Pod
如果你只是臨時需要空間,最快的方法是找出並刪除不必要的 Pod:
# 查看所有 Pod 的資源使用狀況(按 memory 排序)
kubectl top pods -A --sort-by=memory
# 查看所有 Pod(按啟動時間排序)
kubectl get pods -A -o wide --sort-by='.status.startTime'
# 找出長時間運行的 Pod
kubectl get pods -A -o custom-columns=\
NAMESPACE:.metadata.namespace,\
NAME:.metadata.name,\
STATUS:.status.phase,\
AGE:.metadata.creationTimestamp \
--sort-by='.metadata.creationTimestamp'
# 刪除特定 Pod(如果有 Deployment,會自動重建)
kubectl delete pod <pod-name> -n <namespace>
# 完全移除一個服務
kubectl delete deployment <deployment-name> -n <namespace>
# 檢查是否有 Completed 或 Failed 的 Pod 可以清理
kubectl get pods -A | grep -E 'Completed|Error|Failed'
kubectl delete pods -A --field-selector=status.phase==Succeeded
kubectl delete pods -A --field-selector=status.phase==Failed
我的情況: 刪除了一個用於測試的 debug Pod,Strapi 就成功啟動了。
(經過三小時的 debug 和兩杯咖啡的犧牲,問題終於解決。)
預防措施:監控 Pod 容量
建立 CloudWatch 告警
# 使用 AWS CLI 建立告警
aws cloudwatch put-metric-alarm \
--alarm-name "EKS-Pod-Capacity-Warning" \
--alarm-description "Pod capacity usage exceeds 80%" \
--metric-name "pod_count" \
--namespace "ContainerInsights" \
--dimensions Name=ClusterName,Value=my-cluster \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--alarm-actions arn:aws:sns:ap-northeast-1:123456789012:alerts
使用 Prometheus 監控
# prometheus-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: pod-capacity-alerts
namespace: monitoring
spec:
groups:
- name: pod-capacity
rules:
- alert: HighPodUtilization
expr: |
sum(kube_pod_status_phase{phase="Running"}) by (node)
/
sum(kube_node_status_allocatable{resource="pods"}) by (node)
> 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "Node {{ $labels.node }} Pod 使用率超過 80%"
description: "Node {{ $labels.node }} 的 Pod 使用率已達 {{ $value | humanizePercentage }},請考慮擴展。"
- alert: CriticalPodUtilization
expr: |
sum(kube_pod_status_phase{phase="Running"}) by (node)
/
sum(kube_node_status_allocatable{resource="pods"}) by (node)
> 0.95
for: 2m
labels:
severity: critical
annotations:
summary: "Node {{ $labels.node }} Pod 容量即將耗盡!"
description: "Node {{ $labels.node }} 的 Pod 使用率已達 {{ $value | humanizePercentage }},可能導致新 Pod 無法排程。"
定期檢查腳本(加入 cron job)
#!/bin/bash
# /usr/local/bin/check-pod-capacity.sh
LOG_FILE="/var/log/pod-capacity-check.log"
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"
echo "$(date): Starting pod capacity check" >> $LOG_FILE
WARNING_NODES=""
for node in $(kubectl get nodes -o name); do
node_name=$(echo $node | cut -d'/' -f2)
max_pods=$(kubectl get $node -o jsonpath='{.status.allocatable.pods}')
current_pods=$(kubectl get pods -A --field-selector spec.nodeName=$node_name --no-headers | wc -l)
if [ "$max_pods" -gt 0 ]; then
usage=$((current_pods * 100 / max_pods))
if [ $usage -ge 80 ]; then
WARNING_NODES="$WARNING_NODES\n- $node_name: ${usage}% ($current_pods/$max_pods)"
fi
fi
done
if [ -n "$WARNING_NODES" ]; then
# 發送 Slack 通知
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"⚠️ EKS Pod Capacity Warning\n\nThe following nodes have high pod utilization:$WARNING_NODES\"}" \
$SLACK_WEBHOOK
echo "$(date): Warning sent for nodes:$WARNING_NODES" >> $LOG_FILE
fi
echo "$(date): Check completed" >> $LOG_FILE
# 加入 crontab,每 15 分鐘檢查一次
*/15 * * * * /usr/local/bin/check-pod-capacity.sh
架構規劃建議
經過這次踩坑,我總結了幾個 EKS 架構規劃的重點:
1. 依環境分離 Node Group
2. 選擇適當的 Instance 類型
| 用途 | 建議 Instance | 原因 |
|---|---|---|
| System Pods | t3.small / t3.medium | 系統元件數量固定,不需太大 |
| Production | m5.large / m5.xlarge | 平衡的 CPU/Memory,足夠的 Pod 容量 |
| CPU 密集 | c5.large / c5.xlarge | 高 CPU 配置 |
| Memory 密集 | r5.large / r5.xlarge | 高 Memory 配置 |
| 開發測試 | t3.medium | 成本較低,足夠測試用途 |
3. 規劃足夠的 VPC CIDR
如果計劃使用 Prefix Delegation,確保 Subnet 有足夠的 IP 空間:
建議規劃:
├─ VPC CIDR: /16(65,536 個 IP)
├─ 每個 AZ 的 Subnet: /19(8,192 個 IP)
└─ 預留給 Pod 的空間: 至少 /20 per AZ
結語:EKS Pod 限制的真相
這次經驗讓我深刻體會到,EKS 的「Pod 數限制」是一個經常被誤解的概念:
📌 記住:EKS 上 Pod 數上限 ≠ CPU/Memory 限制,而是 ENI + IP 的網路限制!
當你看到「Too many pods」錯誤時,不要急著加 CPU 或 Memory,而是要:
- 檢查 Instance 類型的 ENI/IP 限制
- 評估是否需要升級 Instance 或增加 Node
- 考慮啟用 Prefix Delegation 或使用 Fargate
- 建立監控機制,提早發現問題
希望這篇文章能幫你省下我花掉的那三小時。至於那兩杯咖啡的錢,就當作是我請你的。☕
