GKE Dataplane V2 の使用


このページでは、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 か Kubernetes Engine API を使用して、GKE Dataplane V2 を有効にできます。GKE バージョン 1.17.9 以降を使用した新しいクラスタを作成する場合は、GKE Dataplane V2 をプレビューで有効にすることもできます。

Console

GKE Dataplane V2 を使用して新しいクラスタを作成するには、次の作業を行います。

  1. Google Cloud コンソールで Google Kubernetes Engine のページに移動します。

    Google Kubernetes Engine に移動

  2. [ 作成] をクリックします。

  3. [構成] をクリックして、Standard クラスタを構成します。

  4. [ネットワーキング] セクションで、[Dataplane V2 を有効にする] チェックボックスをオンにします。GKE Dataplane V2 にはネットワーク ポリシーの適用が組み込まれているため、[Dataplane V2 を有効にする] を選択すると、[Kubernetes ネットワーク ポリシーを有効にする] オプションは無効になります。

  5. [作成] をクリックします。

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 の問題を調査して解決する方法について説明します。

  1. GKE Dataplane V2 が有効になっていることを確認します。

    kubectl -n kube-system get pods -l k8s-app=cilium -o wide
    

    GKE Dataplane V2 が実行中の場合、出力には接頭辞が anetd- の Pod が含まれます。anetd は GKE Dataplane V2 のネットワーク コントローラです。

  2. サービスまたはネットワーク ポリシーの適用に問題がある場合は、anetd の Pod ログを確認します。Cloud Logging で次のログセレクタを使用します。

    resource.type="k8s_container"
    labels."k8s-pod/k8s-app"="cilium"
    resource.labels.cluster_name="CLUSTER_NAME"
    
  3. Pod の作成に失敗した場合は、kubelet のログで手がかりを探します。Cloud Logging で次のログセレクタを使用します。

    resource.type="k8s_node"
    log_name=~".*/logs/kubelet"
    resource.labels.cluster_name="CLUSTER_NAME"
    

    CLUSTER_NAME は、クラスタの名前に置き換えます。または、すべてのクラスタのログを表示するには、完全に削除してください。

既知の問題

ネットワーク ポリシーのポート範囲が有効にならない

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 アドレスを削除するには、クラスタの認証情報を取得し、次の手順で単一のノードをクリーンアップします(名前がわかっている場合)。

  1. 次のシェル スクリプトを 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
    
  2. クラスタノードでスクリプトを実行します。

    gcloud compute ssh --zone "ZONE" --project "PROJECT" NODE_NAME --command "$(cat cleanup.sh)"
    

    NODE_NAME は、ノードの名前に置き換えます。

このスクリプトの DaemonSet バージョンを実行し、すべてのノードで同時に実行することもできます。

  1. 次のマニフェストを 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
    
  2. クラスタで DaemonSet を実行します。

    kubectl apply -f cleanup-ips.yaml
    

    このコマンドを実行するには、クラスタの管理者として kubectl アクセス権が必要です。

  3. 実行中の 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 マニフェストの portcontainerPort を同じ値に構成すると軽減できます。

ヘアピン接続フローのパケット ドロップ

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 を実行できなくなります。

次のステップ