Google Distributed Cloud NFS と DataPlane v2 の問題のトラブルシューティング

このドキュメントでは、NFS マウントの問題でボリュームまたは Pod が停止し、DataPlane v2 を有効にしてクラスタを作成した場合に、Google Distributed Cloud で行う操作について詳しく説明します。

この問題は、次のバージョンで修正されています。

  • マイナー バージョン 1.16 の場合は、バージョン 1.16.4-gke.37 以降。
  • マイナー バージョン 1.28 の場合は、バージョン 1.28.200-gke.111 以降。

この問題が修正されているバージョンにアップグレードすることをおすすめします。アップグレードできない場合は、次のセクションで説明する手順で操作してください。

この問題が修正されていないバージョンを使用していて、この問題の影響を受けやすいストレージ ドライバを搭載した ReadWriteMany ボリュームを使用するワークロードがあると、問題が発生する可能性があります。このようなドライバとしては、次のようなものがあります。

  • Robin.io
  • Portworx(sharedv4 サービス ボリューム)
  • csi-nfs

一部のストレージ アーキテクチャの NFS マウントは、Kubernetes Service(ClusterIP)と DataPlane v2 を使用してエンドポイントに接続すると、停止することがあります。この問題は、Linux カーネル ソケット コードが Cillium の eBPF プログラムとやり取りする方法に制限があるために発生します。機能しない NFS マウントはマウント解除できないため、コンテナが I/O でブロックされたり、強制終了できなくなる可能性があります。

この問題は、Kubernetes ノードで実行される NFS サーバーでホストされている RWX ストレージを使用している場合に発生することがあります。これには、Ondat、Robin.io、Portworx などのソフトウェア定義ストレージ ソリューションやハイパーコンバージド ストレージ ソリューションが含まれます。

さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。

既存のクラスタ構成を確認する

クラスタから既存の構成値を取得します。ここで取得した値は、次のセクションで kube-proxy マニフェストを作成する際に使用します。

  1. cm/cilium-config から ClusterCIDR を取得します。

    kubectl get cm -n kube-system cilium-config -o yaml | grep native-routing-cidr
    

    次の出力例は、ClusterCIDR として 192.168.0.0/16 を使用することを示しています。

    ipv4-native-routing-cidr: 192.168.0.0/16
    native-routing-cidr: 192.168.0.0/16
    
  2. anetd DaemonSet から APIServerAdvertiseAddressAPIServerPort を取得します。

    kubectl get ds -n kube-system  anetd -o yaml | grep KUBERNETES -A 1
    

    次の出力例は、APIServerAdvertiseAddress として 21.1.4.119 を使用し、APIServerPort として 443 を使用することを示しています。

    - name: KUBERNETES_SERVICE_HOST
      value: 21.1.4.119
    - name: KUBERNETES_SERVICE_PORT
      value: "443"
    
  3. anetd DaemonSet から RegistryCredentialsSecretName を取得します。

    kubectl get ds -n kube-system  anetd -o yaml | grep imagePullSecrets -A 1
    

    次の出力例は、RegistryCredentialsSecretName として private-registry-creds を使用することを示しています。

    imagePullSecrets:
      - name: private-registry-creds
    
  4. anetd DameonSet から Registry を取得します。

    kubectl get ds -n kube-system  anetd -o yaml | grep image
    

    次の出力例は、Registry として gcr.io/gke-on-prem-release を使用することを示しています。

    image: gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7
    
  5. 管理クラスタのクラスタ Namespace で kube-apiserver のイメージタグから KubernetesVersion を取得します。

    KUBECONFIG=ADMIN_KUBECONFIG
    kubectl get sts -n CLUSTER_NAME kube-apiserver -o yaml | grep image
    

    ADMIN_KUBECONFIG は、管理クラスタの kubeconfig ファイルに置き換え、CLUSTER_NAME はユーザー クラスタの名前に置き換えます。

    次の出力例は、KubernetesVersion として v1.26.2-gke.1001 を使用することを示しています。

    image: gcr.io/gke-on-prem-release/kube-apiserver-amd64:v1.26.2-gke.1001
    imagePullPolicy: IfNotPresent
    

kube-proxy マニフェストを準備する

