Probleme mit NFS und DataPlane v2 in Google Distributed Cloud beheben

In diesem Dokument wird eine manuelle Vorgehensweise für Google Distributed Cloud beschrieben, wenn Sie Probleme mit NFS-Bereitstellungen mit einem hängengebliebenen Volume oder Pod haben und Ihren Cluster mit aktivierter DataPlane v2 erstellt haben.

Dieses Problem wurde in den folgenden Versionen behoben:

  • Für die Nebenversion 1.16 Version 1.16.4-gke.37 und höher.
  • Für die Nebenversion 1.28 Version 1.28.200-gke.111 und höher.

Wir empfehlen Ihnen, ein Upgrade auf eine Version durchzuführen, in der dieses Problem behoben ist. Wenn Sie kein Upgrade durchführen können, folgen Sie der Anleitung in den folgenden Abschnitten.

Wenn Sie eine Version verwenden, in der dieses Problem nicht behoben ist, können bei Arbeitslasten mit ReadWriteMany-Volumes, die von Speichertreibern unterstützt werden, die anfällig für dieses Problem sind, Probleme auftreten. Beispiele:

  • Robin.io
  • Portworx (sharedv4-Dienstvolumes)
  • csi-nfs

NFS-Bereitstellungen in einigen Speicherarchitekturen können hängen bleiben, wenn sie über einen Kubernetes-Dienst (ClusterIP) und DataPlane v2 mit einem Endpunkt verbunden sind. Dieses Verhalten ist auf die Einschränkungen zurückzuführen, die bei der Interaktion des Linux-Kernel-Socket-Codes mit dem eBPF-Programm von Cillium auftreten. Container können bei E/A blockiert werden oder sogar nicht zu beenden sein, da die stillgelegte NFS-Bereitstellung nicht getrennt werden kann.

Dieses Problem kann auftreten, wenn Sie RWX-Speicher verwenden, der auf NFS-Servern gehostet wird, die auf einem Kubernetes-Knoten ausgeführt werden, einschließlich softwaredefinierter oder hyperkonvergenter Speicherlösungen wie Ondat, Robin.io oder Portworx.

Wenn Sie weitere Unterstützung benötigen, wenden Sie sich an den Cloud Customer Care.

Vorhandene Clusterkonfiguration überprüfen

Rufen Sie einige vorhandene Konfigurationswerte aus Ihrem Cluster ab. Mit den Werten aus diesen Schritten erstellen Sie im nächsten Abschnitt ein kube-proxy-Manifest.

  1. ClusterCIDR von cm/cilium-config abrufen:

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

    In der folgenden Beispielausgabe wird gezeigt, dass Sie 192.168.0.0/16 als ClusterCIDR verwenden würden:

    ipv4-native-routing-cidr: 192.168.0.0/16
    native-routing-cidr: 192.168.0.0/16
    
  2. APIServerAdvertiseAddress und APIServerPort aus dem anetd-DaemonSet abrufen:

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

    In der folgenden Beispielausgabe wird gezeigt, dass Sie 21.1.4.119 als APIServerAdvertiseAddress und 443 als APIServerPort verwenden würden:

    - name: KUBERNETES_SERVICE_HOST
      value: 21.1.4.119
    - name: KUBERNETES_SERVICE_PORT
      value: "443"
    
  3. RegistryCredentialsSecretName aus dem anetd-DaemonSet abrufen:

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

    In der folgenden Beispielausgabe wird gezeigt, dass Sie private-registry-creds als RegistryCredentialsSecretName verwenden würden:

    imagePullSecrets:
      - name: private-registry-creds
    
  4. Rufen Sie die Registry aus dem anetd-Daemonset ab:

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

    In der folgenden Beispielausgabe wird gezeigt, dass Sie gcr.io/gke-on-prem-release als Registry verwenden würden:

    image: gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7
    
  5. Rufen Sie die KubernetesVersion aus dem Image-Tag für kube-apiserver im Cluster-Namespace des Administratorclusters ab:

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

    Ersetzen Sie ADMIN_KUBECONFIG durch die kubeconfig-Datei für Ihren Admin-Cluster und CLUSTER_NAME durch den Namen Ihres Nutzerclusters.

    In der folgenden Beispielausgabe wird gezeigt, dass Sie v1.26.2-gke.1001 als KubernetesVersion verwenden würden:

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

