NTT DATA TECH
🦈

サービスメッシュ環境におけるコンテナのパケットキャプチャのいろは

に公開

TL; DR;

  • コンテナ/サービスメッシュ環境では通常のサーバーよりも通信経路が複雑なため知識なしでパケットキャプチャ結果を読み取るのが困難です
  • キャプチャ結果の読み取り方を図も交えて解説しました

背景

自身が参画したプロジェクトにおいて、Anthos Service Mesh(istio)が有効化されたGoogle Kubernetes Engine上で動作するアプリケーションの処理遅延を調査した際、クライアント側(GKE Pod)のリクエストログでは時間がかかっているように見えるのに、サーバー側のアクセスログでは時間がかかっておらず、なんらかのNW遅延があるのではないかと調査を行いました。

その際にパケットキャプチャを利用した結果、NWそのものよりもTLSハンドシェイク部分に時間がかかっていることを見つけ、解決に貢献してくれたのですが、サービスメッシュなコンテナ環境におけるパケットキャプチャの見方に苦労したのでそこで得た知見を共有していきます。

パケットキャプチャによって詳細に絞り込める

コンテナ/サービスメッシュ環境におけるパケットキャプチャの難しさ

ネットワーク系の問題を調査するに当たってはパケットキャプチャは大きな武器となり得ますが、非コンテナ環境と比べるとコンテナ環境においては下記のような難しさがあります。

  • コンテナは基本的に短命でありそもそもパケットキャプチャを取るのが難しい
  • 内部的にはOSの機能で隔離されたプロセスでありいくつかNW的に変換が行われるため、コンテナ内で取得したパケットがそのままマシンから出たパケットとは限らない

これに加え、istioなどサイドカー型のサービスメッシュが導入されている場合には通信の流れが特殊になります。

これを表したのが下の図で、アプリケーションからすると直接相手と通信しているように見えても、実際のところはサイドカーコンテナ(istioの場合istio-proxyという名前のenvoy)が中継をする形で通信をしています。

サービスメッシュの入ったコンテナでの通信経路

さらにややこしいことに、この中継はistioがOSの仕組み(Linuxの場合パケットの編集・フィルタを行うiptables)を利用して動的に実現しており、実際にキャプチャして見えるパケットはこれらの変換が適用された結果、知識なしでは解釈するのが難しくなっています。

この記事ではパケットキャプチャを取得する方法に加え、それらをどう解釈するのかも解説します。

istioによるiptablesの利用について

istioがどのようにiptablesを利用しているかについては、以下のようにいくつかわかりやすい記事があるため、興味のある方はそれをみてみると良いでしょう。
cf. https://zenn.dev/tayusa/articles/aa54bbff3d0d2d
cf. https://engineering.mercari.com/blog/entry/20211021-istio1-10-inbound-fowarding/

サイドカー以外のサービスメッシュについて

cilliumやistio ambient meshなどのサイドカー型以外のサービスメッシュでは、この記事で前提とする仕組みが使われていないことが予想されるため、この記事での内容とは異なるかもしれません。
例えばcilliumではeBPFの仕組みを利用することでiptablesレスなパケット編集を実現していますが、この違いによってキャプチャした結果見えてくるものが異なる可能性があります。

パケットキャプチャの取得

少し小難しい説明を挟んでしまいましたが、百聞は一件にしかずということで、実際にサービスメッシュ環境においてパケットキャプチャをとってみましょう。

なお、環境としては

  • Google Kubernetes Engine(Standardモード)
  • Anthos Service Meshとしてistioが導入済み(L7プロキシ)

となっていますが、サイドカーとしてistioが導入されている環境なら同様のことが言えるはずです。

準備(デモ用Podの作成)

パケットキャプチャを取るにあたり、アプリケーションコンテナがないと話にならないので適当なコンテナを立ててみます。

