Soluciona problemas de NFS y DataPlane v2 de Google Distributed Cloud

En este documento, se detalla un procedimiento manual para Google Distributed Cloud si tienes problemas con las activaciones de NFS con un volumen o Pod atascado, y creaste tu clúster con DataPlane v2 habilitado.

Este problema se corrigió en las siguientes versiones:

  • Para la versión secundaria 1.16, la versión 1.16.4-gke.37 y versiones posteriores.
  • Para la versión secundaria 1.28, la versión 1.28.200-gke.111 y versiones posteriores.

Te recomendamos que actualices a una versión en la que se haya corregido este problema. Si no puedes actualizar, usa los procedimientos que se describen en las siguientes secciones.

Si usas una versión en la que no se corrigió este problema, es posible que tengas problemas si tienes cargas de trabajo que usan volúmenes de ReadWriteMany con controladores de almacenamiento que son susceptibles a este problema, como los siguientes (sin limitarse a ellos):

  • Robin.io
  • Portworx (volúmenes de servicio de sharedv4)
  • csi-nfs

Los segmentos de NFS en algunas arquitecturas de almacenamiento pueden quedar atascados cuando se conectan a un extremo con un servicio de Kubernetes (ClusterIP) y DataPlane v2. Este comportamiento se debe a las limitaciones en la forma en que el código de socket del kernel de Linux interactúa con el programa eBPF de Cilium. Es posible que los contenedores se bloqueen en E/S o incluso que no se puedan detener, ya que no se puede desmontar el montaje de NFS obsoleto.

Es posible que experimentes este problema si usas almacenamiento RWX alojado en servidores NFS que se ejecutan en un nodo de Kubernetes, incluidas las soluciones de almacenamiento definidas por software o hiperconvergentes, como Ondat, Robin.io o Portworx.

Revisa la configuración del clúster existente

Obtén algunos valores de configuración existentes de tu clúster. Usarás los valores de estos pasos para crear un manifiesto kube-proxy en la siguiente sección.

  1. Obtén el ClusterCIDR de cm/cilium-config:

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

    En el siguiente ejemplo de resultado, se muestra que usarías 192.168.0.0/16 como ClusterCIDR:

    ipv4-native-routing-cidr: 192.168.0.0/16
    native-routing-cidr: 192.168.0.0/16
    
  2. Obtén APIServerAdvertiseAddress y APIServerPort del DaemonSet anetd:

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

    En el siguiente ejemplo de resultado, se muestra que usarías 21.1.4.119 como APIServerAdvertiseAddress y 443 como APIServerPort:

    - name: KUBERNETES_SERVICE_HOST
      value: 21.1.4.119
    - name: KUBERNETES_SERVICE_PORT
      value: "443"
    
  3. Obtén el RegistryCredentialsSecretName del DaemonSet anetd:

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

    En el siguiente ejemplo de resultado, se muestra que usarías private-registry-creds como RegistryCredentialsSecretName:

    imagePullSecrets:
      - name: private-registry-creds
    
  4. Obtén el Registry del DaemonSet anetd:

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

    En el siguiente ejemplo de resultado, se muestra que usarías gcr.io/gke-on-prem-release como Registry:

    image: gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7
    
  5. Obtén el valor de KubernetesVersion de la etiqueta de la imagen para kube-apiserver en el espacio de nombres del clúster de administrador:

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

    Reemplaza ADMIN_KUBECONFIG por el archivo kubeconfig de tu clúster de administrador y CLUSTER_NAME por el nombre de tu clúster de usuario.

    En el siguiente ejemplo de resultado, se muestra que usarías v1.26.2-gke.1001 como KubernetesVersion:

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

Prepara manifiestos de kube-proxy

Usa los valores obtenidos en la sección anterior para crear y aplicar un manifiesto YAML que implementará kube-proxy en tu clúster.

  1. Crea un manifiesto llamado kube-proxy.yaml en el editor que elijas:

    nano kube-proxy.yaml
    
  2. Copia y pega la siguiente definición de 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
    

    En este manifiesto YAML, establece los siguientes valores:

    • APIServerAdvertiseAddress: Es el valor de KUBERNETES_SERVICE_HOST, como 21.1.4.119.
    • APIServerPort: Es el valor de KUBERNETES_SERVICE_PORT, como 443.
    • Registry: Es el prefijo de la imagen de Cilium, como gcr.io/gke-on-prem-release.
    • RegistryCredentialsSecretName: Es el nombre del secreto de extracción de la imagen, como private-registry-creds.
  3. Guarda y cierra el archivo de manifiesto en tu editor.

Prepara el parche de anetd

Crea y prepara una actualización para anetd:

  1. Crea un manifiesto llamado cilium-config-patch.yaml en el editor que elijas:

    nano cilium-config-patch.yaml
    
  2. Copia y pega la siguiente definición de YAML:

    data:
      kube-proxy-replacement: "disabled"
      kube-proxy-replacement-healthz-bind-address: ""
      retry-kube-proxy-healthz-binding: "false"
      enable-host-reachable-services: "false"
    
  3. Guarda y cierra el archivo de manifiesto en tu editor.

Implementa kube-proxy y vuelve a configurar anetd

Aplica los cambios de configuración al clúster. Crea copias de seguridad de tu configuración existente antes de aplicar los cambios.

  1. Crea una copia de seguridad de la configuración actual de anetd y cilium-config:

    kubectl get ds -n kube-system anetd > anetd-original.yaml
    kubectl get cm -n kube-system cilium-config > cilium-config-original.yaml
    
  2. Aplica kube-proxy.yaml con kubectl:

    kubectl apply -f kube-proxy.yaml
    
  3. Verifica que los Pods sean Running:

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

    En el siguiente ejemplo de resultado condensado, se muestra que los Pods se ejecutan correctamente:

    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. Aplica un parche al ConfigMap cilium-config con kubectl:

    kubectl patch cm -n kube-system cilium-config --patch-file cilium-config-patch.yaml
    
  5. Edita anetd con kubectl:

    kubectl edit ds -n kube-system anetd
    

    En el editor que se abre, edita las especificaciones de anetd. Inserta lo siguiente como el primer elemento en 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
    

    Reemplaza Image por la misma imagen que se usa en los otros contenedores de Cilium en el DaemonSet anetd, como gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7.

  6. Guarda y cierra el archivo de manifiesto en tu editor.

  7. Para aplicar estos cambios, reinicia todos los nodos de tu clúster. Para minimizar las interrupciones, puedes intentar desviar el tráfico de cada nodo antes de reiniciarlo. Sin embargo, es posible que los Pods que usan volúmenes RWX queden atascados en un estado Terminating debido a que las activaciones de NFS interrumpidas bloquean el proceso de vaciado.

    Puedes forzar la eliminación de los Pods bloqueados y permitir que el nodo se drene correctamente:

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

    Reemplaza POD_NAME por el Pod que intentas borrar y POD_NAMESPACE por su espacio de nombres.

¿Qué sigue?

Si necesitas asistencia adicional, comunícate con Atención al cliente de Cloud.

También puedes consultar Cómo obtener asistencia para obtener más información sobre los recursos de asistencia, incluidos los siguientes: