EKS をアップグレードする

Amazon EKS

EKS クラスターをアップグレードするときに、いつもやっていることを整理しました。EKS 1.29 から 1.30 への更新を例に紹介します。eksctl のバージョンは v0.187.0 で確認しました。

目次

  1. 重要事項を確認する
  2. アドオン名を確認する
  3. アドオンの更新バージョンを決定する
  4. アドオンを更新する
  5. コントロールプレーンを更新する
  6. ノードを更新する
  7. ノード更新時のダウンタイムを最小限にする

重要事項を確認する

既存のクラスターを新しい Kubernetes バージョンに更新する - Amazon EKS を確認して、特別な手順や後方互換性を失う変更など、必要に応じて対処します。

アドオン名を確認する

EKS のアップグレードの前に、インストールされている EKS アドオンを更新します。標準的なアドオンとして、以下のアドオンを利用されている方が多いのではないかと思います。

  • CoreDNS
  • kube-proxy
  • Amazon VPC CNI
  • Amazon EKS Pod Identity Agent
  • Amazon EBS CSI driver

アドオン名を確認します。

eksctl utils describe-addon-versions --kubernetes-version 1.30 | grep AddonName

出力されたアドオン名をメモしておきます。この後、eksctl でアドオンを指定するときに使います。

			"AddonName": "vpc-cni",
...
			"AddonName": "kube-proxy",
			"AddonName": "eks-pod-identity-agent",
...
			"AddonName": "coredns",
...
			"AddonName": "aws-ebs-csi-driver",
...

アドオンの更新バージョンを決定する

CoreDNS アドオンを例に更新方法を紹介します。

現在クラスタにインストールされているアドオンのバージョンを確認します。

aws eks describe-addon --cluster-name my-cluster --addon-name coredns --query 'addon.addonVersion'

更新前の 1.29 で利用できるアドオンの最新バージョンと、更新後の 1.30 で利用できる最新のバージョンを確認します。

eksctl utils describe-addon-versions --kubernetes-version 1.29 --name coredns | grep AddonVersion
			"AddonVersions": [
					"AddonVersion": "v1.11.1-eksbuild.9",
					"AddonVersion": "v1.11.1-eksbuild.8",
...
eksctl utils describe-addon-versions --kubernetes-version 1.30 --name coredns | grep AddonVersion
			"AddonVersions": [
					"AddonVersion": "v1.11.1-eksbuild.9",
					"AddonVersion": "v1.11.1-eksbuild.8",
...

今回の更新では、どちらのバージョンでも利用できる v1.11.1-eksbuild.9 にアップグレードすればよいことが分かります。eksctl の config ファイルを使っている場合は以下のように記述します。

addons:
...
  - name: coredns
    version: v1.11.1-eksbuild.9
...

他のアドオンも同様の手順を繰り返して、更新するアドオンのバージョンを決定します。

アドオン更新の注意事項を確認する

それぞれの EKS アドオンのドキュメントを確認し、特定のバージョンにおける注意点を確認します。

アドオンを更新する

eks-config.yaml に書かれているすべてのアドオンが順番に更新されます。更新は冗長構成を維持したまま行われるのでダウンタイムはありません。

eksctl update addon -f eks-config.yaml

コントロールプレーンを更新する

eks-config.yaml の metadata.version を目的のバージョンに変更します。

metadata:
  name: my-cluster
  version: "1.30"

コントロールプレーンの更新計画を表示します。

eksctl upgrade cluster -f eks-config.yaml

コントロールプレーンを更新します。こちらも更新に伴うダウンタイムはないので、サービス稼働中に更新しても大丈夫です。

eksctl upgrade cluster -f eks-config.yaml --approve

ノードを更新する

コントロールプレーンを更新した後、ノードグループをアップグレードすると新しいバージョンに更新されます。このコマンドは --approve オプションがなく、いきなり始まるので注意しましょう。

eksctl upgrade nodegroup -f eks-config.yaml

更新は通常、ローリングアップデートという方式で行われ、既存のノードを段階的に入れ替えます。

  1. 新しい Kubernetes バージョンのノードが追加される
  2. 新しいノードが正常に動作するまで待つ
  3. 古いノードで稼働していた Pod が排出される
  4. 新しいノードで Pod が起動する

上記が繰り返し行われ、すべてのノードが正常に処理された場合、クリーンアップが行われて古いノードが削除されます。

ノード更新時のダウンタイムを最小限にする

1つ前の手順の項番 3 「古いノードで稼働していた Pod が排出される」でダウンタイムが発生する可能性があります。古いノードで起動している Pod が終了してから新しいノードで Pod が起動するためです。

Kubernetes のマニフェストファイルを適切に設定することで、ダウンタイムを最低限にすることができます。

PodDisruptionBudget の設定

PodDisruptionBudget を使うと、指定された最少稼働 Pod の数が確保されるように設定できます。これにより、ノードの削除中でも指定された数の Pod が常に稼働していることが保証されます。

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  minAvailable: 1  # 常に最低でも 1 つのPodが利用可能であることを保証
  selector:
    matchLabels:
      app: my-app

Deployment strategy の設定

Deployment の strategy をRollingUpdateに設定し、更新中に Pod を停止できる数と、一度に追加できる Pod の数を指定します。以下の設定の場合、1 個ずつ Pod の入れ替えが行われます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1   # アップデート中に停止できるPodの最大数
      maxSurge: 1         # 一時的に追加できるPodの最大数
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: my-app-image:latest

Readiness Probe の設定

Readiness Probe を設定して、Pod がトラフィックを受け取る準備ができているかどうかを Kubernetes に知らせます。この設定により、準備ができていない Pod にはトラフィックが送られないようになります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 5
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: my-app-image:latest
        readinessProbe:  # 準備ができていない Pod にはトラフィックが送られないようになる
          httpGet:
            path: /health-check
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10

-技術ブログ
-