$ kubectl run --image=nginx:latest maca-problematic-pod
pod/maca-problematic-pod created
作成されたPodのマニフェスト(一部省略)
apiVersion: v1
kind: Pod
metadata:
  annotations:
    istio.io/rev: asm-1234-7
  name: maca-problematic-pod
spec:
  containers:
  # サイドカーコンテナ
  - image: gke.gcr.io/asm/proxyv2:1.23.4-asm.7
    name: istio-proxy

  # アプリケーションコンテナ
  - image: nginx:latest
    name: maca-problematic-pod
status:
  # PodのIPアドレス
  podIP: 172.19.7.156

簡単ですね。ここで覚えておくべきことは、サイドカーコンテナが存在していること、PodのIPアドレスが172.19.7.156であるということのみです。

debugコンテナの作成(Optional)

Podも作成できたのでいよいよパケットキャプチャといきたいところですが、このままではパケットキャプチャを行うことはできません。

というのも、パケットキャプチャを行うツール(今回はtcpdumpを使用)は通常アプリケーションコンテナには入っていないためです。

ツールを含んだイメージでデプロイし直したり、Podマニフェストを修正してツールを含むコンテナを追加する、という方法でもキャプチャを行うことは可能ですが、これらにはPodの再起動を伴います。

時には環境制約でPodを再起動させたくない...!という場合もあるかと思うので、この記事ではKubernetesのephemeral containerを使ってツールを含むコンテナを立ち上げます。
この機能はPodの再起動を伴わずに一時的にPodに対してコンテナを追加するというもので、デバッグ用途を主眼とする機能のため、まさに今回の用途にぴったりです。

$ kubectl debug maca-problematic-pod -it --image=nicolaka/netshoot -- /bin/bash
Defaulting debug container name to debugger-xk9qq.
If you don't see a command prompt, try pressing enter.
maca-problematic-pod:~#

kubectl debugコマンドで簡単に追加することができました。debugger-xk9qqという名前のコンテナが生成されたようです。なお今回追加したコンテナイメージはnetshootというものであり、NW系のデバッグツールが豊富に含まれています。

パケットキャプチャ取得

それでは実際にパケットキャプチャを取得してみましょう。

ここで注意することは、パケットを取得する対象のネットワークインタフェースの指定としてanyを用いることです。
コンテナ環境でのパケットキャプチャの難しさを説明した際に、「いくつかOSレイヤでパケット変換が行われる」と書きましたが、これによって特定のインタフェースだけに着目すると全ての通信が取得できない可能性があり、それを防ぐために指定しています。

滅多に再現しない事象の調査を行なっており、めでたくキャプチャしているときに再現したとしても、情報が断片的にしか取れていないと非常に悲しいですよね。それを防ぐためにもインタフェースはanyにすることをおすすめします。

maca-problematic-pod:~# tcpdump -i any -w `TZ='Asia/Tokyo' date +%Y_%m%d_%H%M%S`.pcap -C 180
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes

その他にもタイムゾーンの指定だったりファイル名の指定を行なっていますが、上のようなコマンドで取得が可能です。

また、このタイミングで解析対象の通信を実際に行なってみましょう。
通信の流れのみに着目するため、シンプルにgoogleに対してHTTPリクエストを送ってみます。

$ kubectl exec -it -n payment maca-problematic-pod -c maca-problematic-pod -- /bin/bash
root@maca-problematic-pod:/# curl https://google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>

解析

それでは実際にキャプチャ結果を見てみましょう。
キャプチャファイルはnetshootコンテナに存在するので、まずは手元に持ってきます。

$ kubectl cp -c debugger-xk9qq maca-problematic-pod:2025_0424_023957.pcap ./2025_0424_023957.pcap

このファイルを可視化ツールで見てみます。ツールはなんでもいいですが、この記事ではwiresharkを利用します。

キャプチャしていた時間によってはブワッと大量に出てくるかと思いますが、通信に用いるポート番号(443)・通信相手のIPアドレス(今回は142.251.42.142)で一次絞り込みをした上で少しずつフィルタを修正していきます。

