ACK KubeSkoop (旧 ACK Net Exporter) は、Alibaba Cloud Container Service for Kubernetes が提供するオープンソースのネットワークモニタリングおよび診断スイートです。これにより、クラスター内の複雑なネットワーク問題をモニタリングし、迅速にトラブルシューティングできます。この記事では、マネージド ACK クラスターで KubeSkoop を使用して実際の問題を解決するためのベストプラクティスを説明します。
背景情報
KubeSkoop は、詳細なネットワークモニタリング、ネットワーク接続診断、パケットキャプチャ、レイテンシープロービングなど、eBPF ベースの一連の機能を提供します。Prometheus メトリクスと異常レコードを公開します。KubeSkoop は、各ノードで DaemonSet Pod として実行されます。eBPF テクノロジーを使用してノードから情報を収集し、特定の Pod 向けに集約します。これにより、高レベルのネットワーク情報のための標準化された可観測性インターフェースが提供されます。次の図は、KubeSkoop のコアアーキテクチャを示しています。
ACK KubeSkoop のインストールと設定
ACK KubeSkoop のインストール
ACKコンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のナビゲーションウィンドウで、 を選択します。
-
アドオン管理 ページで ACK KubeSkoop を検索し、該当コンポーネントを見つけて、インストール をクリックします。
-
インストール [ACK KubeSkoop] パネルで、確認 をクリックします。
KubeSkoop の設定
-
KubeSkoop コンポーネントを設定するには、次のコマンドを実行して ConfigMap を編集します。
kubectl edit cm kubeskoop-config -n ack-kubeskoop -
または、ACK コンソールでコンポーネントを設定します。
ACK コンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、 を選択します。
-
ConfigMap ページで、名前空間 を ack-kubeskoop に設定し、kubeskoop-config を検索します。次に、kubeskoop-config の右側にある 操作 列で 編集 をクリックします。
-
編集 パネルでパラメーターを設定し、OK をクリックします。次の表に、KubeSkoop でサポートされている設定オプションを示します。
パラメーター
説明
デフォルト
debugmode
デバッグモードを有効にするかどうかを指定します。有効な値:
-
false:デバッグモードは無効です。
-
true:デバッグモードは有効です。有効にすると、このオプションは DEBUG レベルのログ、デバッグ用インターフェイス、および Go pprof と gops 診断ツールを提供します。
falseport
HTTP エンドポイントを提供するメトリクスサービスのポートです。
9102enableController
コントローラーコンポーネントを有効にするかどうかを指定します。コントローラーは Kubernetes API と連携し、モニタリングと管理タスクを実行します。
truecontrollerAddr
KubeSkoop コントローラーコンポーネントのアドレスです。
dns:kubeskoop-controller:10263metrics.probes
収集するモニタリングメトリクスのタイプのリストです。各プローブはメトリクスカテゴリに対応します。
metrics: probes: - name: conntrack - name: qdisc - name: netdev - name: io - name: sock - name: tcpsummary - name: tcp - name: tcpext - name: udp - name: rdma詳細については、「Probes, Metrics, and Events」をご参照ください。
ACK KubeSkoop コンポーネントは ConfigMap からの設定変更を自動的にホットリロードするため、再起動する必要はありません。
-
ARMS Prometheus ダッシュボードの設定
にログインします。 ARMSコンソールを使用します。
-
左側のナビゲーションペインで、アクセス管理 をクリックします。
-
アクセス管理 ページで、[統合の追加] をクリックします。検索ボックスで KubeSkoop を検索し、[ACK KubeSkoop Network Monitoring] をクリックします。
-
[ACK KubeSkoop Network Monitoring] ダイアログボックスで、統合する ACK クラスターを選択し、[統合名] を入力します。次に、OK をクリックして KubeSkoop モニタリングを有効にします。
ACK コンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、 を選択します。
-
その他 タブをクリックします。ダッシュボードのリストで、ノードと Pod の KubeSkoop モニタリングダッシュボードである、ACK KubeSkoop Network Monitor - Node と ACK KubeSkoop Network Monitor - Pod を確認できます。
Managed Service for Prometheus の詳細については、「Integrate with Alibaba Cloud Managed Service for Prometheus」をご参照ください。
KubeSkoop の使用
KubeSkoop 監視メトリクスの手動確認
KubeSkoop は Prometheus フォーマットで監視メトリクスを提供します。KubeSkoop をインストールした後、任意の KubeSkoop Pod インスタンスのサービスポートにアクセスして、すべてのメトリクスを取得できます。
-
次のコマンドを実行して、すべての KubeSkoop インスタンスを取得します。
kubectl get pod -n ack-kubeskoop -o wide | grep kubeskoop-agent想定される出力:
kubeskoop-agent-2chvw 1/1 Running 0 43m 172.16.16.xxx cn-hangzhou.172.16.16.xxx <none> <none> kubeskoop-agent-2qtbf 1/1 Running 0 43m 172.16.16.xxx cn-hangzhou.172.16.16.xxx <none> <none> kubeskoop-agent-72pgf 1/1 Running 0 43m 172.16.16.xxx cn-hangzhou.172.16.16.xxx <none> <none> -
次のコマンドを実行してメトリクスを取得します。
172.16.16.xxxを、前の手順で取得した KubeSkoop インスタンスの IP アドレスに置き換えてください。curl http://172.16.16.xxx:9102/metrics
KubeSkoop は次のフォーマットで監視メトリクスを提供します:
kubeskoop_netdev_rxbytes{k8s_namespace="",k8s_node="cn-hangzhou.172.16.16.xxx",k8s_pod=""} 2.970963745e+09
断続的なネットワークの問題のトラブルシューティング
次のセクションでは、ACK KubeSkoop を使用して、一般的なクラウドネイティブの問題をトラブルシューティングする方法について説明します。
DNS タイムアウトの問題
クラウドネイティブ環境では、DNS サービスのタイムアウトにより、サービスへのアクセスに失敗する場合があります。DNS タイムアウトの一般的な原因は次のとおりです:
-
DNSサーバーの応答が遅く、アプリケーションがタイムアウトするまでに DNS クエリを完了できません。
-
クライアント側の問題により、送信側が DNS クエリパケットを迅速に送信できません。
-
サーバーは迅速に応答しますが、メモリ不足などの問題により送信側がパケットを破棄します。
断続的な DNS タイムアウトの問題のトラブルシューティングには、次のメトリクスが役立ちます:
|
メトリクス名 |
説明 |
|
kubeskoop_pod_udpsndbuferrors |
ネットワーク層を介して UDP データを送信する際に発生するエラー数です。 |
|
kubeskoop_pod_udpincsumerrors |
UDP パケットの受信時に発生するチェックサムエラー数です。 |
|
kubeskoop_pod_udpnoports |
ネットワーク層が |
|
kubeskoop_pod_udpinerrors |
UDP パケットの受信時に発生するエラー数です。 |
|
kubeskoop_pod_udpoutdatagrams |
ネットワーク層を介して UDP が正常に送信したパケット数です。 |
|
kubeskoop_pod_udprcvbuferrors |
アプリケーション層へデータをコピーする際に、ソケット受信キューが不足しているために発生するエラー数です。 |
クラウドネイティブ環境では、多くのサービスが CoreDNS によるドメイン名解決に依存しているため、DNS の問題が CoreDNS に関連している場合は、CoreDNS 関連の Pod についても前述のメトリクスを監視する必要があります。
Nginx Ingress の HTTP 499/502/503/504 エラー
クラウドネイティブ環境では、Ingress ゲートウェイやその他のプロキシサービスで断続的な例外が発生することがよくあります。Nginx Ingress およびその他の Nginx ベースのプロキシサービスでは、499、502、503、504 が最も一般的なエラーです。これらは次の内容を示します:
-
499 Client Closed Request:Nginx が応答する前に、クライアントが TCP 接続をクローズします。一般的な原因は次のとおりです:-
クライアントは接続を確立しますが、リクエストの送信が遅いため、Nginx が応答する前にクライアント側でタイムアウトが発生します。これは Android クライアントの非同期リクエストフレームワークでよく発生します。
-
接続確立後のサーバー側の処理が遅くなっています。追加の調査が必要です。
-
アップストリームバックエンドに送信されたリクエストの処理が、Nginx 側で遅延しています。
-
-
502 Bad Gateway:これは、接続失敗やバックエンドによる異常終了など、Nginx とアップストリームバックエンド間の接続レベルの問題を示すことが多いです。一般的な原因は次のとおりです:-
設定されたバックエンドの DNS 解決に失敗しています。これは、Kubernetes Service をバックエンドとして使用している場合によく発生します。
-
アップストリームとの接続確立に失敗しています。
-
アップストリームのリクエストまたはレスポンスが大きすぎるため、メモリ割り当てに失敗し、通常の業務処理が中断されます。
-
-
503 Service Unavailable:Nginx では、このステータスコードはすべてのアップストリームサーバーが利用できないことを示します。クラウドネイティブのシナリオでは、これには特有の意味があります。一般的な原因は次のとおりです:-
利用可能なバックエンドがありません (まれです) 。
-
トラフィックが過大で、Ingress のレート制限によってスロットリングされています。
-
-
504 Gateway Timeout:このエラーは、Nginx とアップストリーム間の業務関連パケットでタイムアウトが発生していることを示します。一般的な原因は、アップストリームからの応答遅延です。
これらの問題が発生した場合は、まず一般情報を収集し、問題の影響範囲と次のトラブルシューティング手順を判断します:
-
Nginx のアクセスログ情報。特に
request_time、upstream_connect_time、upstream_response_timeです。 -
問題発生時に異常なエラーメッセージがないか、Nginx の error_log 情報を確認します。
-
liveness/readiness ヘルスチェックが設定されている場合は、そのステータスを確認します。
接続失敗が発生した可能性がある場合は、この情報に基づき、次のメトリクスの変化を監視します:
|
メトリクス名 |
説明 |
|
kubeskoop_tcpext_listenoverflow |
LISTEN 状態のソケットのハーフコネクションキューがオーバーフローした場合に増加します。 |
|
kubeskoop_tcpext_listendrops |
LISTEN 状態のソケットが SYN_RECV 状態のソケットを作成できなかった場合に増加します。 |
|
kubeskoop_netdev_txdropped |
送信エラーにより、ネットワークインターフェイスカード (NIC) がパケットを破棄した回数です。 |
|
kubeskoop_netdev_rxdropped |
受信エラーにより、NIC がパケットを破棄した回数です。 |
|
kubeskoop_tcp_activeopens |
Pod が SYN パケットで TCP ハンドシェイクを正常に開始した回数です。SYN の再送は含みませんが、接続に失敗した場合もこのメトリクスは増加します。 |
|
kubeskoop_tcp_passiveopens |
Pod が TCP ハンドシェイクを完了し、ソケットの割り当てに成功した累積回数です。一般的に、正常に確立された接続数として解釈できます。 |
|
kubeskoop_tcp_retranssegs |
単一の Pod における再送セグメントの合計数です。値は TCP セグメンテーションオフロード (TSO) によるセグメンテーション後に算出されます。 |
|
kubeskoop_tcp_estabresets |
単一の Pod において TCP 接続が異常終了した回数です。このメトリクスは結果のみをカウントします。 |
|
kubeskoop_tcp_outrsts |
単一の Pod において TCP が送信したリセットパケット数です。 |
|
kubeskoop_conntrack_invalid |
さまざまな理由によりコネクショントラッキング (conntrack) エントリを確立できないものの、パケットは破棄されない回数です。 |
|
kubeskoop_conntrack_drop |
conntrack エントリを確立できなかったために破棄されたパケット数です。 |
タイムアウトが発生しているにもかかわらず Nginx の request_time が短いなど、Nginx の応答が遅いと思われる状況では、次のメトリクスの変化を監視します:
|
メトリクス名 |
説明 |
|
kubeskoop_tcpsummary_tcpestablishedconn |
ESTABLISHED 状態にある TCP 接続の現在数です。 |
|
kubeskoop_tcpsummary_tcptimewaitconn |
TIME_WAIT 状態にある TCP 接続の現在数です。 |
|
kubeskoop_tcpsummary_tcptxqueue |
ESTABLISHED 状態にある TCP 接続の送信キュー内のデータ総バイト数です。 |
|
kubeskoop_tcpsummary_tcprxqueue |
ESTABLISHED 状態にある TCP 接続の受信キュー内のデータ総バイト数です。 |
|
kubeskoop_tcpext_tcpretransfail |
再送パケットが EBUSY 以外のエラーで返された場合に増加します。これは、再送が失敗したことを示します。 |
インシデント発生中のこれらのメトリクスの変化は、調査範囲の絞り込みに役立ちます。
TCP リセットの問題
TCP リセットパケットは、TCP プロトコルにおける予期しない状況への応答です。通常、ユーザープログラムでは次のエラーが発生します:
-
Nginx などの C ライブラリに依存するアプリケーションでよく見られる
connection reset by peerエラー。 -
Java や Python などの TCP 接続ラッパーを使用するアプリケーションでよく見られる
Broken pipeエラー。
クラウドネイティブのネットワーク環境では、リセットパケットが発生する一般的な理由が数多くあります。主な原因は次のとおりです:
-
TCP に割り当てられたメモリが不足しているなど、サーバー側の例外によりサービスを正常に提供できません。この状況では通常、能動的なリセットが発生します。
-
Service またはロードバランシングを使用している場合に、エンドポイント選択や conntrack などのステートフルなメカニズムの異常により、想定外のバックエンドにトラフィックが転送されます。
-
セキュリティ上の理由で接続が解放されます。
-
NAT 環境または高同時実行のシナリオで、PAWS (Protection Against Wrapped Sequence Numbers) またはシーケンス番号のラップアラウンドが発生します。
-
TCP Keepalive を使用して接続を維持していますが、長時間にわたり業務通信が正常に行われていません。
これらの根本原因を迅速に切り分けるには、基本情報とメトリクスを収集します:
-
リセットパケットが生成された際のクライアントとサーバー間のネットワークトポロジを分析します。
-
次のメトリクスの変化を監視します:
メトリクス名
説明
kubeskoop_tcpext_tcpabortontimeout
keepalive、ウィンドウプローブ、または再送の呼び出し回数が最大値を超過したためにリセットが送信された場合に増加します。
kubeskoop_tcpext_tcpabortonlinger
TCP Linger2 オプションが有効な場合に、FIN_WAIT2 状態の接続を迅速に回収するために送信されたリセット数です。
kubeskoop_tcpext_tcpabortonclose
状態遷移 (ステートマシン) 以外の理由で TCP 接続をクローズする際に、未読データが残っているためリセットパケットが送信された場合に増加します。
kubeskoop_tcpext_tcpabortonmemory
tw_sockやtcp_sockなどのリソースを割り当てる際に、tcp_check_oomによってメモリ不足が検出されたため、接続を終了する目的で送信されたリセット数です。Linger または Linger2 オプションが有効な場合に、高速な接続回収のために送信されたリセット数です。
kubeskoop_tcpext_tcpackskippedsynrecv
SYN_RECV 状態のソケットが ACK を返信しない回数です。
kubeskoop_tcpext_tcpackskippedpaws
PAWS メカニズムによって補正がトリガーされたにもかかわらず、Out-of-Window (OOW) のレート制限により ACK パケットが送信されない回数です。
kubeskoop_tcp_estabresets
単一の Pod において TCP 接続が異常終了した回数です。このメトリクスは結果のみをカウントします。
kubeskoop_tcp_outrsts
単一の Pod において TCP が送信したリセットパケット数です。
断続的なネットワーク遅延のジッター
断続的なネットワーク遅延のジッターは、クラウドネイティブ環境で一般的であり、診断が難しい問題です。原因は多岐にわたり、前述の3種類の問題につながる可能性があります。コンテナネットワークのシナリオでは、ノード内のネットワーク遅延は通常、次の原因で発生します:
-
RT スケジューラによって管理されるリアルタイムプロセスの実行が長すぎるため、業務プロセスまたはネットワークのカーネルスレッドが長時間キューに滞留したり、処理が遅くなったりします。
-
プロセス自体で、クラウドディスクの応答遅延や RDS のラウンドトリップタイム (RTT) の断続的な増加など、外部呼び出しが突発的に長時間化し、リクエスト処理が遅くなります。
-
ノード設定の問題により、CPU または NUMA ノード間で負荷が不均一になり、高負荷のシステムで遅延が発生します。
-
カーネル内のステートフルなメカニズム (conntrack の confirm 操作など) が遅延を引き起こしたり、多数の孤立ソケットが通常のソケット検索に影響を与えたりします。
これらの問題はネットワークの問題として現れますが、根本原因は別のオペレーティングシステム要因に関連していることが多いです。調査範囲を絞り込むには、次のメトリクスを監視します:
|
メトリクス名 |
説明 |
|
kubeskoop_io_ioreadsyscall |
|
|
kubeskoop_io_iowritesyscall |
|
|
kubeskoop_io_ioreadbytes |
プロセスがファイルシステムから読み取ったバイト数です。通常はブロックデバイスから読み取られます。 |
|
kubeskoop_io_iowritebytes |
プロセスがファイルシステムに書き込んだバイト数です。 |
|
kubeskoop_tcpext_tcptimeouts |
輻輳回避 (CA) 状態が recovery、loss、または disorder に入っていない場合にトリガーされます。SYN パケットが ACK されず再送された場合に増加します。 |
|
kubeskoop_tcpsummary_tcpestablishedconn |
ESTABLISHED 状態にある TCP 接続の現在数です。 |
|
kubeskoop_tcpsummary_tcptimewaitconn |
TIME_WAIT 状態にある TCP 接続の現在数です。 |
|
kubeskoop_tcpsummary_tcptxqueue |
ESTABLISHED 状態にある TCP 接続の送信キュー内のデータ総バイト数です。 |
|
kubeskoop_tcpsummary_tcprxqueue |
ESTABLISHED 状態にある TCP 接続の受信キュー内のデータ総バイト数です。 |
|
kubeskoop_softnet_processed |
単一の Pod 内で、すべての CPU が NIC のバックログから処理したパケット数です。 |
|
kubeskoop_softnet_dropped |
単一の Pod 内で、すべての CPU により破棄されたパケット数です。 |
ケーススタディ
以下のケーススタディでは、ACK KubeSkoop を使用して複雑なネットワークの問題をトラブルシューティングする方法を紹介します。
ケース1:断続的なDNSタイムアウト
問題
あるお客様の環境で、断続的なDNS名前解決のタイムアウトが発生しました。お客様のアプリケーションは PHP で実行されており、DNS サービスは CoreDNS で設定されていました。
トラブルシューティングのプロセス
-
お客様からの説明に基づき、DNS 関連の監視データを取得しました。
-
エラー期間中のデータを分析した結果、次のことが判明しました。
-
kubeskoop_udp_noportsメトリクスがエラー期間中に 1 増加しました。全体的なメトリクス値はわずかでした。 -
kubeskoop_packetloss_totalメトリクスが 1 増加しました。パケットロスの変化はわずかでした。
-
-
お客様は、設定された DNS アドレスがパブリックサービスプロバイダーのアドレスであると報告しました。この情報と監視データを組み合わせた結果、DNS 応答の遅延が根本原因であることがわかりました。DNS 応答パケットは、ユーザー側のアプリケーションがタイムアウトした後に到着していました。
ケース2:Java における断続的な接続障害
問題
あるお客様から、Tomcat インスタンスが断続的に利用できなくなり、停止のたびに5~10秒間続いたとの報告がありました。
トラブルシューティングのプロセス
-
ログ分析の結果、問題発生時にお客様の Java ランタイムがガベージコレクション (GC) 操作を実行していたことが判明しました。
-
KubeSkoop モニタリングをデプロイしたところ、問題発生時に
kubeskoop_tcpext_listendropsメトリクスが大幅に増加していることが判明しました。 -
お客様の Java ランタイムが GC を実行するとリクエスト処理速度が低下し、接続の解放が遅延することがわかりました。しかし、新しい接続リクエストは制限されず、大量の接続が作成されていました。これにより、リスンソケットのバックログが一杯になってオーバーフローが発生し、
kubeskoop_tcpext_listendropsの増加につながりました。 -
お客様の接続の滞留は短時間であり、処理能力に問題はありませんでした。関連する Tomcat パラメーターを調整するよう推奨したところ、問題は解決されました。
ケース3:断続的なネットワークレイテンシージッター
問題
あるお客様の環境で、アプリケーションと Redis 間のリクエストで断続的な RTT の増加が発生し、ビジネスタイムアウトにつながっていることが判明しました。しかし、問題を再現することはできませんでした。
トラブルシューティングのプロセス
-
ログ分析の結果、お客様の環境で合計応答時間が 300 ms を超える Redis リクエストが断続的に発生していることがわかりました。
-
KubeSkoop をデプロイした後、監視データから問題発生時に
kubeskoop_virtcmdlatency_latencyメトリクスが増加したことが確認されました。増加したle(Prometheus ヒストグラムバケットラベル) の値は 18 と 15 でした。これは、2つの高レイテンシーの仮想化コールが発生したことを意味します。le=15のコールは 36 ms を超える遅延を、le=18のコールは 200 ms を超える遅延をそれぞれ引き起こしました。 -
カーネルの仮想化コールは CPU を占有しプリエンプトできないため、Pod の一括作成と削除中に長時間実行される仮想化コールが、断続的なレイテンシーを引き起こしていました。
ケース4:Ingress Nginx のヘルスチェック失敗
問題
Ingress マシンで断続的なヘルスチェックの失敗が発生し、それに伴いビジネスリクエストも失敗していました。
トラブルシューティングのプロセス
-
モニタリングをデプロイしたところ、問題発生時にいくつかのメトリクスで異常な変化が見られることが判明しました。
-
kubeskoop_tcpsummary_tcprxqueueとkubeskoop_tcpsummary_tcptxqueueの両方が増加しました。 -
kubeskoop_tcpext_tcptimeoutsが増加しました。 -
kubeskoop_tcpsummary_tcptimewaitconnが減少し、kubeskoop_tcpsummary_tcpestablishedconnが増加しました。
-
-
分析の結果、カーネルは正常に動作しており、接続も正しく確立されていることが確認できました。しかし、受信ソケットからのパケット処理やパケット送信を含むプロセスの実行に異常が見られました。ユーザープロセスのスケジューリングまたはリソース制限の問題が疑われました。
-
Cgroup モニタリングを確認したところ、お客様の環境で問題発生時に CPU スロットリングが発生していたことが判明しました。これにより、Cgroup の制限がユーザープロセスのスケジューリングを断続的に妨げていたことが裏付けられました。
-
ガイド 「CPUバーストパフォーマンス最適化ポリシーの有効化」 に従って Ingress に CPU バースト機能を設定することで、この種の問題は解決しました。