mcpField
G
gke-storage-troubleshooting

gke-storage-troubleshooting

github.com/google云与 DevOps21.6k1.9k 次安装今天更新
代码仓库

关于 gke-storage-troubleshooting

面向 GKE 工作负载的持久化存储故障诊断技能,适用于集群运维人员。它按故障类型提供诊断和配置修正建议,并要求保持只读诊断,将修正作为 GitOps 补丁提交,而不直接修改线上资源。

主要功能

  1. 01诊断卷挂载与附加故障
  2. 02排查磁盘性能和节点存储压力
  3. 03分析存储卷扩容未生效
  4. 04检查集群及节点池创建错误
  5. 05调查 Cloud Storage FUSE 内存溢出
  6. 06以 GitOps 补丁提出配置修正

适用场景

  1. 01处理 Pod 的卷挂载失败
  2. 02调查节点存储压力或磁盘变慢
  3. 03修复容器未反映卷扩容的问题
  4. 04排查 Cloud Storage FUSE Pod 的 OOM

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/google/skills --skill gke-storage-troubleshooting

安装后在 Claude Code 中输入/gke-storage-troubleshooting确认已加载。

附带文件references/attribution.md

详细介绍

GKE 存储故障排查技能

使用此技能系统地诊断并解决在 GKE 上运行的工作负载的持久性存储故障,包括卷挂接/挂载错误、磁盘性能和节点存储压力、卷扩容、与存储相关的集群/节点池创建错误,以及 Cloud Storage FUSE 内存问题。此技能以非交互方式运行,并会在提出清单或配置修正建议前,严格执行只读诊断边界。

对于常规存储配置以及 StorageClass/PVC 编写,请改用 gke-storage 技能。此技能专注于故障诊断。

归属信息

必须阅读:执行任何 gcloud、REST API 或 MCP 命令之前,必须先阅读使用归属信息。对于直接在终端中执行的命令(绝不在生成的脚本、Terraform 或用户代码中执行),请在 gcloud 前加上 CLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:gke-storage-troubleshooting)" ,并在 User-Agent 标头中追加 agent-skills/1.0 (skill:gke-storage-troubleshooting)。

🔍 诊断与解决工作流

步骤 0:非交互式上下文发现与试运行回退
  1. 提取参数:从用户提示、当前的 SETTINGS.md 或环境默认值中,以非交互方式提取所需上下文(project_id、 cluster_name、cluster_location、workload_name、workload_namespace、 pod_name 以及相关的 pvc_name/pv_name/node_name):

    • 如果未提供 workload_namespace,则默认为 default。
    • 从当前环境推断缺失的集群参数(kubectl config current-context 或 gcloud config get-value project)。
  2. 集群凭据与回退模式:

    • 尝试获取凭据:gcloud container clusters get-credentials {cluster_name} --location {cluster_location} --project {project_id}。
    • 回退/试运行模式:如果集群无法访问、不存在,或实时命令执行失败(例如在沙盒评估、试运行模式或离线分析中):
      • 限制重试次数,避免资源耗尽和上下文溢出。
      • 立即提供供人工操作员运行的准确 kubectl/gcloud 诊断命令。
      • 根据报告的症状综合分析根本原因,并输出建议的 GitOps 修正方案。

步骤 1:对存储症状进行分类

收集主要信号,然后跳转到步骤 2(解决方案)中匹配的分支——通常只需执行与你的诊断匹配的一个分支,而非全部分支。

诊断命令:

kubectl describe pod {pod_name} -n {workload_namespace}
kubectl get pvc,pv -n {workload_namespace}
kubectl get events -n {workload_namespace} --sort-by='.metadata.creationTimestamp'
kubectl describe node {node_name}
  • Pod 卡在 ContainerCreating,并出现挂接/挂载事件 → 卷挂接与挂载故障。
  • 节点级运行缓慢、PLEG is not healthy 或出现 StoragePressureDetected 事件 → 磁盘性能与节点存储压力。
  • 集群/节点池创建或配置错误 → 存储配置与创建故障。
  • 已扩容的卷未反映在容器内 → 卷扩容未反映在容器中。
  • Cloud Storage FUSE Pod/sidecar OOM → Cloud Storage FUSE 内存不足(OOM)事件。

步骤 2:解决方案