最終的に以下のようなフィルタをかけたのが下の画像です。

(ip.addr == 142.251.42.142 or ip.addr == 127.0.0.1) and (tcp.port == 49504 or tcp.port == 49514)

パケットキャプチャ

wiresharkのおすすめ設定

デフォルトの設定でもいいですが、wiresharkを使う時は以下のような情報を列に追加すると良いです。

  • 絶対時間
  • 前に表示されているパケットとの時間差分(delta time displayed)
  • 最初のパケットからの経過時間(Relative time)
  • TCPのストリーム番号
  • TCPポート番号
  • TCPのSeqとAck

参考までに私の設定は以下の画像のようにしています。

wiresharkの設定

TLS通信となっているのでHTTP通信の内容は見えませんが、TCPハンドシェイク時のパケットをみてみると、いくつか法則があることがわかるかと思います。

  • TCPストリームが3つある(番号は2,3,4)
  • outbound(アプリコンテナ -> 通信相手)な通信はストリーム2,4を通る
  • inbound(通信相手 -> アプリコンテナ)な通信はストリーム3,4を通る
  • ストリーム2はローカルIP(127.0.0.1)と通信している

この事実と上の通信経路とを見比べてみると、どうやらローカルIPと通信しているストリーム2はアプリケーションコンテナとサイドカーの間の通信(往路)であることが推測できます。
すると必然的にストリーム4はサイドカーコンテナと通信相手であり、こちらは往復ともに同じストリームのようです。
残されたストリーム3はアプリケーションコンテナ・サイドカーコンテナ通信(復路)であると言えそうです。

これを図解したのが下です。

通信経路とキャプチャ内容の対応

ここで重要なのは、wiresharkでのTCPストリーム番号が違うからといってTCPコネクション自体が別だとは限らないということで、上の例ではストリーム2と3は同じTCPコネクションであるという点です(下の画像を参照)

生情報でみると同じTCPコネクション

まさにこの点が、istioがiptables書き換えによってパケット編集をした結果であり、

  • 往路:アプリケーションコンテナからの通信をサイドカーに向けるための編集がなされる
    • destination ipやポートがサイドカーのものになる
  • 復路:アプリケーション側に直接通信相手と通信しているように見せるための編集がされる
    • source ipやポートは通信相手のものになる

ということになります。

これを念頭に置くと、初めは訳のわからなかったキャプチャ結果もある程度体系だって見えるようになり、あとはこれをもとに、遅延ならどの経路で遅れているのか・エラーならどの経路でパケットロスや再送が発生しているのかを見ていくことでスムーズな調査が可能になるでしょう。

パケットキャプチャ再掲

とはいえ...

ここまでコンテナ/サービスメッシュ環境におけるパケットキャプチャの方法・解析の仕方を説明してきましたが、個人的にはネットワーク系の問題調査においてパケットキャプチャをファーストステップとして用いるということはあまり良くない(というよりもコスパが悪い)ことだと考えています。

パケットキャプチャを行う前に、

  • アクセスログ・リクエストログなどのアプリケーションログやメトリクス
  • netstatコマンドや各種メトリクス

などで、「パケットの遅延やドロップが起きていそう」「ハンドシェイク部分に時間がかかっているのではないか」などの確度を高めてから行うようにしましょう。

(さもないとパケットの海を泳いでいるだけで無駄な時間が過ぎていきます)

まとめ

この記事では、コンテナ環境/サービスメッシュ環境に特有なパケットキャプチャの取得方法や結果の調査方法について説明しました。
前のセクションにも書いたようにパケットキャプチャは問題調査に毎回出てくるわけではないですが、通信のすべてが載っている強力なツールです。

この記事を参考にぜひ使いこなして調査の役に立ててくださると幸いです。

NTT DATA TECH
NTT DATA TECH

Discussion