排查 Google Distributed Cloud NFS 和 DataPlane v2 问题

本文档详细介绍了在 NFS 装载出现问题且卷或 Pod 卡住,并且您在创建集群时启用了 DataPlane v2 的情况下 Google Distributed Cloud 的手动过程。

以下版本已修复此问题:

  • 对于次要版本 1.16,版本 1.16.4-gke.37 及更高版本。
  • 对于次要版本 1.28,版本 1.28.200-gke.111 及更高版本。

我们建议您升级到已修复此问题的版本。如果您无法升级,请按照以下部分中概述的过程操作。

如果您使用未修复此问题的版本,则在工作负载使用由易受此问题影响的存储驱动程序提供支持的 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),可能会遇到此问题。

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

查看现有集群配置

从集群中获取一些现有配置值。您将在下一部分中使用这些步骤中的值来创建 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 DaemonSet 中获取 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:Cilium 映像的前缀,例如 gcr.io/gke-on-prem-release
    • RegistryCredentialsSecretName:映像拉取 Secret 名称,例如 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 联系。