はじめに
執筆開始日は2021年2月8日です。
環境はAmazon EKS(v1.18),Istio 1.7の環境で確認した内容です。
採用技術
この記事では下記技術の動作概要や取り組んだポイントについて記載します。
- Horizontal Pod Autoscaler
- Cluster-Autoscaler
- AWS Node Termination Handler
Horizontal Pod Autoscaler (HPA) は何をしてくれる?
Podの負荷(CPU使用率・Memory使用率)によって水平スケーリングを自動で行ってくれます。
HPA単体では動作せず、Metrics-Serverによって行われるリソース監視の結果と連携し動作します。
負荷がしきい値を上回ればスケールアウトし、下回った状態が続けばスケールインしてくれるいい感じのやつです。
HPAのKubernetes APIとしてautoscaling/v2beta2
がKubernetes 1.18で導入され、新しく追加された機能もあります。
例えば「スケールインを行わない」といった設定を加えることができます。
spec:
behavior:
scaleDown:
selectPolicy: Disabled
Kubernetes - Horizontal Pod Autoscalerより
"トラフィックの急増を繰り返すことが予期されていて、サービス提供時間内はスケールインを行わない”といった
ポリシーでの運用であればこのようなスケールイン自体を無効にすることも有効と思えます。
Cluster-Autoscaler(CA)は何をしてくれる?
Nodeの水平スケールまたは垂直スケールを自動で行ってくれます。
例えば、上述のHPAでPodのスケールアウトが行われますが、無限にスケールアウトできるわけではありませんよね。
Nodeのリソースを使い切った状態から、さらにもう一つのPodを起動しようとしたとき
Pod分のリソースが確保されるまでPodのステータスはPendingとなり起動できません。
Cluster-Autoscaler
では、そのPendingを検知することでAWSのAutoscaling API
を叩いて新規にNodeを立ち上げてくれます。
一つ注意しておきたいのは、AutoScaling グループで指定した最大キャパシティを超えるスケールアウトはできない
点です。
予め幅を持たせた最大値を設定することで、トラフィックが集中したときに対応可能になると思います。
また、最小キャパシティを下回るNode数へのスケールインもできません。
AWS NodeTerminationHandler(NTH)は何をしてくれる?
EKSクラスタのスケールインの際、AutoScalingグループがNodeを終了させる動作が発生します。
終了するNode上で起動されたPodも当然のことながら巻き添えを食らい、別のNodeで起動しなければならなくなり
ダウンタイムが発生することに繋がります。
NodeTerminationHandler(NTH)
を導入することによりPodのダウンタイムを大幅に減少させることが可能となります。
もう少し丁寧に言うと、Nodeが終了状態(Teminated)になる前に、別のNodeへPodを移動させてくれるのがNTHの主な動作です。
k8s-Node-Drainerも候補に挙がり、どちらを採用するか実際に動かしてみましたが、大きな違いは無いように見えました。
Amazon EKSに導入するのであればスポットインスタンスとオンデマンドインスタンス両方に対応してくれるNTHのほうが良いかなとも思えます。
NTH導入時には次の設定をAWSリソースに追加する必要があります。
- Autoscalingグループのライフサイクルフック
- Amazon EventBridgeのトリガーとターゲット
- Amazon Simple Queue Service
処理フローとしては、
1. NodeのTeminatingをEventBridgeで検知。
2. EventBridgeはSQSキューへ連携。
3. NTHがSQSキューを確認していて、インスタンスIDなどの情報を受け取る。
4. NTHがSQSキューのメッセージを削除。
もっと突っ込んだ話をすると、NTHが処理3で受け取った情報を元に、
終了するNodeに対してdrain
とcordon
を行います。
そうすることで、終了するNodeへの新規スケジューリングをできないようマーク(cordon)
し、
別NodeへのPodの退去(drain)
が行われます。
このように、NTHは各リソースと連携しながらダウンタイムを減少させてくれます。
少しだけ気をつけたいポイント
PodDisruptionBudget
Nodeのスケールインが行われる時に、サービス提供Podが全て落ちてしまう場合があります。
この事象を回避するにはkind: PodDisraptionBudget
で
minAvailableや maxUnavailableをサービス提供Podへ適用し、
EKSクラスタとして「最低N個のPodは生かしておかなければならない」といった制約を持たせ、 全断を防いであげるような設定
も必要になります。
コネクションのDraining
istioのingressgatewayの振る舞いをログから見ると、Pod終了前に5秒間だけ待機してくれているようなのですが
コネクションを切断せずに落ちてしまい、クライアントから見るとタイムアウトを引き起こすことがありました。
ingressgatewayのDeploymentではgracefulTerminationPeriodが30秒で設定されているのですが、
どうにも効いているようには見えません。istioの開発コミュニティを覗くと似たようなissueがボロボロと出てきたので既知のバグかもしれません。
おわりに
スケーリング機能をEKSクラスタへ追加することはAWSでELBやターゲットグループを使用するのと同じくらい重要なことであると思っています。
それほど重要な部分について触れることができたことや、EKSの周辺リソースにも触れることができ、濃厚な時間を過ごせました。
正直に楽しかったと言えます。
また何か触って楽しくなっちゃった時に、このような記事を書きたいと思います。
誰かの参考になりましたら幸いです。