Kubernetesの通信最適化を「魔法のツール」に頼るな——泥臭いボトルネック解消の全技術

Kubernetesの通信最適化を「魔法のツール」に頼るな——泥臭いボトルネック解消の全技術

「KubernetesのPod間通信が遅い? じゃあIstioを入れよう」

もし君が会議でそう発言したなら、少し落ち着いて深呼吸することをお勧めする。私は過去、マイクロサービスアーキテクチャの設計で「Service Meshを入れれば全て解決する」という幻想を追いかけ、見事にクラスターを自壊させたことがある。

Envoyサイドカーが全Podに居座ることでCPU使用率は跳ね上がり、mTLSの暗号化・復号化コストでレイテンシは悪化。結局、私たちが手にしたのは「管理不能な複雑性」と「予測不能なパフォーマンス低下」という名の負債だった。

この記事では、魔法のツールに頼る前に、Kubernetesというプラットフォームを限界まで使い倒すための「泥臭い」最適化手法を共有する。


1. 「Service Mesh」か「ネイティブ」か:運用の現実

Service Meshは万能薬ではない。導入を検討する際は、以下のトレードオフを冷徹に計算する必要がある。

比較項目Service Mesh (Istio等)Kubernetes Native
可観測性自動で詳細なトレース取得自前での実装・設定が必要
セキュリティmTLSを透過的に適用NetworkPolicyによる制御
リソース消費サイドカーによるメモリ/CPU占有ほぼゼロ
運用コスト極めて高い(設定の複雑化)低い(標準機能の活用)

結論: 「アプリケーションコードを書き換えずにリトライやサーキットブレーカーを実装したい」という明確な動機がない限り、まずはネイティブな仕組みでどこまでいけるかを検証すべきだ。


2. DNS解決のボトルネックを叩く

通信の遅延は、多くの場合「名前解決」の段階で起きている。特にCoreDNSへのクエリ集中はクラスター全体のボトルネックだ。ここで効いてくるのが `NodeLocal DNSCache` である。

#### なぜ `169.254.20.10` なのか?
これはリンクローカルアドレスであり、各ノードのネットワーク名前空間内で完結する。外部のDNSサーバーまでパケットを飛ばさず、ノード内でキャッシュを完結させることで、往復のレイテンシを極限まで削る。

# NodeLocal DNSCacheの構成例
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-local-dns
spec:
  template:
    spec:
      containers:
      - name: node-cache
        image: registry.k8s.io/node-cache:1.21.1
        args: ["-localip", "169.254.20.10", "-conf", "/etc/Corefile"]
        # ノードのネットワーク名前空間を共有し、高速な解決を実現
        securityContext:
          privileged: true


3. Prometheusの「罠」:Cardinality爆発との戦い

「監視を強化すれば問題が特定できる」というのも大きな勘違いだ。私は以前、全PodのネットワークI/Oを1秒間隔で取得しようとして、PrometheusのTSDBをパンクさせ、クラスターをEvictさせた苦い経験がある。

#### Cardinality(時系列データ数)を制御せよ
ラベルに「リクエストID」や「ユーザーID」のようなユニークな値を含めてはならない。これらは時系列データの爆発を引き起こす。

対策: Recording Rulesでクエリを事前計算する
重いクエリを毎回走らせるのではなく、事前に計算結果をメトリクスとして保存しておくのが鉄則だ。

groups:
  - name: network_metrics
    rules:
    - record: job:network_io_bytes:rate5m
      expr: sum(rate(container_network_receive_bytes_total[5m])) by (job)

もしCardinalityを確認したいなら、以下のPrometheusクエリを叩いてみてほしい。君の環境で「何が」データを食いつぶしているか一目瞭然だ。

# ラベルの組み合わせ数が多いメトリクスを特定する
topk(10, count by (__name__) ({__name__=~".+"}))


4. 明日から始める「通信の最適化」ステップ

いきなり複雑なアーキテクチャをいじる必要はない。まずは以下の順序でボトルネックを排除せよ。

1. Keep-Aliveの確認: アプリケーションコードでコネクションプールを適切に設定しているか? TCPハンドシェイクの頻度を減らすのが最優先だ。
2. NodeLocal DNSCacheの導入: まずはDNSクエリのレイテンシを計測し、高ければ即導入する。
3. REDメトリクスの監視:
- Rate: リクエスト数
- Error: エラー率
- Duration: 応答時間
まずはこれら3つだけでいい。ここから外れた異常値が出た時だけ、詳細なトレースに潜ればいい。

最後に

Kubernetesにおける最適化の本質は、魔法のツールを探すことではなく、「何が起きているか」を論理的に追跡できる状態を作ることだ。

ネットワークのオーバーヘッド、DNSのタイムアウト、PrometheusのCardinality。これらの一つひとつと泥臭く向き合うこと。それが、真のエンジニアリングというものだ。君のクラスターのボトルネックは、設定ファイルではなく、君自身の「理解不足」にあるかもしれない。まずはそこから始めよう。