チャオ。SREチームの栗山(@sheepland)です。 好きな漫画は「僕の心のヤバイやつ」です。毎回心がバキバキになりながら読んでいます。
今回はEKSでCluster Autoscalerを使った際にNodeがスケールインするタイミングで502、504エラーがでるのを解消した話です。
TL;DR
- EKSでCluster Autoscalerを使う場合、Ingressは
target-type: ip
にする target-type: ip
にした場合、PodのpreStop内で長めにsleepを入れる
前提
- ALBの管理にはAWS ALB Ingress Controllerを使用 (※近いうちにAWS Load Balancer Controllerにバージョンアップ予定)
- トラフィックモードはデフォルトのInstance modeを使用
- Podの終了時に新規リクエストが来なくなるのを待つためにのpreStopの中でsleepを10秒入れている
事象
Cluster Autoscalerを導入するにあたりNodeのスケールアウト/スケールイン時にリクエストエラーが発生しないかを検証していました。検証方法は簡単でLocustという負荷試験ツールを使ってひたすらリクエストを投げるというものです。リクエストエラーが発生すればLocustの画面のFailuresタブから分かります。
スケールアウト時には問題なかったのですが、Nodeがスケールインするタイミングで数リクエストが502や504エラーになるという問題が発生しました。
最初はスケールインするNodeにのっているPodの退避がNodeのスケールインに間に合わずエラーが発生しているのかと思っていました。
しかし調査をするとNodeがスケールインする前にPodは退避されているというのと、スケールインするNodeにアプリケーションPodがのっていない場合でもリクエストエラーが発生していたためPodのターミネート処理に問題があるのではなく、ALB周りになにか問題があると推測。
ここからは想像ですがNodeが終了するときに他のNodeのiptablesを更新するときに一部のリクエストがエラーになっているような印象をうけました。
Ingressのtarget-typeを変えてみる
Ingressのトラフィックモード(target-type)がデフォルトのInstance mode から IP mode に変更してみました。 そうするとNodeのスケールイン時にリクエストエラーが発生しなくなりました 🎉
しかし別の問題が…
今度はPodが終了するときにリクエストエラーが発生するようになりました。Instance modeのときは発生しなかった事象です。 しかもNodeのスケールイン時のリクエストエラーよりもエラー数が多くなってます。
preStopのsleepを伸ばしてみる
色々ネットで調べてみるとIP modeにするとALBのターゲットグループからPodを登録解除するのに時間がかかるということでした。
(参考記事: スマホゲームの API サーバにおける EKS の運用事例 | エンジニアブログ | GREE Engineering)
そのため10秒sleepするだけではターゲットグループからの解除が間に合わず、Podが終了しているにも関わらずリクエストがPodにきていたと推測されます。
実際にpreStopの中でsleepを10秒から30秒に伸ばしたところリクエストエラーが発生しなくなりました 🎉
まとめ
Cluster AutoscalerのNodeのスケールイン時のリクエストエラーの解消方法について紹介しました。
スケールイン時のリクエストエラーは80RPSくらいの負荷の中で1回リクエストエラーが発生するくらいだったので、リクエストがそこまで多くないサービスであれば気づかなかったり問題にならなかったりするかもしれません。しかし大きなサービスになるとこういった問題が顕在化してきます。
やはり事前検証をしっかり行うのは大切ですね。調査当初は何が原因か分からずかなり焦りましたが無事解決できてよかったです。