Resolver problemas de NFS e DataPlane v2 do GKE no VMware

Neste documento, detalhamos um procedimento manual do GKE no VMware se você tiver problemas com as montagens NFS com um volume ou pod travado e tiver criado o cluster com o DataPlane v2 ativado. Talvez você encontre problemas se tiver cargas de trabalho usando volumes ReadWriteMany com drivers de armazenamento suscetíveis a esse problema, como, entre outros:

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

As montagens NFS em algumas arquiteturas de armazenamento podem ficar travadas quando estão conectadas a um endpoint usando um Serviço do Kubernetes (ClusterIP) e o DataPlane v2. Esse comportamento se deve às limitações na forma como o código de soquete do kernel do Linux interage com o programa eBPF do Cillium. Os contêineres podem ficar bloqueados na E/S ou até mesmo não poderem ser eliminados, já que a montagem NFS extinta não pode ser desmontada.

Você poderá enfrentar esse problema se usar o armazenamento RWX hospedado em servidores NFS que são executados em um nó do Kubernetes, incluindo soluções de armazenamento definidas por software ou hiperconvergentes, como Ondat, Robin.io ou Portworx.

Se precisar de mais ajuda, entre em contato com o Cloud Customer Care.

Revisar a configuração do cluster atual

Receba alguns valores de configuração atuais do cluster. Use os valores dessas etapas para criar um manifesto kube-proxy na próxima seção.

  1. Acesse o ClusterCIDR de cm/cilium-config:

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

    O exemplo de saída a seguir mostra que você usaria 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. Receba APIServerAdvertiseAddress e APIServerPort do DaemonSet anetd:

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

    O exemplo de saída a seguir mostra que você 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. Receba o RegistryCredentialsSecretName do DaemonSet anetd:

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

    O exemplo de saída a seguir mostra que você usaria private-registry-creds como RegistryCredentialsSecretName:

    imagePullSecrets:
      - name: private-registry-creds
    
  4. Receba o Registry do DameonSet anetd:

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

    O exemplo de saída a seguir mostra que você 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. Receba o KubernetesVersion da tag de imagem para kube-apiserver no namespace do cluster de administrador:

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

    Substitua ADMIN_KUBECONFIG pelo arquivo kubeconfig do cluster de administrador e CLUSTER_NAME pelo nome do cluster de usuário.

    O exemplo de saída a seguir mostra que você 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
    

Preparar manifestos kube-proxy

Use os valores da seção anterior para criar e aplicar um manifesto YAML que implantará kube-proxy no cluster.

  1. Crie um manifesto chamado kube-proxy.yaml no editor que preferir:

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

    Nesse 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 Cilium, como gcr.io/gke-on-prem-release.
    • RegistryCredentialsSecretName: o nome do secret de extração da imagem, como private-registry-creds.
  3. Salve e feche o arquivo de manifesto no editor.

Preparar patch anetd

Crie e prepare uma atualização para anetd:

  1. Crie um manifesto chamado cilium-config-patch.yaml no editor que preferir:

    nano cilium-config-patch.yaml
    
  2. Copie e cole a seguinte definição 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. Salve e feche o arquivo de manifesto no editor.

Implantar kube-proxy e reconfigurar anetd

Aplique as alterações de configuração ao cluster. Crie backups da configuração atual antes de aplicar as alterações.

  1. Faça backup 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 usando 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 condensado a seguir mostra que os pods estão sendo 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 um patch ao ConfigMap cilium-config usando kubectl:

    kubectl patch cm -n kube-system cilium-config --patch-file cilium-config-patch.yaml
    
  5. Editar anetd usando kubectl:

    kubectl edit ds -n kube-system anetd
    

    No editor que é aberto, 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 contêineres Cilium no DaemonSet anetd, como gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7.

  6. Salve e feche o arquivo de manifesto no editor.

  7. Para aplicar essas alterações, reinicie todos os nós do cluster. Para minimizar a interrupção, tente drenar cada nó antes da reinicialização. No entanto, os pods que usam volumes RWX podem ficar travados em um estado Terminating devido a montagens NFS interrompidas que bloqueiam o processo de drenagem.

    É possível forçar a exclusão de pods bloqueados e permitir que o nó seja drenado corretamente:

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

    Substitua POD_NAME pelo pod que você está tentando excluir e POD_NAMESPACE pelo namespace dele.

A seguir

Se precisar de mais ajuda, entre em contato com o Cloud Customer Care.