はじめに
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つずつ詳しくみていく
各フェーズの詳細
セットアップフェーズ
EC2起動テンプレートを更新し、それをAutoScalingグループに紐付けるフェーズ
--name=node-group-nameで指定されたノードグループに関連つけられているAutoScalingグループのEC2起動テンプレートの新しいバージョンを作成する。- AutoScalingグループを更新し、作成した新しいバージョンの起動テンプレートに紐付けする
スケールアップフェーズ
新しいバージョンのノードを起動するため、スケールアップするフェーズ
新しいノードは、古いノードと同じAZで起動する
スケールアップ量は、関連ついているAZ数またはmaxUnavailable(ノードグループの設定値)の値で決定される
- AutoScalingグループの最大サイズと希望のサイズを増加させる
ただし、増加させる量は以下のうち大きい方- AutoScalingグループがデプロイされているAZ数の2倍
古いノード、新しいノードいずれも全部のAZで起動できるようにするため、最大サイズと希望のサイズはAZ数の2倍となる
maxUnavailable(ノードグループの設定値)の値(デフォルト値は1)
- AutoScalingグループがデプロイされているAZ数の2倍
- 新しいノードが起動した後、新しいPodsのスケジュールを回避するために、ノードをスケジュール不可としてマークする。
アップグレードフェーズ
Podをdrainし、古いバージョンから新しいバージョンのノードに移行するフェーズ
maxUnavailable(ノードグループの設定値)の値を最大数として、古いノードをランダムに選択する- 選択されたNodeからPodをDrainし、新しいノードに持っていく。15分間ノードが移動できなかったら
PodEvictionFailureエラーが発生するが、forceフラグを立てておけば強制的にPodを終了させて新しいノードに持っていくことができる。drain動作なので、forceをつけなければPDBが尊重される。例えば、あるpodのreplicas数の最大値1で、そのpodに関連つけられたminAvailable(PDBの設定値)が1であると、podを新しく起動することも、podを停止することもできず、PodEvictionFailureエラーが発生する。forceをつけるとPDBが無視されるのでエラーは発生しない - 全てのPodが削除された後、60秒間待つ
- cordonされたノードが縮小するようにAutoscalingGroupにTerminationリクエストを送る。また、ノードを終了する前にロードバランサーからノードを除外するため。ノードに
node.kubernetes.io/exclude-from-external-load-balancers=trueのラベルを付ける - 1~4の手順を全ての古いノードに繰り返す
スケールダウンフェーズ
- 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)