Resolva problemas do Google Distributed Cloud NFS e do DataPlane v2

Este documento detalha um procedimento manual para o Google Distributed Cloud se tiver problemas com montagens NFS com um volume ou um pod bloqueado e tiver criado o cluster com o DataPlane v2 ativado.

Este problema foi corrigido para as seguintes versões:

  • Para a versão secundária 1.16, versão 1.16.4-gke.37 e superior.
  • Para a versão secundária 1.28, versão 1.28.200-gke.111 e superior.

Recomendamos que atualize para uma versão em que este problema esteja corrigido. Se não conseguir atualizar, use os procedimentos descritos nas secções seguintes.

Se estiver a usar uma versão em que este problema não está corrigido, pode ter problemas se tiver cargas de trabalho que usem volumes ReadWriteMany com tecnologia de controladores de armazenamento suscetíveis a este problema, como (entre outros):

  • Robin.io
  • Portworx (volumes de serviço sharedv4)
  • csi-nfs

As montagens NFS em algumas arquiteturas de armazenamento podem ficar bloqueadas quando estão ligadas a um ponto final através de um serviço Kubernetes (ClusterIP) e do DataPlane v2. Este comportamento deve-se às limitações na forma como o código de soquete do kernel do Linux interage com o programa eBPF do Cillium. Os contentores podem ficar bloqueados na E/S ou até mesmo não ser elimináveis, uma vez que não é possível desmontar a montagem NFS obsoleta.

Pode ter este problema se usar o armazenamento RWX alojado em servidores NFS que são executados num nó do Kubernetes, incluindo soluções de armazenamento definidas por software ou hiperconverged, como Ondat, Robin.io ou Portworx.

Reveja a configuração do cluster existente

Obter alguns valores de configuração existentes do seu cluster. Use os valores destes passos para criar um kube-proxy manifesto na secção seguinte.

  1. Apanhe a linha ClusterCIDR na estação cm/cilium-config:

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

    O exemplo de resultado seguinte mostra que usaria 192.168.0.0/16 como o ClusterCIDR:

    ipv4-native-routing-cidr: 192.168.0.0/16
    native-routing-cidr: 192.168.0.0/16
    
  2. Obtenha o APIServerAdvertiseAddress e o APIServerPort do DaemonSet anetd:

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

    O resultado do exemplo seguinte mostra que usaria 21.1.4.119 como APIServerAdvertiseAddress e 443 como APIServerPort:

    - name: KUBERNETES_SERVICE_HOST
      value: 21.1.4.119
    - name: KUBERNETES_SERVICE_PORT
      value: "443"
    
  3. Obtenha o RegistryCredentialsSecretName do anetd DaemonSet:

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

    O exemplo de resultado seguinte mostra que usaria private-registry-creds como RegistryCredentialsSecretName:

    imagePullSecrets:
      - name: private-registry-creds
    
  4. Obtenha o Registry do DaemonSet anetd:

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

    O exemplo de resultado seguinte mostra que usaria 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. Obtenha o KubernetesVersion da etiqueta de imagem para kube-apiserver no espaço de nomes do cluster do cluster de administrador:

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

    Substitua ADMIN_KUBECONFIG pelo ficheiro kubeconfig do cluster de administrador e CLUSTER_NAME pelo nome do cluster de utilizador.

    O exemplo de saída seguinte mostra que usaria v1.26.2-gke.1001 como KubernetesVersion:

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

Prepare kube-proxy manifestos

Use os valores obtidos na secção anterior para criar e aplicar um manifesto YAML que implemente o kube-proxy no cluster.

  1. Crie um manifesto denominado kube-proxy.yaml no editor à sua escolha:

    nano kube-proxy.yaml
    
  2. Copie e cole a seguinte definição 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
    

    Neste manifesto YAML, defina os seguintes valores:

    • APIServerAdvertiseAddress: o valor de KUBERNETES_SERVICE_HOST, como 21.1.4.119.
    • APIServerPort: o valor de KUBERNETES_SERVICE_PORT, como 443.
    • Registry: o prefixo da imagem do Cilium, como gcr.io/gke-on-prem-release.
    • RegistryCredentialsSecretName: o nome do segredo de obtenção de imagens, como private-registry-creds.
  3. Guarde e feche o ficheiro de manifesto no editor.

Prepare o patch anetd

Crie e prepare uma atualização para anetd:

  1. Crie um manifesto com o nome cilium-config-patch.yaml no editor à sua escolha:

    nano cilium-config-patch.yaml
    
  2. Copie e cole a seguinte definição YAML:

    data:
      kube-proxy-replacement: "disabled"
      kube-proxy-replacement-healthz-bind-address: ""
      retry-kube-proxy-healthz-binding: "false"
      enable-host-reachable-services: "false"
    
  3. Guarde e feche o ficheiro de manifesto no editor.

Implemente kube-proxy e reconfigure anetd

Aplique as alterações de configuração ao cluster. Crie cópias de segurança da sua configuração existente antes de aplicar as alterações.

  1. Faça uma cópia de segurança da configuração atual do anetd e do 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. Aplique kube-proxy.yaml através de kubectl:

    kubectl apply -f kube-proxy.yaml
    
  3. Verifique se os Pods estão Running:

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

    O exemplo de saída condensada seguinte mostra que os pods estão a ser executados corretamente:

    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. Aplique uma correção ao cilium-config ConfigMap através de kubectl:

    kubectl patch cm -n kube-system cilium-config --patch-file cilium-config-patch.yaml
    
  5. Edite anetd com kubectl:

    kubectl edit ds -n kube-system anetd
    

    No editor apresentado, edite a especificação de anetd. Insira o seguinte como o primeiro item em 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
    

    Substitua Image pela mesma imagem usada nos outros contentores Cilium no DaemonSet anetd, como gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7.

  6. Guarde e feche o ficheiro de manifesto no editor.

  7. Para aplicar estas alterações, reinicie todos os nós no cluster. Para minimizar a interrupção, pode tentar esgotar cada nó antes do reinício. No entanto, os pods que usam volumes RWX podem ficar bloqueados num estado Terminating devido a montagens NFS danificadas que bloqueiam o processo de drenagem.

    Pode forçar a eliminação de pods bloqueados e permitir que o nó seja esvaziado corretamente:

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

    Substitua POD_NAME pelo pod que está a tentar eliminar e POD_NAMESPACE pelo respetivo espaço de nomes.

O que se segue?

Se precisar de assistência adicional, contacte o apoio ao cliente do Google Cloud.

Também pode consultar o artigo Receber apoio técnico para mais informações sobre recursos de apoio técnico, incluindo o seguinte: