AWS EKS 叢集升級與維護

AWS EKS Cluster Upgrade and Maintenance

EKS 升級概述

Amazon EKS 叢集升級是維護 Kubernetes 環境安全性和穩定性的重要工作。AWS 會定期發布新版本的 Kubernetes,每個版本通常支援約 14 個月。升級叢集可以獲得最新的功能、安全修補和效能改進。

升級路徑說明

EKS 叢集升級必須按照版本順序進行,不支援跨版本升級。例如,從 1.27 升級到 1.29 必須先升級到 1.28,再升級到 1.29。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查看目前叢集版本
aws eks describe-cluster \
  --name my-eks-cluster \
  --query "cluster.version" \
  --output text

# 查看可用的 Kubernetes 版本
aws eks describe-addon-versions \
  --query "addons[].addonVersions[].compatibilities[].clusterVersion" \
  --output text | tr '\t' '\n' | sort -u

升級元件順序

建議的升級順序如下:

  1. 控制平面(Control Plane)
  2. 核心附加元件(Add-ons)
  3. 節點群組(Node Groups)
  4. 應用程式相容性驗證

升級前準備工作

備份叢集資源

在升級前,務必備份所有重要的 Kubernetes 資源:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 建立備份目錄
mkdir -p eks-backup/$(date +%Y%m%d)
cd eks-backup/$(date +%Y%m%d)

# 備份所有 namespace
kubectl get namespaces -o yaml > namespaces.yaml

# 備份所有 deployments
kubectl get deployments --all-namespaces -o yaml > deployments.yaml

# 備份所有 services
kubectl get services --all-namespaces -o yaml > services.yaml

# 備份所有 configmaps
kubectl get configmaps --all-namespaces -o yaml > configmaps.yaml

# 備份所有 secrets
kubectl get secrets --all-namespaces -o yaml > secrets.yaml

# 備份 persistent volumes
kubectl get pv -o yaml > persistent-volumes.yaml
kubectl get pvc --all-namespaces -o yaml > persistent-volume-claims.yaml

# 使用 Velero 進行完整備份(推薦)
velero backup create pre-upgrade-backup --include-namespaces '*'

檢視叢集現況

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看叢集基本資訊
aws eks describe-cluster --name my-eks-cluster --output table

# 列出所有節點群組
aws eks list-nodegroups --cluster-name my-eks-cluster

# 查看節點狀態
kubectl get nodes -o wide

# 查看所有 pod 狀態
kubectl get pods --all-namespaces -o wide | grep -v Running

檢查叢集相容性

檢查 API 棄用項目

Kubernetes 每個版本都會棄用某些 API,升級前需要確認應用程式沒有使用已棄用的 API:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 安裝 pluto 工具檢查棄用 API
wget https://github.com/FairwindsOps/pluto/releases/download/v5.18.0/pluto_5.18.0_linux_amd64.tar.gz
tar -xzf pluto_5.18.0_linux_amd64.tar.gz
sudo mv pluto /usr/local/bin/

# 檢查叢集中的棄用 API
pluto detect-helm -o wide
pluto detect-files -d ./manifests -o wide

# 檢查特定版本的棄用項目
pluto detect-helm --target-versions k8s=v1.29.0

檢查 Add-ons 相容性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 列出目前安裝的 add-ons
aws eks list-addons --cluster-name my-eks-cluster

# 查看每個 add-on 的版本資訊
for addon in $(aws eks list-addons --cluster-name my-eks-cluster --query 'addons[]' --output text); do
  echo "=== $addon ==="
  aws eks describe-addon \
    --cluster-name my-eks-cluster \
    --addon-name $addon \
    --query 'addon.{name:addonName,version:addonVersion,status:status}'
done

# 查看目標版本支援的 add-on 版本
aws eks describe-addon-versions \
  --kubernetes-version 1.29 \
  --addon-name vpc-cni \
  --query 'addons[].addonVersions[].addonVersion'

檢查 Pod Disruption Budgets

1
2
3
4
5
# 列出所有 PDB
kubectl get pdb --all-namespaces

# 檢查 PDB 設定是否允許節點排程
kubectl describe pdb -n kube-system

升級控制平面

使用 AWS CLI 升級

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 開始升級控制平面(此操作約需 20-30 分鐘)
aws eks update-cluster-version \
  --name my-eks-cluster \
  --kubernetes-version 1.29

# 追蹤升級進度
aws eks describe-update \
  --name my-eks-cluster \
  --update-id <update-id>

# 持續監控升級狀態
watch -n 30 "aws eks describe-cluster --name my-eks-cluster --query 'cluster.{status:status,version:version}'"

使用 eksctl 升級

1
2
3
4
5
6
7
8
# 使用 eksctl 升級控制平面
eksctl upgrade cluster \
  --name my-eks-cluster \
  --version 1.29 \
  --approve

# 檢查升級狀態
eksctl get cluster --name my-eks-cluster

