本文档详细介绍了在 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),可能会遇到此问题。
查看现有集群配置
从集群中获取一些现有配置值。您将在下一部分中使用这些步骤中的值来创建 kube-proxy
清单。
从
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
从
anetd
DaemonSet 获取APIServerAdvertiseAddress
和APIServerPort
: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"
从
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
从
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
从管理员集群的集群命名空间中
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
部署到集群。
在您选择的编辑器中创建名为
kube-proxy.yaml
的清单:nano kube-proxy.yaml
复制并粘贴以下 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 清单中,设置以下值:
APIServerAdvertiseAddress
:KUBERNETES_SERVICE_HOST
的值,例如21.1.4.119
。APIServerPort
:KUBERNETES_SERVICE_PORT
的值,例如443
。Registry
:Cilium 映像的前缀,例如gcr.io/gke-on-prem-release
。RegistryCredentialsSecretName
:映像拉取 Secret 名称,例如private-registry-creds
。
在编辑器中保存并关闭清单文件。
准备 anetd
补丁
为 anetd
创建并准备更新:
在您选择的编辑器中创建名为
cilium-config-patch.yaml
的清单:nano cilium-config-patch.yaml
复制并粘贴以下 YAML 定义:
data: kube-proxy-replacement: "disabled" kube-proxy-replacement-healthz-bind-address: "" retry-kube-proxy-healthz-binding: "false" enable-host-reachable-services: "false"
在编辑器中保存并关闭清单文件。
部署 kube-proxy
并重新配置 anetd
将配置更改应用于集群。在应用更改之前,请先创建现有配置的备份。
备份当前的
anetd
和cilium-config
配置:kubectl get ds -n kube-system anetd > anetd-original.yaml kubectl get cm -n kube-system cilium-config > cilium-config-original.yaml
使用
kubectl
应用kube-proxy.yaml
:kubectl apply -f kube-proxy.yaml
检查 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) [...]
使用
kubectl
修补cilium-config
ConfigMap:kubectl patch cm -n kube-system cilium-config --patch-file cilium-config-patch.yaml
使用
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
。在编辑器中保存并关闭清单文件。
如需应用这些更改,请重新启动集群中的所有节点。为了尽可能减少中断,您可以在重新启动之前尝试排空每个节点。不过,使用 RWX 卷的 Pod 可能会因 NFS 装载中断而卡在
Terminating
状态,从而阻止排空过程。您可以强制删除被阻止的 Pod,并允许节点正常排空:
kubectl delete pods -–force -–grace-period=0 --namespace POD_NAMESPACE POD_NAME
将
POD_NAME
替换为您尝试删除的 Pod,并将POD_NAMESPACE
替换为其命名空间。