このページでは、Google Kubernetes Engine(GKE)クラスタで GKE Dataplane V2 を有効にしてトラブルシューティングする方法について説明します。
新しい Autopilot クラスタでは、バージョン 1.22.7-gke.1500 以降とバージョン 1.23.4-gke.1500 以降で GKE Dataplane V2 が有効になっています。GKE Dataplane V2 の使用に関する問題が発生した場合は、トラブルシューティングに進んでください。
GKE Dataplane V2 を使用して GKE クラスタを作成する
GKE バージョン 1.20.6-gke.700 以降で新しいクラスタを作成する場合は、gcloud CLI か GKE API を使用して、GKE Dataplane V2 を有効にできます。GKE バージョン 1.17.9 以降を使用した新しいクラスタを作成する場合は、GKE Dataplane V2 をプレビューで有効にすることもできます。
Console
GKE Dataplane V2 を使用して新しいクラスタを作成するための作業は次のとおりです。
Trusted Cloud コンソールで、[Kubernetes クラスタの作成] ページに移動します。
[ネットワーキング] セクションで、[Dataplane V2 を有効にする] チェックボックスをオンにします。GKE Dataplane V2 にはネットワーク ポリシーの適用が組み込まれているため、[Dataplane V2 を有効にする] を選択すると、[Kubernetes ネットワーク ポリシーを有効にする] オプションは無効になります。
[作成] をクリックします。
gcloud
GKE Dataplane V2 を使用して新しいクラスタを作成するには、次のコマンドを使用します。
gcloud container clusters create CLUSTER_NAME \
--enable-dataplane-v2 \
--enable-ip-alias \
--release-channel CHANNEL_NAME \
--location COMPUTE_LOCATION
次のように置き換えます。
CLUSTER_NAME
: 新しいクラスタの名前。CHANNEL_NAME
: GKE バージョン 1.20.6-gke.700 以降を含むリリース チャンネル。リリース チャンネルを使用しない場合は、--release-channel
ではなく--cluster-version
フラグを使用してバージョン 1.20.6-gke.700 以降を指定することもできます。COMPUTE_LOCATION
: 新しいクラスタの Compute Engine のロケーション。
API
GKE Dataplane V2 を使用して新しいクラスタを作成するには、create
リクエストで networkConfig
オブジェクトに datapathProvider
フィールドを指定します。
次の JSON スニペットは、GKE Dataplane V2 を有効にするために必要な構成を示しています。
"cluster":{
"initialClusterVersion":"VERSION",
"ipAllocationPolicy":{
"useIpAliases":true
},
"networkConfig":{
"datapathProvider":"ADVANCED_DATAPATH"
},
"releaseChannel":{
"channel":"CHANNEL_NAME"
}
}
次のように置き換えます。
- VERSION: クラスタのバージョン。GKE 1.20.6-gke.700 以降にする必要があります。
- CHANNEL_NAME: GKE バージョン 1.20.6-gke.700 以降を含むリリース チャンネル。
GKE Dataplane V2 に関する問題のトラブルシューティング
このセクションでは、GKE Dataplane V2 の問題を調査して解決する方法について説明します。
GKE Dataplane V2 が有効になっていることを確認します。
kubectl -n kube-system get pods -l k8s-app=cilium -o wide
GKE Dataplane V2 が実行中の場合、出力には接頭辞が
anetd-
の Pod が含まれます。anetd は GKE Dataplane V2 のネットワーク コントローラです。サービスまたはネットワーク ポリシーの適用に問題がある場合は、
anetd
の Pod ログを確認します。Cloud Logging で次のログセレクタを使用します。resource.type="k8s_container" labels."k8s-pod/k8s-app"="cilium" resource.labels.cluster_name="CLUSTER_NAME"
Pod の作成に失敗した場合は、kubelet のログで手がかりを探します。Cloud Logging で次のログセレクタを使用します。
resource.type="k8s_node" log_name=~".*/logs/kubelet" resource.labels.cluster_name="CLUSTER_NAME"
CLUSTER_NAME
は、クラスタの名前に置き換えます。または、すべてのクラスタのログを表示するには、完全に削除してください。anetd
Pod が実行されていない場合は、cilium-config ConfigMap に変更がないか確認します。この ConfigMap 内の既存のフィールドを変更しないでください。このような変更によってクラスタが不安定になり、anetd
が中断する可能性があるためです。ConfigMap は、新しいフィールドが追加された場合にのみ、デフォルトの状態に戻されます。既存のフィールドに対する変更は元に戻せないため、ConfigMap は変更またはカスタマイズしないことをおすすめします。
既知の問題
GKE Dataplane V2 クラスタでの NodePort
範囲の競合に関連する、接続が断続的になる問題
GKE Dataplane V2 クラスタでは、マスカレード トラフィックまたはエフェメラル ポートの使用で、接続が頻繁に途切れる問題が生じることがあります。これらの問題は、予約済みの NodePort
の範囲とポートの競合が原因となり、通常は次のシナリオで発生します。
カスタム
ip-masq-agent
: カスタムip-masq-agent
(バージョン 2.10 以降)を使用している場合、クラスタにNodePort
サービスまたは Load Balancer サービスが存在します。これらサービスがNodePort
の範囲と競合することで接続が断続的になることがあります。バージョン 2.10 以降では、ip-masq-agent
に--random-fully
引数がデフォルトで内部的に実装されています。これを軽減するには、ip-masq-agent
構成の引数で--random-fully=false
(バージョン 2.11 以降で使用可能)を明示的に設定します。構成の詳細については、Standard クラスタでの IP マスカレード エージェントの構成をご覧ください。エフェメラル ポート範囲の重複: GKE ノードの
net.ipv4.ip_local_port_range
で定義されたエフェメラル ポート範囲とNodePort
範囲(30000~32767)との重複によっても、接続の問題が発生することがあります。この問題を回避するには、これらの 2 つの範囲が重複しないようにします。
ip-masq-agent
構成とエフェメラル ポート範囲の設定を確認し、NodePort
範囲と競合していないことを確認します。接続が断続的になる問題が生じている場合は、これらの原因を検討し、構成を調整してください。
GKE Dataplane V2 クラスタでの hostPort
に関連する接続の問題
影響を受ける GKE バージョン: 1.29 以降
GKE Dataplane V2 を使用するクラスタでは、トラフィックがターゲットとするノードの IP で、ポートが Pod で定義された hostPort
となっている場合に、接続障害が発生することがあります。これらの問題は、主に次の 2 つのシナリオで発生します。
ノードの
hostPort
がパススルー ネットワーク ロードバランサの背後にある:hostPort
は Pod を特定のノードのポートに結び付けます。また、パススルー ネットワーク ロードバランサはすべてのノード間でトラフィックを分散します。hostPort
とパススルー ネットワーク ロードバランサを使用して Pod をインターネットに公開すると、ロードバランサによって Pod が実行されていないノードにトラフィックが送信される可能性があり、接続エラーの原因となります。これは、パススルー ネットワーク ロードバランサのトラフィックは必ずしもhostPort
Pod に転送されないという GKE Dataplane V2 の既知の制限によるものです。回避策: パススルー ネットワーク ロードバランサを使用してノード上の Pod の
hostPort
を公開する場合は、Pod のhostIP
フィールドにネットワーク ロードバランサの内部 IP アドレスまたは外部 IP アドレスを指定します。ports: - containerPort: 62000 hostPort: 62000 protocol: TCP hostIP: 35.232.62.64 - containerPort: 60000 hostPort: 60000 protocol: TCP hostIP: 35.232.62.64 # Assuming 35.232.62.64 is the external IP address of a passthrough Network Load Balancer.
hostPort
が予約済みのNodePort
の範囲と競合する:Pod の
hostPort
が予約済みのNodePort
範囲(30000~32767)と競合している場合、Cilium はトラフィックを Pod に転送できないことがあります。この動作はクラスタ バージョン 1.29 以降で確認されています。以前の Portmap メソッドに代わり、Cilium がhostPort
機能を管理するようになったことが原因です。これは Cilium の想定される動作であり、公開されているドキュメントにも記載されています。
これらの制限を以降のバージョンで修正する予定はありません。これらの問題の根本原因は Cilium の動作に関連しており、GKE で直接管理できる範囲にありません。
推奨事項: 信頼性を高めるために、hostPort
ではなく NodePort
サービスに移行することをおすすめします。NodePort
サービスで同様の機能を利用できます。
ネットワーク ポリシーのポート範囲が有効にならない
GKE Dataplane V2 が有効になっているクラスタのネットワーク ポリシーで endPort
フィールドを指定しても、有効になりません。
GKE 1.22 以降では、Kubernetes Network Policy API を使用して、ネットワーク ポリシーが適用されるポートの範囲を指定できます。この API は、Calico ネットワーク ポリシーを使用するクラスタでサポートされますが、GKE Dataplane V2 を使用するクラスタではサポートされません。
NetworkPolicy
オブジェクトを API サーバーに書き込んだ後、読み返すことで、このオブジェクトの動作を確認できます。オブジェクトに endPort
フィールドが含まれている場合、この機能が適用されます。endPort
フィールドがない場合、この機能は適用されません。いずれの場合も、API サーバーに格納されているオブジェクトがネットワーク ポリシーの信頼できる情報源になります。
詳細については、KEP-2079: Network Policy to Port Ranges をご覧ください。
Pod に failed to allocate for range 0: no IP addresses available in range set
エラー メッセージが表示される
影響を受ける GKE のバージョン: 1.22~1.25
containerd を使用し、GKE Dataplane V2 が有効になっているノードプールを実行している GKE クラスタでは、IP アドレスのリーク問題が発生し、ノード上のすべての Pod の IP アドレスが使い果たされる可能性があります。影響を受けるノードでスケジュールされた Pod には、次のようなエラー メッセージが表示されます。
failed to allocate for range 0: no IP addresses available in range set: 10.48.131.1-10.48.131.62
この問題の詳細については、containerd の問題 #5768 をご覧ください。
解決済みのバージョン
この問題を解決するには、次のいずれかの GKE バージョンにクラスタをアップグレードします。
- 1.22.17-gke.3100 以降
- 1.23.16-gke.200 以降
- 1.24.9-gke.3200 以降
- 1.25.6-gke.200 以降
GKE Standard クラスタの回避策
この問題を軽減するには、リークした Pod の IP アドレスをノードから削除します。
リークした Pod の IP アドレスを削除するには、クラスタの認証情報を取得し、次の手順で単一のノードをクリーンアップします(名前がわかっている場合)。
次のシェル スクリプトを
cleanup.sh
という名前のファイルに保存します。for hash in $(sudo find /var/lib/cni/networks/gke-pod-network -iregex '/var/lib/cni/networks/gke-pod-network/[0-9].*' -exec head -n1 {} \;); do hash="${hash%%[[:space:]]}"; if [ -z $(sudo ctr -n k8s.io c ls | grep $hash | awk '{print $1}') ]; then sudo grep -ilr $hash /var/lib/cni/networks/gke-pod-network; fi; done | sudo xargs -r rm
クラスタノードでスクリプトを実行します。
gcloud compute ssh --zone "ZONE" --project "PROJECT" NODE_NAME --command "$(cat cleanup.sh)"
NODE_NAME
は、ノードの名前に置き換えます。
このスクリプトの DaemonSet バージョンを実行し、すべてのノードで同時に実行することもできます。
次のマニフェストを
cleanup-ips.yaml
という名前のファイルに保存します。apiVersion: apps/v1 kind: DaemonSet metadata: name: cleanup-ipam-dir namespace: kube-system spec: selector: matchLabels: name: cleanup-ipam template: metadata: labels: name: cleanup-ipam spec: hostNetwork: true securityContext: runAsUser: 0 runAsGroup: 0 containers: - name: cleanup-ipam image: gcr.io/gke-networking-test-images/ubuntu-test:2022 command: - /bin/bash - -c - | while true; do for hash in $(find /hostipam -iregex '/hostipam/[0-9].*' -mmin +10 -exec head -n1 {} \; ); do hash="${hash%%[[:space:]]}" if [ -z $(ctr -n k8s.io c ls | grep $hash | awk '{print $1}') ]; then grep -ilr $hash /hostipam fi done | xargs -r rm echo "Done cleaning up /var/lib/cni/networks/gke-pod-network at $(date)" sleep 120s done volumeMounts: - name: host-ipam mountPath: /hostipam - name: host-ctr mountPath: /run/containerd volumes: - name: host-ipam hostPath: path: /var/lib/cni/networks/gke-pod-network - name: host-ctr hostPath: path: /run/containerd
クラスタで DaemonSet を実行します。
kubectl apply -f cleanup-ips.yaml
このコマンドを実行するには、クラスタの管理者として kubectl アクセス権が必要です。
実行中の DaemonSet のログを確認します。
kubectl -n kube-system logs -l name=cleanup-ipam
接続トラッキング ルックアップが正しくないため、ネットワーク ポリシーによって接続が切断される
クライアント Pod が Service または内部パススルー ネットワーク ロードバランサの仮想 IP アドレスを介して自身に接続する場合、データプレーンでの conntrack ルックアップが正しく行われず、応答パケットが既存の接続の一部として識別されません。つまり、Pod の上り(内向き)トラフィックを制限するネットワーク ポリシーが、誤ってパケットに適用されます。
この問題の影響は、Service に構成された Pod の数によって異なります。たとえば、Service にバックエンド Pod が 1 つある場合、接続は常に失敗します。Service にバックエンド Pod が 2 つある場合、接続は 50% の確率で失敗します。
解決済みのバージョン
この問題を解決するには、次のいずれかの GKE バージョンにクラスタをアップグレードします。
- 1.28.3-gke.1090000 以降
回避策
この問題は、Service マニフェストの port
と containerPort
を同じ値に構成すると軽減できます。
ヘアピン接続フローのパケット ドロップ
Pod が Service を使用して自身との TCP 接続を作成し、Pod が接続の送信元と宛先の両方である場合、GKE Dataplane V2 eBPF 接続トラッキングは接続状態を誤って追跡し、conntrack エントリがリークします。
接続タプル(プロトコル、送信元 / 宛先 IP、送信元 / 宛先ポート)がリークすると、同じ接続タプルを使用する新しい接続で、戻りパケットがドロップされる可能性があります。
解決済みのバージョン
この問題を解決するには、次のいずれかの GKE バージョンにクラスタをアップグレードします。
- 1.28.3-gke.1090000 以降
- 1.27.11-gke.1097000 以降
回避策
以下のいずれかの回避策を使用します。
Pod 内で実行され、Service を使用して自身と通信する可能性があるアプリケーションに対して TCP 再利用(キープアライブ)を有効にします。これにより、TCP FIN フラグが発行されなくなり、conntrack エントリのリークを回避できます。
短時間の接続を使用する場合は、Gateway などのプロキシ ロードバランサを使用して Pod を公開して、Service を公開します。これにより、接続リクエストの宛先がロードバランサの IP アドレスに設定され、GKE Dataplane V2 がループバック IP アドレスに対して SNAT を実行できなくなります。
GKE コントロール プレーンのアップグレードにより anetd
Pod がデッドロックする
GKE Dataplane V2(高度なデータパス)が有効になっている GKE クラスタを、バージョン 1.27 から 1.28 にアップグレードすると、デッドロックが発生する可能性があります。古い Pod を終了できない、または anetd
などの必要なコンポーネントをスケジュールできないために、ワークロードが中断する場合があります。
原因
クラスタのアップグレード プロセスでは、GKE Dataplane V2 コンポーネントに必要なリソースが増加します。この増加によりリソース競合が発生し、Cilium Container Network Interface(CNI)プラグインと Cilium デーモン間の通信が中断される可能性があります。
現象
次のような症状が生じる可能性があります。
anetd
Pod がPending
状態のままになる。- ワークロード Pod が
Terminating
状態で停止する。 failed to connect to Cilium daemon
などの Cilium 通信障害を示すエラーの発生。Pod サンドボックス用ネットワーク リソース クリーンアップ中のエラーの発生。例:
1rpc error: code = Unknown desc = failed to destroy network for sandbox "[sandbox_id]": plugin type="cilium-cni" failed (delete): unable to connect to Cilium daemon... connection refused
回避策
Standard クラスタ: この問題を解決して anetd
Pod をスケジュールできるようにするには、影響を受けるノードへの割り当て可能なリソースを一時的に増やします。
影響を受けるノードを特定し、割り当て可能な CPU とメモリを確認するには、次のコマンドを実行します。
kubectl get nodes $NODE_NAME -o json | jq '.status.allocatable | {cpu, memory}'
割り当て可能な CPU とメモリを一時的に増やすには、次のコマンドを実行します。
kubectl patch
Autopilot クラスタ: Autopilot クラスタのデッドロックの問題を解決するには、影響のある Pod を強制的に削除してリソースを解放します。
kubectl delete pod POD_NAME -n NAMESPACE --grace-period=0 --force
次のように置き換えます。
POD_NAME
: Pod の名前。NAMESPACE
: Pod の Namespace
ノードに割り当て可能なリソースを増やし、GKE バージョンの 1.27 から 1.28 へのアップグレードが完了すると、anetd
Pod は新しいバージョンで実行されます。
次のステップ
- ネットワーク ポリシー ロギングを使用して、クラスタのネットワーク ポリシーによって Pod への接続が許可または拒否される時間を記録する。
- GKE Dataplane V2 の仕組みについて確認する。