驗證控制平面升級

1
2
3
4
5
6
7
8
# 確認控制平面版本
kubectl version --short

# 檢查 API server 健康狀態
kubectl get --raw='/healthz'

# 驗證核心元件運作正常
kubectl get pods -n kube-system

升級 Node Groups

升級 Managed Node Groups

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 列出節點群組及其版本
aws eks list-nodegroups --cluster-name my-eks-cluster

# 查看節點群組詳細資訊
aws eks describe-nodegroup \
  --cluster-name my-eks-cluster \
  --nodegroup-name standard-workers

# 升級節點群組
aws eks update-nodegroup-version \
  --cluster-name my-eks-cluster \
  --nodegroup-name standard-workers \
  --kubernetes-version 1.29

# 監控升級進度
aws eks describe-nodegroup \
  --cluster-name my-eks-cluster \
  --nodegroup-name standard-workers \
  --query 'nodegroup.{status:status,version:version}'

使用 eksctl 升級節點群組

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 升級所有 managed node groups
eksctl upgrade nodegroup \
  --cluster my-eks-cluster \
  --name standard-workers \
  --kubernetes-version 1.29

# 或建立新的節點群組並遷移工作負載
eksctl create nodegroup \
  --cluster my-eks-cluster \
  --name standard-workers-v129 \
  --node-type t3.medium \
  --nodes 3 \
  --nodes-min 1 \
  --nodes-max 5 \
  --version 1.29

節點滾動更新策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 設定節點群組更新策略
aws eks update-nodegroup-config \
  --cluster-name my-eks-cluster \
  --nodegroup-name standard-workers \
  --update-config maxUnavailable=1

# 手動排空節點(如需精細控制)
kubectl cordon <node-name>
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data

# 確認 pod 已遷移
kubectl get pods -o wide --all-namespaces | grep <node-name>

升級 Add-ons

升級 VPC CNI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 查看目前版本
aws eks describe-addon \
  --cluster-name my-eks-cluster \
  --addon-name vpc-cni

# 取得建議版本
aws eks describe-addon-versions \
  --kubernetes-version 1.29 \
  --addon-name vpc-cni \
  --query 'addons[0].addonVersions[0].addonVersion' \
  --output text

# 升級 VPC CNI
aws eks update-addon \
  --cluster-name my-eks-cluster \
  --addon-name vpc-cni \
  --addon-version v1.16.0-eksbuild.1 \
  --resolve-conflicts OVERWRITE

升級 CoreDNS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 查看目前 CoreDNS 版本
kubectl get deployment coredns -n kube-system -o jsonpath='{.spec.template.spec.containers[0].image}'

# 升級 CoreDNS
aws eks update-addon \
  --cluster-name my-eks-cluster \
  --addon-name coredns \
  --addon-version v1.11.1-eksbuild.4 \
  --resolve-conflicts OVERWRITE

# 驗證升級
kubectl rollout status deployment/coredns -n kube-system

升級 kube-proxy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 查看目前版本
kubectl get daemonset kube-proxy -n kube-system -o jsonpath='{.spec.template.spec.containers[0].image}'

# 升級 kube-proxy
aws eks update-addon \
  --cluster-name my-eks-cluster \
  --addon-name kube-proxy \
  --addon-version v1.29.0-eksbuild.1 \
  --resolve-conflicts OVERWRITE

# 驗證升級
kubectl rollout status daemonset/kube-proxy -n kube-system

批次升級所有 Add-ons

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
CLUSTER_NAME="my-eks-cluster"
K8S_VERSION="1.29"

# 取得所有 add-ons
ADDONS=$(aws eks list-addons --cluster-name $CLUSTER_NAME --query 'addons[]' --output text)

for ADDON in $ADDONS; do
  echo "升級 $ADDON..."

  # 取得建議版本
  RECOMMENDED_VERSION=$(aws eks describe-addon-versions \
    --kubernetes-version $K8S_VERSION \
    --addon-name $ADDON \
    --query 'addons[0].addonVersions[0].addonVersion' \
    --output text)

  # 執行升級
  aws eks update-addon \
    --cluster-name $CLUSTER_NAME \
    --addon-name $ADDON \
    --addon-version $RECOMMENDED_VERSION \
    --resolve-conflicts OVERWRITE

  echo "$ADDON 升級至 $RECOMMENDED_VERSION"
done

升級後驗證

叢集健康檢查

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 檢查所有節點狀態
kubectl get nodes -o wide

# 確認所有節點版本一致
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'

# 檢查核心元件健康
kubectl get componentstatuses
kubectl get pods -n kube-system

# 檢查所有 pod 狀態
kubectl get pods --all-namespaces | grep -v Running | grep -v Completed

應用程式驗證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 檢查所有 deployment 狀態
kubectl get deployments --all-namespaces

# 檢查所有 service endpoints
kubectl get endpoints --all-namespaces

