背景
GKEのオートスケールは、便利ですがいくつか不満もありました。例えば、ノードによってトラフィックの割合が均一化されないと言う問題です。オートスケーラによってPodが増えた場合、新しいPodへのトラフィックはすぐに均一化される訳ではなく、段階的に上昇していきます。これはk8sのデフォルトでの負荷分散の仕組みに起因するものだと思うのですが、新しく作成されたPodが直ちに有効活用されません。この影響で、急なスパイクには対応しにくいですし、安全に運用するためにはオートスケールの条件を緩める必要がありました。
以下のチャートは、Podごとに負荷の推移を観察したものです。新しく作成されたPodの負荷が、既存のPodと同じ水準の負荷に増えるまで、2~3時間かかってるのがわかると思います。
コンテナネイティブ負荷分散を使ってみる
去年の10月、GKEでコンテナネイティブ負荷分散が正式リリースされました。
https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing?hl=ja
既存の負荷分散だと、LB -> インスタンスグループ -> ノード -> Pod
と言う流れでトラフィックが送られます。
コンテナネイティブ負荷分散だと、LB -> Network Endpoint Group -> Pod
と言う流れになり、ノードを介さずに分散されます(Network Endpoint Groupに関しての詳細はドキュメントを見ていただけると)。
コンテナネイティブ負荷分散を既存のサービスで有効にする
留意点はいくつかありますが、コンテナネイティブ負荷分散を使用するために行うことは非常に簡単です。serviceリソースのmetadataに以下のannotationを追記するだけです。
apiVersion: v1
kind: Service
metadata:
name: service名
annotations:
cloud.google.com/neg: '{"ingress": true}' # これを追記する
反映されるまでに4~5分かかります。稼働中のサービスで行う場合、一時的にトラフィックが途切れるので注意してください。
目に見えてトラフィックが均一化された!
コンテナネイティブ負荷分散を有効にした結果、Podへのトラフィックが均一化され、Podごとの負荷も均一になりました。
以下のチャートは、コンテナネイティブ負荷分散を有効にする前と後で、同じ時間帯(4時〜12時)におけるPodごとの負荷を観察したものです。
Before
After
有効にする前と比較すると、明らかにPodごとの負荷が均一になっていますね。またそれだけではなく、オートスケーラーによって新しく作成されたPodの負荷も、直ちに既存のPodと同じ水準まで増加しています。
まとめ
と言うわけで、コンテナネイティブ負荷分散をGKEで使ってみたわけですが・・・これはGKEでオートスケールを利用する場合はほぼ必須と言ってもいいくらい効果があると感じました。実際にこれを利用することで、安定運用に必要なノードの台数を削減することが出来ました。
今回扱ったコンテナネイティブ負荷分散はGCPのネットワークエンドポイントを利用するものですが、k8s側で同様の機能が提供されればAWS等他のプロバイダでも使えるので、今後はその辺にも期待したいです。