kube-proxy-Manifeste vorbereiten

Verwenden Sie die im vorherigen Abschnitt ermittelten Werte, um ein YAML-Manifest zu erstellen und anzuwenden, mit dem kube-proxy in Ihrem Cluster bereitgestellt wird.

  1. Erstellen Sie in einem Editor Ihrer Wahl ein Manifest mit dem Namen kube-proxy.yaml:

    nano kube-proxy.yaml
    
  2. Kopieren Sie die folgende YAML-Definition und fügen Sie sie ein:

    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
    

    Legen Sie in diesem YAML-Manifest die folgenden Werte fest:

    • APIServerAdvertiseAddress: der Wert von KUBERNETES_SERVICE_HOST, z. B. 21.1.4.119.
    • APIServerPort: der Wert von KUBERNETES_SERVICE_PORT, z. B. 443.
    • Registry: das Präfix des Cilium-Images, z. B. gcr.io/gke-on-prem-release.
    • RegistryCredentialsSecretName: der Name des Secrets für das Abrufen von Images, z. B. private-registry-creds.
  3. Speichern und schließen Sie die Manifestdatei in Ihrem Editor.

anetd-Patch vorbereiten

So erstellen und bereiten Sie ein Update für anetd vor:

  1. Erstellen Sie in einem Editor Ihrer Wahl ein Manifest mit dem Namen cilium-config-patch.yaml:

    nano cilium-config-patch.yaml
    
  2. Kopieren Sie die folgende YAML-Definition und fügen Sie sie ein:

    data:
      kube-proxy-replacement: "disabled"
      kube-proxy-replacement-healthz-bind-address: ""
      retry-kube-proxy-healthz-binding: "false"
      enable-host-reachable-services: "false"
    
  3. Speichern und schließen Sie die Manifestdatei in Ihrem Editor.

kube-proxy bereitstellen und anetd neu konfigurieren

Wenden Sie die Konfigurationsänderungen auf Ihren Cluster an. Erstellen Sie Sicherungen Ihrer vorhandenen Konfiguration, bevor Sie die Änderungen anwenden.

  1. Sichern Sie die aktuelle anetd- und cilium-config-Konfiguration:

    kubectl get ds -n kube-system anetd > anetd-original.yaml
    kubectl get cm -n kube-system cilium-config > cilium-config-original.yaml
    
  2. Wenden Sie kube-proxy.yaml mit kubectl an:

    kubectl apply -f kube-proxy.yaml
    
  3. Prüfen Sie, ob die Pods Running sind:

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

    Die folgende komprimierte Beispielausgabe zeigt, dass die Pods ordnungsgemäß ausgeführt werden:

    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. Patchen Sie die ConfigMap cilium-config mit kubectl:

    kubectl patch cm -n kube-system cilium-config --patch-file cilium-config-patch.yaml
    
  5. Bearbeiten Sie anetd mit kubectl:

    kubectl edit ds -n kube-system anetd
    

    Bearbeiten Sie im geöffneten Editor die Spezifikation von anetd. Fügen Sie Folgendes als erstes Element unter initContainers ein:

    - 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
    

    Ersetzen Sie Image durch dasselbe Image, das in den anderen Cilium-Containern im anetd-DaemonSet verwendet wird, z. B. gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7.

  6. Speichern und schließen Sie die Manifestdatei in Ihrem Editor.

  7. Um diese Änderungen anzuwenden, starten Sie alle Knoten in Ihrem Cluster neu. Um Unterbrechungen zu minimieren, können Sie versuchen, vor dem Neustart jeden Knoten per Drain zu beenden. Pods mit RWX-Volumes können jedoch aufgrund fehlerhafter NFS-Bereitstellungen, die den Drain-Prozess blockieren, im Status Terminating hängen bleiben.

    Sie können blockierte Pods erzwungen löschen und dem Knoten ermöglichen, ordnungsgemäß per Drain beendet zu werden:

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

    Ersetzen Sie POD_NAME durch den Pod, den Sie löschen möchten, und POD_NAMESPACE durch seinen Namespace.

Nächste Schritte

Wenn Sie weitere Unterstützung benötigen, wenden Sie sich an den Cloud Customer Care.