KARTE Message 配信基盤で起きたIP枯渇とその対処

はじめに

こんにちはプレイドのKARTE Messageチームでエンジニアをしている土谷です。

今回はKARTE Messageで起きたGKEのPodのIPアドレスの枯渇問題に関して、何が起きてどのように対応したのかを紹介します。

KARTE Messageについて

KARTE Messageはマルチチャネル(Mail/アプリPush/LINE[^1] )での大量配信を行えるMAツールです。

最大2000rpsを超える速度で配信しており、大量かつ高速な配信ができるMAツールとなっています。

詳しくは過去のブログで紹介しているので、そちらをご覧ください。

GKEのIPに関して

本題に入る前に、GKE VPCネイティブクラスタのIPの割り振りについて整理しておきます。

Pod の IP アドレス範囲(Alias IP)

クラスタ内でPodに割り当てられる専用のネットワーク帯域です。

VPC セカンダリ IP 範囲

GKEではVPCサブネットの「セカンダリIP範囲」をPod用の帯域として利用します。

ノードあたりの最大 Pod 数

1つのNodeに割り振られるIPアドレスの数は、実際のPod数ではなく「Nodeあたりの最大Pod数」の設定に基づき、あらかじめNodeごとにCIDRブロックとして確保されます。Podの数とIPの数に関してはドキュメントをご覧ください。

発生した問題

今回のブログのタイトルの通りで、配信基盤のNode PoolでIPが不足しPodが起動できないエラーが発生しました。エラーが発生したのが配信処理のJobがまとめられているNode Poolだったため、配信の遅延の可能性があり、即座に対応を開始しました。

対応1: IPアドレスの追加

まずは単純にIPが足りないエラーなので、IPアドレスを増やすことを試みました。VPCサブネットに新しいIP範囲を追加し、クラスタおよびNode Poolで利用するように設定しました。

# 1. VPCサブネットにセカンダリIP範囲を追加
resource "google_compute_subnetwork" "example-vpc" {
  # 中略
  secondary_ip_range {
+   ip_cidr_range = "xxx.xxx.xxx.xxx/yy"
+   range_name    = "additional-pod-range-1"
  }
}

# 2. クラスタに新しい範囲を認識させる
resource "google_container_cluster" "example-cluster" {
  # 中略
  ip_allocation_policy {
    # 中略
    additional_pod_ranges_config {
+     pod_range_names = ["additional-pod-range-1"]
    }
  }
}

# 3. Node Pool で利用する範囲を切り替える
resource "google_container_node_pool" "example-node-pool-v2" {
  # 中略
  network_config {
+   create_pod_range = false
+   pod_range        = "additional-pod-range-1"
  }
}

結果

これにより数千個単位のIPを追加したにも関わらず、一瞬で使い切る結果となりました。実際に立っているPod数を確認すると数百程度だったので、実際のPod数以上にIPを消費していることがわかりました。

PodのIPアドレスの割り振りは、実際のPodの数ではなくNodeあたりのPod数の設定によるのでNodeにPodが何台立っているかを確認したところ、1Nodeあたり1Podしか立っていませんでした。しかし、Nodeあたりの最大Pod数は110台に設定されていたので、1Podに対して256のIPアドレスが消費される状態となっていました。

対応2: NodeあたりのPod数の調整

次に考えられる対応は以下のどちらかでした。

  1. インフラリソースの調整をしてNodeに対して十分なPodが立つ状態を作る
  2. Nodeあたりの最大Pod数を調整し、IPアドレスの消費量を抑える

Podの処理の性質上リソースの消費量が大きく、マシンスペックを上げても1NodeにPodが110台載ることは現実的でなかったので、先にIPアドレスの無駄遣いを解消することを実施しました。

内容

マシンスペックを大きくしても1Nodeには20台もPodは立たない想定で、1NodeあたりのPod数は32としました

resource "google_container_node_pool" "example-node-pool-v3" {
  # 中略
~  max_pods_per_node = 110 -> 32
}

結果

これによりIPアドレスの無駄遣いが解消されて、IP枯渇が解消しました!

が、これによりIPアドレスのボトルネックが外れ、「1Node 1Pod」の状態のままPodがスケールした結果Node 数が比例して増え続け、インフラコストが 1.2 〜 1.5 倍程度まで増えてしまいました。

対応3: Nodeのスペック調整

1Pod増えると1Node増える構造がコスト増加の原因のため、Nodeのマシンスペックを調整しNodeに載るPodの数を調整しました。

以下を考慮しマシンスペックを決定しました。

  • コスト効率:マシンスペックの変更によるコストの変化
  • 耐障害性:マシンスペックを大きくした場合、Nodeで問題が発生した場合に影響を受けるPod数が増える
  • スケール特性:Affinity 設定でPodを分散配置しているため、Nodeのスケールインが遅くなる可能性がある

最終的に、CPU/メモリのバランスが良いStandardタイプのコア数を増やしたインスタンスを選択しました。

結果

1Nodeあたりに複数のPodが安定して収容されるようになり、コストは元の水準まで戻りました。以前よりもスケーラビリティに余裕が生まれたため、実質的には運用効率が向上する結果となりました。

まとめ

振り返ってみると基本的な内容での対応が多かったですが、社内でもIP枯渇の対応事例はなく、個人的にもKubernetesの運用経験として非常に良い経験となりました。

KARTE Messageはローンチからサービスも大きくなり過去問題なかったインフラ設定でも、運用しているうちに1Nodeに1Podという状態になってしまっていました。こういったビジネスのスケールと共にインフラ基盤が変化していく過程を経験できたのは非常に良い経験でした!

株式会社プレイドでは一緒に働く仲間を募集しています!

興味がある方はぜひ採用ページをご覧ください。お待ちしております!