前のセクションで取得した値を使用して、kube-proxy をクラスタにデプロイする YAML マニフェストを作成して適用します。

  1. 任意のエディタで、kube-proxy.yaml という名前のマニフェストを作成します。

    nano kube-proxy.yaml
    
  2. 次の YAML 定義をコピーして貼り付けます。

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      labels:
        k8s-app: kube-proxy
      name: kube-proxy
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          k8s-app: kube-proxy
      template:
        metadata:
          annotations:
            scheduler.alpha.kubernetes.io/critical-pod: ""
          labels:
            k8s-app: kube-proxy
        spec:
          containers:
          - command:
            - kube-proxy
            - --v=2
            - --profiling=false
            - --iptables-min-sync-period=10s
            - --iptables-sync-period=1m
            - --oom-score-adj=-998
            - --ipvs-sync-period=1m
            - --ipvs-min-sync-period=10s
            - --cluster-cidr=ClusterCIDR
            env:
            - name: KUBERNETES_SERVICE_HOST
              value:APIServerAdvertiseAddress
            - name: KUBERNETES_SERVICE_PORT
              value: "APIServerPort"
            image: Registry/kube-proxy-amd64:KubernetesVersion
            imagePullPolicy: IfNotPresent
            name: kube-proxy
            resources:
              requests:
                cpu: 100m
                memory: 15Mi
            securityContext:
              privileged: true
            volumeMounts:
            - mountPath: /run/xtables.lock
              name: xtables-lock
            - mountPath: /lib/modules
              name: lib-modules
          imagePullSecrets:
          - name: RegistryCredentialsSecretName
          nodeSelector:
            kubernetes.io/os: linux
          hostNetwork: true
          priorityClassName: system-node-critical
          serviceAccount: kube-proxy
          serviceAccountName: kube-proxy
          tolerations:
          - effect: NoExecute
            operator: Exists
          - effect: NoSchedule
            operator: Exists
          volumes:
          - hostPath:
              path: /run/xtables.lock
              type: FileOrCreate
            name: xtables-lock
          - hostPath:
              path: /lib/modules
              type: DirectoryOrCreate
            name: lib-modules
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: system:kube-proxy
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: ClusterRole
        name: system:node-proxier
      subjects:
        - kind: ServiceAccount
          name: kube-proxy
          namespace: kube-system
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: kube-proxy
        namespace: kube-system
    

    この YAML マニフェストで、次の値を設定します。

    • APIServerAdvertiseAddress: KUBERNETES_SERVICE_HOST の値(21.1.4.119 など)。
    • APIServerPort: KUBERNETES_SERVICE_PORT の値(443 など)。
    • Registry: Cilium イメージの接頭辞(gcr.io/gke-on-prem-release など)。
    • RegistryCredentialsSecretName: イメージ pull シークレット名(private-registry-creds など)。
  3. エディタでマニフェスト ファイルを保存して閉じます。

anetd パッチを準備する

anetd の更新を作成して準備します。

  1. 任意のエディタで、cilium-config-patch.yaml という名前のマニフェストを作成します。

    nano cilium-config-patch.yaml
    
  2. 次の YAML 定義をコピーして貼り付けます。

    data:
      kube-proxy-replacement: "disabled"
      kube-proxy-replacement-healthz-bind-address: ""
      retry-kube-proxy-healthz-binding: "false"
      enable-host-reachable-services: "false"
    
  3. エディタでマニフェスト ファイルを保存して閉じます。

kube-proxy をデプロイして anetd を再構成する

構成の変更をクラスタに適用します。変更を適用する前に、既存の構成のバックアップを作成します。

  1. 現在の anetdcilium-config の構成をバックアップします。

    kubectl get ds -n kube-system anetd > anetd-original.yaml
    kubectl get cm -n kube-system cilium-config > cilium-config-original.yaml
    
  2. kubectl を使用して kube-proxy.yaml を適用します。

    kubectl apply -f kube-proxy.yaml
    
  3. Pod が Running であることを確認します。

    kubectl get pods -n kube-system -o wide | grep kube-proxy
    

    次の要約された出力の例は、Pod が正しく実行されていることを示しています。

    kube-proxy-f8mp9    1/1    Running   1 (4m ago)    [...]
    kube-proxy-kndhv    1/1    Running   1 (5m ago)    [...]
    kube-proxy-sjnwl    1/1    Running   1 (4m ago)    [...]
    
  4. kubectl を使用して cilium-config ConfigMap にパッチを適用します。

    kubectl patch cm -n kube-system cilium-config --patch-file cilium-config-patch.yaml
    
  5. kubectl を使用して anetd を編集します。

    kubectl edit ds -n kube-system anetd
    

    開いたエディタで anetd の仕様を編集します。initContainers の最初の項目として、次のように挿入します。

    - name: check-kube-proxy-rules
      image: Image
      imagePullPolicy: IfNotPresent
      command:
      - sh
      - -ec
      - |
        if [ "$KUBE_PROXY_REPLACEMENT" != "strict" ]; then
          kube_proxy_forward() { iptables -L KUBE-FORWARD; }
          until kube_proxy_forward; do sleep 2; done
        fi;
      env:
      - name: KUBE_PROXY_REPLACEMENT
        valueFrom:
          configMapKeyRef:
            key: kube-proxy-replacement
            name: cilium-config
            optional: true
      securityContext:
        privileged: true
    

    Image は、anetd DaemonSet の他の Cilium コンテナで使用されているイメージ(gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7 など)に置き換えます。

  6. エディタでマニフェスト ファイルを保存して閉じます。

  7. これらの変更を適用するには、クラスタ内のすべてのノードを再起動します。中断を最小限に抑えるために、再起動の前に各ノードのドレインを試すことができます。ただし、NFS マウントの破損が原因でドレイン プロセスがブロックされると、RWX ボリュームを使用する Pod が Terminating 状態のままになる場合があります。

    ブロックされた Pod を強制的に削除すると、ノードを正しくドレインできます。

    kubectl delete pods -–force -–grace-period=0 --namespace POD_NAMESPACE POD_NAME
    

    POD_NAME は、削除する Pod に置き換え、POD_NAMESPACE はその Namespace に置き換えます。

次のステップ

さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。