只执行与你在步骤 1 中的诊断相匹配的分支。这些分支是互斥的备选方案,并非连续步骤。

卷挂接与挂载故障
  • Error 400: Cannot attach RePD to an optimized VM:区域级持久磁盘不能用于内存优化型或计算优化型机器类型。

    • 如果不强制要求使用区域级 PD,请将工作负载切换到非区域级持久磁盘 StorageClass。
    • 如果确实需要区域级 PD,请使用污点和容忍度,将需要区域级 PD 的 Pod 调度到不使用优化型机器类型的节点池。
  • 节点池迁移到第 4 代(N4、N4A、N4D)机器系列后,如果工作负载使用 Persistent Disk StorageClass,Pod 仍处于 Pending / FailedScheduling 状态:N4/N4A/N4D 机器不支持 Persistent Disk(仅支持 Hyperdisk),因此绑定到 pd-* StorageClass 的 PVC 无法绑定到这些节点,也无法在其上调度。事件通常会显示 FailedScheduling,并提示卷节点亲和性/拓扑冲突。

    • 将工作负载切换到适用于 Gen4 节点池的Hyperdisk StorageClass(例如 type: hyperdisk-balanced)。
    • 对于现有 Persistent Disk 卷,请将数据迁移到 Hyperdisk 卷;原始 PD 无法挂接到 Gen4 节点。
    • 如果工作负载必须继续使用 Persistent Disk,请通过节点选择将其保留在支持 PD 的机器系列(例如 N2)上。这是机器类型与磁盘类型不兼容的问题,不是容量问题,因此增加磁盘大小或配额没有帮助。
  • 当计算类在不同 VM 代际之间回退(例如优先使用 N4,回退到 N2),或一个 StorageClass 必须服务于混合代际时,Hyperdisk Pod 无法调度:StorageClass 中单一的静态磁盘类型与回退列表中的所有机器系列都不兼容,因此 Pod 无法在回退节点上绑定其卷。

    • 使用自动磁盘类型选择:将 StorageClass 的 parameters.type 设置为 dynamic,并配置 hyperdisk-type、pd-type 和 disk-type-preference,再设置 use-allowed-disk-topology: "true",这样 GKE 就会为每个节点选择兼容的磁盘类型,并且只将 Pod 调度到支持该类型的节点上。这样,一个动态 StorageClass 就能覆盖多个 VM 代际(需要使用文档中注明的 GKE 版本)。

      动态 StorageClass 示例(GKE 1.35.3-gke.1290000+):

      apiVersion: storage.k8s.io/v1
      kind: StorageClass
      metadata:
        name: dynamic-volume
      provisioner: pd.csi.storage.gke.io
      volumeBindingMode: WaitForFirstConsumer
      allowVolumeExpansion: true
      parameters:
        type: dynamic
        pd-type: pd-balanced
        hyperdisk-type: hyperdisk-balanced
        # 对同时支持 PD 和 Hyperdisk 的节点,优先使用的存储类型;
        # 如果省略,则默认为 hyperdisk-type。
        disk-type-preference: hyperdisk-type
        # 最佳实践:仅将 Pod 调度到支持该磁盘类型的节点上。
        use-allowed-disk-topology: "true"
      
  • 由于 fsGroup 设置导致挂载无响应:如果 Pod 在包含大量文件的卷上配置了 securityContext.fsGroup,kubelet 会递归更改每个文件的所有权,这可能导致挂载超时。症状如下:

    Unable to attach or mount volumes for pod; skipping pod ... timed out waiting for the condition
    

    检查 Pod 日志中是否有 Setting volume ownership for ... and fsGroup set 条目以确认,然后采取以下一种措施:

    • 减少卷中的文件数量。
    • 设置 securityContext.fsGroupChangePolicy: OnRootMismatch,仅在顶层权限不匹配时更改所有权。
    • 如果不需要,请停止使用 fsGroup 设置。
