最近業務で EKS を運用しており、aws-load-balancer-controller(albc) の挙動で調べたことがあるのでメモしておくはなし
albc(ip-mode) と readinessGate まわりのはなし #
はじめに #
aws-load-balancer-controller は k8s cluster で ALB,NLB を使う際、勝手に LB を立ててくれて勝手に target group の lisner を弄ってくれるので便利
AWS Load Balancer Controller https://github.com/kubernetes-sigs/aws-load-balancer-controller
k8s & LB であるあるの問題が rolling update 時に 502 が出ることで、これは両者が非同期で処理を進めることに起因する
原因としては以下の記事が見やすく、
対応としてはこの辺も参考になる
[AWS][EKS] Zero downtime deployment(RollingUpdate) when using ALB Ingress Controller on Amazon EKS
ざっくりな原因は、
- pod の terminate 時に target group から削除されている保証がない
- pod の terminate 時に、代わりの pod 達が target group で healthy になっている保証がない
の2点で、
- 前者は pod の
preStop
とterminationGracePeriodSeconds
を伸ばす - 後者は container に readinessGate を登録する
- k8s側の Podのライフサイクル とalbc側の Pod readiness gate が参考になる
で対応する事がプラクティスとして言われている
pod の READY になる条件に target group 側でヘルスチェックが通ってる事を追加する事で rolling update 時の性急な terminate を抑制するのは分かるが、これはつまり notREADY な pod が target group に登録されているということ
では、ALB から見て pod がアクセスを捌けるという事はどうやって保証しているのか? (この場合、target group で HEALTY な事は pod がアクセスを捌けるという事を保証している訳ではないと考えた)
本記事では albc のコードを読み解くことで、上記の問題への対応を見ていく
詳細 #
以下のコードを読んでいく
pod を target group へ登録する3ステップ #
albc は、以下のステップにて新規 pod を登録する。ざっくりなコードはここで、その中の ResolvePodEndpoints が追加するエンドポイントを取得している
- target group の port と同じ port が設定されている service を取得する
- 上記 port と同一の port が設定されているエンドポイント(notReady含)を取得する
- notReady なエンドポイントの内、
readinessGate
が設定されておりcontainersReady
なエンドポイントを、 target group に登録する
それぞれの詳細は下に書くが、ここで重要なのは target group への登録対象として、 containersReady
である事を保証している事である
上の方に書いた
ALB から見て pod がアクセスを捌けるという事はどうやって保証しているのか?
への回答は、コンテナに readinessProbe を設定する事でコンテナがアクセスを捌ける事を保証し、チェックが通った(=containersReady)な pod を登録している、ということになる
以上でこの記事の結論が出てしまった訳だが、一応上記ステップについて細かく触れていく。ただコードのリンクを飛び飛びで貼っているので、素直に自分で上記のコードを読んだ方が楽かもしれない
ステップ詳細 #
1. target group の port と同じ port が設定されている service を取得する #
findServiceAndServicePort で k8s API( Service ) を叩き、 service 一覧を取得した後、 LookupServicePort で service を絞っている
2. 上記 port と同一の port が設定されているエンドポイント(notReady含)を取得する #
エンドポイント一覧をここで k8s API( Endpoints )を叩いて取得している。
当初、k8s上ではこの時点で新podは READY ではないため、 service のエンドポイントには新podは登録されていないと考えていた。API reference を読んでみると、 NotReadyAddresses
として取得できる事が分かった
3. notReady なエンドポイントの内、 readinessGate
が設定されており containersReady
なエンドポイントを、 target group に登録する #
notReady な pod 達はここで以下のチェックが入る
- ReadinessGate が設定されているかどうか
- ReadinessGate が設定されていない pod は素直に READY になってから登録すれば良い
- containersReady かどうか
- containersReady でない、つまり readinessProbe を通っていない pod はアクセスを捌ける保証がないので、登録しない
以上が登録部分の概要である。
まとめ #
readinessGate は k8s に pod が target group で healthy で登録されている事を伝えながらも、containersReady な pod のみを登録するように制御されていることがわかった
この辺は k8s cluster と AWS(ALB) がどう同期を取るかという所が工夫されていて、読んでいて面白かった。一方で僕の感じた疑問の回答がネットで見つけられなかったので、ここに残しておくという訳だ
以上