排查 GKE on VMware NFS 和 DataPlane v2 问题

本文档详细介绍了 GKE on VMware 的手动过程:如果您遇到 NFS 装载的卷或 Pod 卡住问题,并且您在创建集群时启用了 DataPlane v2 来解决问题。如果您的工作负载使用由存储驱动程序提供支持的 ReadWriteMany 卷,且易受此问题影响,则可能会遇到以下问题:

  • Robin.io
  • Portworx(sharedv4 个服务卷)
  • csi-nfs

某些存储架构上的 NFS 装载可能会在使用 Kubernetes Service (ClusterIP) 和 DataPlane v2 连接到端点时卡住。此行为是由于 Linux 内核套接字代码与 Cillium 的 eBPF 程序交互方式的限制。容器可能会在 I/O 上被阻止,甚至无法终止,因为无法卸载默认的 NFS 装载。

如果您使用托管在 Kubernetes 节点的 NFS 服务器上的 RWX 存储,包括软件定义或超融合存储解决方案(如 Ondat、Robin.io 或 Portworx),您可能会遇到此问题。

查看现有集群配置

从集群中获取一些现有配置值。在下一部分中,您将使用这些步骤中的值创建 kube-proxy 清单。

  1. cm/cilium-config 获取 ClusterCIDR

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

    以下示例输出结果显示,您将使用 192.168.0.0/16 作为 ClusterCIDR

    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
    

    以下示例输出结果显示,您将使用 21.1.4.119 作为 APIServerAdvertiseAddress,使用 443 作为 APIServerPort

    - 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
    

    以下示例输出结果显示,您将使用 private-registry-creds 作为 RegistryCredentialsSecretName

    imagePullSecrets:
      - name: private-registry-creds
    
  4. anetd DameonSet 获取 Registry

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

    以下示例输出结果显示,您将使用 gcr.io/gke-on-prem-release 作为 Registry

    image: gcr.io/gke-on-prem-release/cilium/cilium:v1.12.6-anthos1.15-gke4.2.7
    
  5. 从管理员集群的集群命名空间中 kube-apiserver 的映像标记中获取 KubernetesVersion

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

    ADMIN_KUBECONFIG 替换为您的管理员集群的 kubeconfig 文件,并将 CLUSTER_NAME 替换为您的用户集群的名称。

    以下示例输出结果显示,您将使用 v1.26.2-gke.1001 作为 KubernetesVersion

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

准备 kube-proxy 清单

使用在上一部分中获取的值创建并应用 YAML 清单,以便将 kube-proxy 部署到您的集群。

  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 清单中,设置以下值:

    • APIServerAdvertiseAddressKUBERNETES_SERVICE_HOST 的值,例如 21.1.4.119
    • APIServerPortKUBERNETES_SERVICE_PORT 的值,例如 443
    • Registry:Cilum 映像的前缀,例如 gcr.io/gke-on-prem-release
    • RegistryCredentialsSecretName:映像拉取密钥名称,例如 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. 如需应用这些更改,请重新启动集群中的所有节点。为了最大限度地减少中断,您可以尝试在重新启动之前排空每个节点。但是,使用 RWX 卷的 Pod 可能会因为 NFS 装载损坏而卡在 Terminating 状态,而这些装载会阻塞排空过程。

    您可以强制删除已屏蔽的 Pod 并允许节点正确排空:

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

    POD_NAME 替换为您尝试删除的 Pod,并将 POD_NAMESPACE 替换为其命名空间。

后续步骤

如果您需要其他帮助,请与 Cloud Customer Care 联系。