磁盘性能与节点存储压力
  • 磁盘性能不佳(症状包括 task dockerd:... blocked for more than 300 seconds、PLEG is not healthy,或缓慢的 fs: disk usage 扫描):节点启动磁盘由操作系统、容器镜像、overlay 文件系统和基于磁盘的 emptyDir 卷共享,且节点上所有同类型磁盘的性能也由它们共同使用。

    • 标准持久磁盘小于 200 GB 的节点通常会受到影响。请增大磁盘容量或改用 SSD,尤其是在生产环境中。
    • 对于工作负载频繁使用 emptyDir 的节点池,请启用用于临时存储的本地 SSD。
  • 磁盘操作缓慢导致 Pod 创建失败:在受影响的节点版本上(GKE 1.18–1.23,且低于已修复的补丁版本),k8s_node container-runtime 日志会显示 failed to reserve container name ... is reserved for ...(containerd 问题 #4604)。

    • 在 PodSpec 中设置 restartPolicy: Always 或 OnFailure,并提高启动磁盘 IOPS(使用更大或速度更快的磁盘类型),以缓解问题。
    • 永久修复方案是使用 containerd 1.6.0+;请升级到包含此版本的 GKE 版本。
  • StoragePressureDetected(节点存储压力过高):节点条件 StoragePressureRootFileSystem 变为 True(例如,Disk /dev/nvme0n1 usage 89% exceeds threshold 85%),原因可能是 emptyDir 写入过多、拉取大型镜像或日志不断累积。

    • 在受影响的节点上使用 df -h 查看用量(重点关注 /mnt/stateful_partition 和临时挂载点)。
    • 可通过使用更大的启动磁盘、为临时存储添加本地 SSD、设置合适的 ephemeral-storage 请求/限制,以及清理未使用的文件/镜像/日志来解决。
存储配置与创建失败
  • The selected machine type ... has a fixed number of local SSD(s):EphemeralStorageLocalSsdConfig / LocalNvmeSsdBlockConfig 中指定的本地 SSD 数量与机器类型包含的固定数量不匹配。

    • 指定与机器类型匹配的本地 SSD 数量。对于第三代机器系列,请省略本地 SSD 的 count 标志,系统会自动配置正确的值。
  • Hyperdisk 存储池:创建集群或节点池失败,并出现 ZONE_RESOURCE_POOL_EXHAUSTED(或类似的 Compute Engine 资源错误):目标可用区没有足够容量来满足所请求的 Hyperdisk Balanced 磁盘或机器类型。

    • 在同一区域内选择一个有可用容量且支持 Hyperdisk Balanced 存储池的新可用区。由于存储池是区域级资源,请在新可用区删除并重新创建存储池,然后在那里创建集群/节点池。
卷扩容未反映到容器中

卷扩容必须始终通过PersistentVolumeClaim进行。直接编辑 PersistentVolume 可能会导致容器文件系统仍使用旧容量。

  1. 保持修改后的 PersistentVolume 对象不变。

  2. 编辑 PersistentVolumeClaim,并将 spec.resources.requests.storage 设置为高于当前 PersistentVolume 容量的值。

  3. kubelet 随后会自动调整 PV、PVC 和容器文件系统的大小。在 Pod 内验证:

    kubectl exec {pod_name} -n {workload_namespace} -- df -h
    
Cloud Storage FUSE 内存不足(OOM)事件

如果 Pod 出现高内存使用率,或发生与 Cloud Storage FUSE CSI 驱动程序相关的 OOM 终止:

  1. 在 Cloud Storage FUSE CSI 驱动程序的 sidecar 容器上配置 Cloud Profiler,以启用 CPU/内存快照。

  2. 在 Cloud Logging 中按 Pod 筛选,查找 OOM 事件:

    jsonPayload.involvedObject.name="{pod_name}"
    jsonPayload.involvedObject.kind="Pod"
    OOMKilled
    

    如果 sidecar 挂载器或 GCSFuse 进程发生 OOM,Pod 名称就是工作负载 Pod 的名称;如果节点驱动程序发生 OOM,则名称为 gcsfusecsi-node-*。

  3. 提取 Pod UID(jsonPayload.involvedObject.uid)和时间戳,然后在 Cloud Profiler 中使用 OOM 时间戳对应的 {pod_name}_{pod_uid} Service Version 分析匹配的快照。


步骤 3:提出 GitOps 修正方案

遵守只读诊断边界:不要使用 kubectl edit、kubectl patch 或 kubectl apply 应用实时变更。请改为提供修正后的 StorageClass、PersistentVolumeClaim、PodSpec(securityContext、restartPolicy)或节点池配置,作为可供审核的补丁,通过用户的 GitOps 流水线(例如 Config Sync、Argo CD 或 Flux)应用。

参考资料

评论

支持 Markdown