k8s-csi-s3 故障排查:从 PVC Pending 到 Pod 挂载失败的完整快速指南
k8s-csi-s3 故障排查从 PVC Pending 到 Pod 挂载失败的完整快速指南【免费下载链接】k8s-csi-s3GeeseFS-based CSI for mounting S3 buckets as PersistentVolumes项目地址: https://gitcode.com/gh_mirrors/k8s/k8s-csi-s3k8s-csi-s3 通过 CSI 标准把 S3 兼容对象存储变成 Kubernetes 里的持久卷动态创建存储桶、以 FUSE 方式挂载进容器一套配置即可让应用像用本地目录一样读写云端对象。但正因为它把对象存储伪装成文件系统出问题时症状往往五花八门——PVC 永远 Pending、Pod 卡在 ContainerCreating、挂载后目录为空甚至报 Transport endpoint is not connected。本文用一条症状倒推的路线带你从最直观的现象出发一路追到根因。排障第一步先给故障分段别在错误的楼层找问题k8s-csi-s3 的完整链路可以切成两段故障几乎只落在其中一段上供应段ProvisioningPVC 提交后由csi-provisioner组件调用驱动创建存储桶/PV直到 PVC 变为 Bound。这一段出问题最典型的现象就是PVC 一直 Pending。挂载段MountingPV 已经就绪但 Pod 调度到节点后节点上的csi-s3DaemonSet 负责把桶挂到本地再传入容器。这一段出问题典型现象是Pod 起不来事件里反复出现 FailedMount。所以动手之前我们先用三秒做个分段判断kubectl get pvc kubectl get pv kubectl describe pod your-pod你看到的现象故障落在哪一段该看谁的日志PVC 一直是 Pending且没有任何 PV 被创建供应段provisioner 日志PV 已经 Bound但 Pod 停在 ContainerCreating挂载段csi-s3 驱动日志PVC Bound、Pod 也 Running但写入报错或目录为空两端都可能两边日志 挂载器状态先确认故障楼层再按下面的路线逐层下钻能省下大量盲目试错的时间。供应段排查三步定位 PVC 一直 Pending 的根因第一步用 describe 听集群怎么说PVC 卡住时事件里通常已经写了原因。运行kubectl describe pvc pvc-name你会看到Events一栏。常见的提示有两种一种是明确的权限/参数错误比如AccessDenied、InvalidAccessKeyId、InvalidBucketName这类信息几乎可以直接指向凭证或桶名问题另一种是waiting for a volume to be created之类的空泛状态说明外部 provisioner 压根没有响应需要进入第二步。第二步翻 provisioner 日志区分被拒绝与静默失败外部 provisioner 容器在kube-system命名空间下标签是appcsi-provisioner-s3kubectl logs -l appcsi-provisioner-s3 -c csi-s3日志里出现GRPC error且带具体错误码属于被明确拒绝直接按错误信息修配置即可如果日志一片空白或只有反复的重试、超时则是静默失败重点检查网络连通性、endpoint 是否能从集群内访问以及 RBAC 是否允许 provisioner 读取 Secret。记住一个经验排障时先看日志时间戳与 PVC 创建时间是否吻合避免看了半天旧日志。第三步核对 Secret 与 StorageClass 的凭证链这是 PVC Pending 问题里命中率最高的一处。k8s-csi-s3 在供应阶段会按 StorageClass 里声明的名字去指定命名空间找 Secret任何一环对不上都会表现为创建卷失败。对照检查下面三个点StorageClass 里的 secret 参数例如csi.storage.k8s.io/provisioner-secret-name和...-namespace必须与真实 Secret 完全一致Secret 的命名空间示例默认放在kube-system如果你们改到了别的命名空间StorageClass 里的 namespace 也要同步改Secret 的字段名accessKeyID、secretAccessKey、endpoint三个字段是必需的AWS 还要加region。字段名拼错一个字母比如写成accessKeyId驱动只会拿到空值报错却不一定直接指向它。kubectl get secret csi-s3-secret -n kube-system -o yaml kubectl get sc csi-s3 -o yaml两段输出并排对比一眼就能看出对没对上。挂载段排查Pod 起不来时按顺序检查这三处如果 PV 已经 Bound问题就转移到节点侧。Pod 的事件里通常会刷出FailedMount: MountVolume.SetUp failed接下来按顺序做三件事。第一现场csi-s3 驱动日志节点上的驱动以 DaemonSet 形式运行标签是appcsi-s3kubectl logs -l appcsi-s3 -c csi-s3驱动日志会打出完整的挂载命令和报错比如 bucket 不存在、凭证无效、或者 FUSE 设备不可用。注意GeeseFS 在默认情况下是通过宿主机的 systemd 启动挂载进程的真正的挂载细节可能不在驱动日志里而在 systemd unit 的日志中。若驱动日志只显示starting geesefs using systemd可以再到节点上查对应的geesefs-*.service状态。运行前提特权容器与 MountPropagationk8s-csi-s3 有三条硬性前提缺一条挂载段就会失败而且报错经常很隐晦Kubernetes 版本 1.17集群允许特权容器DaemonSet 需要以 privileged 运行才能做 FUSE 挂载Docker daemon 允许共享挂载systemd 的MountFlagsshared并且功能门控MountPropagation不能被关闭。如果你的 Pod 一直卡在 ContainerCreating 且日志里出现operation not permitted之类的字眼优先怀疑这几项而不是怀疑桶和凭证。落地验证进 Pod 看 FUSE 挂载即使 Pod 起来了也别急着宣布成功。进去看一眼挂载是否真的生效kubectl exec -ti pod-name -- mount | grep fuse你会看到类似fuse.geesefs的挂载记录。试着在挂载目录里 touch 一个文件再读出来能正常读写才算真正打通。如果挂载记录存在但读写报Transport endpoint is not connected这是典型的 FUSE 进程与容器失去联系的症状多半和 GeeseFS 的 systemd 管理方式有关下面挂载器调优一节会讲对策。配置层的隐蔽根因凭证、命名空间与桶的三份一致排查过日志之后很多问题其实沉淀在配置的一致性上。我们常遇到的不是单个字段错而是三份配置互相打架。Secret 字段逐项核对一份完整的 Secret 长这样apiVersion: v1 kind: Secret metadata: namespace: kube-system name: csi-s3-secret stringData: accessKeyID: YOUR_ACCESS_KEY_ID secretAccessKey: YOUR_SECRET_ACCESS_KEY endpoint: https://storage.yandexcloud.net #region: 几点容易被忽略的细节endpoint 格式AWS 要写成https://s3.region.amazonaws.com这种完整形式其他 S3 兼容服务填各自的对象存储地址。漏掉https://前缀或带了多余路径都可能引发连接失败。region 参数AWS 必须显式设置 region其他兼容服务可以留空。如果你在 AWS 上不填 region签名计算会对不上报 403。凭证是否有权限供应段的账户需要建桶权限s3:CreateBucket等如果你只想挂现有桶权限可以收窄但要确保ListBucket、GetObject、PutObject这些基本动作齐全。动态供应与静态供应怎么选k8s-csi-s3 默认是动态供应每个 PV 对应一个全新存储桶删除 PV 时桶也随之删除适合测试和隔离要求高的场景。想让多个卷共享一个预建桶可以在 StorageClass 里声明bucket: your-existing-bucket-name驱动会自动为每个卷在桶内分配独立前缀删除卷时只删前缀不删桶。而静态供应适合挂载已经存在、且不能被驱动删除的桶或桶内前缀。做法是PVC 的storageClassName留空手动创建一个带claimRef的 PersistentVolume把volumeHandle写成bucket/prefix的格式并在volumeAttributes里带上mounter和options。参考仓库deploy/kubernetes/examples/pvc-manual.yaml直接复制改字段即可。 这里有个易错点静态供应的 PVC 与 PV 的claimRef.namespace/name必须匹配否则 PV 永远等不到绑定。挂载器选型与调优别把性能问题当成故障不少用户报挂载异常实际是选错了挂载器导致的兼容性或性能问题。k8s-csi-s3 支持三款后端行为差异很大。挂载器POSIX 兼容性性能画像典型短板GeeseFS默认推荐接近完整大小文件均衡不保存自定义权限与 mtimes3fs接近完整大文件优秀小文件性能差大目录极慢rclone较差小文件尚可大文件差不创建目录对象偶发挂起GeeseFS 生产配置要点官方推荐的 StorageClass 参数里通常带着一段 optionsparameters: mounter: geesefs options: --memory-limit 1000 --dir-mode 0777 --file-mode 0666逐项拆解--memory-limit 1000限制 GeeseFS 的内存缓存上限单位 MB防止大流量读写把节点内存吃满--dir-mode 0777和--file-mode 0666统一目录与文件的权限位避免容器内以非 root 用户运行时碰壁。另一个关键参数是--no-systemd。默认情况下 GeeseFS 借助宿主机 systemd 启动挂载进程这样驱动升级或重启时挂载点不会断开避免Transport endpoint is not connected代价是宿主上会残留 systemd unit。如果你在升级驱动后反复遇到挂载点失联可以考虑改用--no-systemd让进程随容器生命周期管理——但这会牺牲升级时的稳定性取舍前先在测试环境验证。生产环境一般建议保留 systemd 模式。按场景选挂载器大多数生产负载直接选 GeeseFS性能与兼容性最均衡大文件、顺序读写为主比如视频、备份归档s3fs 可以一战临时验证、小文件密集的轻量场景rclone 也能用但别对它要求太高遇到莫名挂起就换回 GeeseFS。环境杂症网络、TLS 与升级带来的隐蔽故障这类问题不属于配置写错而是环境层面症状往往表现为偶发超时或全链路失败的随机组合。网络与端点连通性先确认集群到 S3 端点的通路。从集群内起一个临时 Pod 测连通性kubectl run -it --rm debug --imagebusybox --restartNever -- wget -O- endpoint-url注意很多 S3 兼容服务对不带认证的匿名请求会返回 403这不算网络问题能收到 HTTP 响应就说明链路通了。真正要排查的是超时TCP 层不通检查节点出网规则、防火墙、以及集群里是否有强制代理拦截了对象存储流量。TLS 与自签名证书如果你用的是自建 S3 服务或自签名证书驱动在握手阶段就可能失败。此时优先把 CA 证书注入信任链让驱动用标准 TLS 完成验证而不是直接关掉校验——关校验只建议在纯内网测试环境临时使用。日志里出现certificate signed by unknown authority时走注入 CA 这条路最稳妥。升级兼容性旧版本残留是隐形炸弹从旧版本升级 k8s-csi-s3 时最大的坑不是新代码而是没删干净的旧资源从0.35.5 及更早升级必须删除旧的attacher.yaml里的全部资源从0.40.6 及更早升级必须删除旧provisioner.yaml的资源。升级路径是先删旧资源再重新应用csi-s3.yaml、driver.yaml、provisioner.yaml三份清单。如果升级后挂载行为异常先用kubectl get all -n kube-system | grep csi-s3看看有没有新旧两套组件并存——新旧 provisioner 同时存在时PVC 可能被旧实例抢走症状非常迷惑。全套清单可以从仓库 https://gitcode.com/gh_mirrors/k8s/k8s-csi-s3 克隆后到deploy/kubernetes/目录获取。收尾一张可对照的自查清单最后把全文浓缩成一份可照着执行的清单建议打印或存成笔记下次排障直接过一遍分段判断30 秒kubectl get pvckubectl get pv确认故障在供应段还是挂载段kubectl describe pod看是否有 FailedMount 事件供应段PVC Pendingkubectl describe pvc看事件里的具体错误kubectl logs -l appcsi-provisioner-s3 -c csi-s3确认是被拒绝还是超时Secret 的accessKeyID/secretAccessKey/endpoint/region四字段核对StorageClass 里的 secret 名称与命名空间和真实 Secret 一致账户具备建桶/读写权限bucket 参数是否声明了预建桶挂载段Pod 起不来kubectl logs -l appcsi-s3 -c csi-s3查看驱动报错确认特权容器、MountPropagation、共享挂载三项前提kubectl exec ... -- mount | grep fuse验证挂载生效并实际读写配置与选型动态供应确认桶生命周期符合预期静态供应确认claimRef与volumeHandle正确挂载器选型匹配工作负载特征GeeseFS 配置了合理的--memory-limit升级前清理旧版 attacher/provisioner 残留资源按这条路线走一遍绝大多数 k8s-csi-s3 故障都能在十分钟内定位到根因。如果某一步的现象对不上清单里的任何描述那就回到日志——k8s-csi-s3 的日志向来诚实它只是等着你按顺序读下去。【免费下载链接】k8s-csi-s3GeeseFS-based CSI for mounting S3 buckets as PersistentVolumes项目地址: https://gitcode.com/gh_mirrors/k8s/k8s-csi-s3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考