はじめに

EKSのマイナーバージョンアップデートの際、クラスターコントロールプレーンのアップデート後、EKSノードのバージョンアップも必要になる。
EKSノードのバージョンアップの際、運用するシステムが停止しないか確認するため、EKSノードのアップデート時の挙動を調べてみたので、調査メモを示す

登場人物

  • AutoScalingグループ:ノードグループに紐付いている、EC2を水平スケーリングするためのリソース
  • EC2起動テンプレート:AutoScalingグループに紐づいている、EC2の起動設定が記載されたテンプレート。バージョニング機能を持つ
  • maxUnavailable(ノードグループの設定値):ローリングアップデート中にノードが同時に停止してよい最大値を示す。ノードがデフォルト値は1、つまりデフォルトだとノードは同時に1台しか停止できない。この値が大きいとローリングアップデートの時間は短縮できるが、アップデート中一時的にpod数が増えるためIPアドレス不足などの問題が懸念される。
  • PodDisruptionBudget(以降PDB):Drain中、Podが一度に停止して良い最大数(maxUnavailable)、またはPodが最低限起動していなければならない最小数(minAvailable)を設定することができる。ノードグループの設定値と被っているためややこしいが、こちらはPodに対する設定である。
  • node.kubernetes.io/exclude-from-external-load-balancers:ノードに付与するラベル設定値の1つ。これをtrueにするろロードバランサーの対象から除外される

全体の流れ

クラスターコントロールプレーンのアップデート後、AWSコンソール上で、対象のノードグループの画面を開き、今すぐ更新ボタンを押し、ローリングアップデートを選択すると以下のフローが開始される。

EKSノードのアップデートのフローは以下の4つのフェーズが自動で実行される

  1. セットアップフェーズ
  2. スケールアップフェーズ
  3. アップグレードフェーズ
  4. スケールダウンフェーズ

1つずつ詳しくみていく

各フェーズの詳細

セットアップフェーズ

EC2起動テンプレートを更新し、それをAutoScalingグループに紐付けるフェーズ

  1. --name=node-group-nameで指定されたノードグループに関連つけられているAutoScalingグループのEC2起動テンプレートの新しいバージョンを作成する。
  2. AutoScalingグループを更新し、作成した新しいバージョンの起動テンプレートに紐付けする

スケールアップフェーズ

新しいバージョンのノードを起動するため、スケールアップするフェーズ
新しいノードは、古いノードと同じAZで起動する
スケールアップ量は、関連ついているAZ数またはmaxUnavailable(ノードグループの設定値)の値で決定される

  1. AutoScalingグループの最大サイズと希望のサイズを増加させる
    ただし、増加させる量は以下のうち大きい方
    • AutoScalingグループがデプロイされているAZ数の2倍
      古いノード、新しいノードいずれも全部のAZで起動できるようにするため、最大サイズと希望のサイズはAZ数の2倍となる
    • maxUnavailable(ノードグループの設定値)の値(デフォルト値は1)
  2. 新しいノードが起動した後、新しいPodsのスケジュールを回避するために、ノードをスケジュール不可としてマークする。

アップグレードフェーズ

Podをdrainし、古いバージョンから新しいバージョンのノードに移行するフェーズ

  1. maxUnavailable(ノードグループの設定値)の値を最大数として、古いノードをランダムに選択する
  2. 選択されたNodeからPodをDrainし、新しいノードに持っていく。15分間ノードが移動できなかったらPodEvictionFailureエラーが発生するが、forceフラグを立てておけば強制的にPodを終了させて新しいノードに持っていくことができる。
    drain動作なので、forceをつけなければPDBが尊重される。例えば、あるpodのreplicas数の最大値1で、そのpodに関連つけられたminAvailable(PDBの設定値)が1であると、podを新しく起動することも、podを停止することもできず、PodEvictionFailureエラーが発生する。forceをつけるとPDBが無視されるのでエラーは発生しない
  3. 全てのPodが削除された後、60秒間待つ
  4. cordonされたノードが縮小するようにAutoscalingGroupにTerminationリクエストを送る。また、ノードを終了する前にロードバランサーからノードを除外するため。ノードにnode.kubernetes.io/exclude-from-external-load-balancers=trueのラベルを付ける
  5. 1~4の手順を全ての古いノードに繰り返す

スケールダウンフェーズ

  1. Auto Scaling グループの最大サイズと希望するサイズが 1 ずつ減り、更新が開始される前の値に戻す

実際にやってみた際のメモ

  • ノードグループのAutoScalingグループに紐付いている起動テンプレートが更新されるだけなので、ノードグループ自体の設定は変わらない
  • LoadBalancerのReplicas数を1で実行すると、アップグレードフェーズのドレインの際にダウンタイムが発生する
  • その他のPocもReplicas数が1だとDrainの際、各Podでダウンタイムが発生する
  • replicas数を2以上、PDBのminAvailableを1以上にすればダウンタイムは発生しない

参考

マネージド型ノードグループの更新
マネージド型ノードの更新動作
起動テンプレート
起動テンプレートのバージョン変更
KubernetesDoc(node.kubernetes.io/exclude-from-external-load-balancers)