# 測試 DNS 解析
kubectl run test-dns --image=busybox:1.28 --rm -it --restart=Never -- nslookup kubernetes.default

# 測試網路連通性
kubectl run test-network --image=busybox:1.28 --rm -it --restart=Never -- wget -qO- http://kubernetes.default.svc.cluster.local/healthz

效能基準測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 部署效能測試 pod
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: performance-test
spec:
  containers:
  - name: test
    image: alpine
    command: ["sleep", "3600"]
EOF

# 執行基本效能測試
kubectl exec -it performance-test -- sh -c "time wget -qO- http://kubernetes.default.svc.cluster.local/healthz"

# 清理測試資源
kubectl delete pod performance-test

回滾策略

控制平面回滾

EKS 控制平面升級後無法直接回滾,需要透過以下方式處理:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 方法一:建立新叢集並遷移
# 1. 建立舊版本的新叢集
eksctl create cluster \
  --name my-eks-cluster-rollback \
  --version 1.28 \
  --region ap-northeast-1

# 2. 從備份還原資源
velero restore create --from-backup pre-upgrade-backup

# 3. 更新 DNS 或負載平衡器指向新叢集

節點群組回滾

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 建立舊版本節點群組
eksctl create nodegroup \
  --cluster my-eks-cluster \
  --name standard-workers-rollback \
  --node-type t3.medium \
  --nodes 3 \
  --version 1.28

# 排空新版本節點
kubectl cordon -l eks.amazonaws.com/nodegroup=standard-workers-v129
kubectl drain -l eks.amazonaws.com/nodegroup=standard-workers-v129 --ignore-daemonsets --delete-emptydir-data

# 刪除新版本節點群組
eksctl delete nodegroup \
  --cluster my-eks-cluster \
  --name standard-workers-v129

Add-ons 回滾

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 回滾 add-on 到先前版本
aws eks update-addon \
  --cluster-name my-eks-cluster \
  --addon-name vpc-cni \
  --addon-version v1.15.0-eksbuild.2 \
  --resolve-conflicts OVERWRITE

# 驗證回滾狀態
aws eks describe-addon \
  --cluster-name my-eks-cluster \
  --addon-name vpc-cni

最佳實踐

升級規劃建議

  1. 環境分層升級:先在開發環境測試,再升級測試環境,最後升級生產環境
  2. 維護時段:選擇業務低峰期進行升級
  3. 監控告警:升級期間加強監控,設定適當的告警閾值
  4. 文件記錄:詳細記錄升級步驟和遇到的問題

自動化升級腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/bash
set -e

CLUSTER_NAME="my-eks-cluster"
TARGET_VERSION="1.29"
NODEGROUPS=$(aws eks list-nodegroups --cluster-name $CLUSTER_NAME --query 'nodegroups[]' --output text)

echo "開始升級 $CLUSTER_NAME 至 Kubernetes $TARGET_VERSION"

# 步驟 1:升級控制平面
echo "升級控制平面..."
aws eks update-cluster-version \
  --name $CLUSTER_NAME \
  --kubernetes-version $TARGET_VERSION

# 等待控制平面升級完成
while true; do
  STATUS=$(aws eks describe-cluster --name $CLUSTER_NAME --query 'cluster.status' --output text)
  if [ "$STATUS" = "ACTIVE" ]; then
    break
  fi
  echo "等待控制平面升級完成... 狀態: $STATUS"
  sleep 60
done

# 步驟 2:升級 add-ons
echo "升級 add-ons..."
for ADDON in vpc-cni coredns kube-proxy; do
  RECOMMENDED_VERSION=$(aws eks describe-addon-versions \
    --kubernetes-version $TARGET_VERSION \
    --addon-name $ADDON \
    --query 'addons[0].addonVersions[0].addonVersion' \
    --output text)

  aws eks update-addon \
    --cluster-name $CLUSTER_NAME \
    --addon-name $ADDON \
    --addon-version $RECOMMENDED_VERSION \
    --resolve-conflicts OVERWRITE
done

# 步驟 3:升級節點群組
echo "升級節點群組..."
for NODEGROUP in $NODEGROUPS; do
  echo "升級節點群組: $NODEGROUP"
  aws eks update-nodegroup-version \
    --cluster-name $CLUSTER_NAME \
    --nodegroup-name $NODEGROUP \
    --kubernetes-version $TARGET_VERSION
done

echo "升級完成!"

升級檢查清單

  • 確認目前叢集版本和目標版本
  • 備份所有 Kubernetes 資源
  • 檢查 API 棄用項目
  • 確認 add-ons 相容性
  • 通知相關團隊維護時段
  • 升級控制平面
  • 驗證控制平面健康
  • 升級 add-ons
  • 升級節點群組
  • 執行應用程式驗證測試
  • 監控叢集指標 24-48 小時
  • 更新文件記錄

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy