这个项目能做什么

pillar-csi 是面向自托管裸金属集群的 Kubernetes CSI 驱动。它把专用存储节点上的本地 ZFS zvol 或 LVM 逻辑卷通过 NVMe-oF/TCP 导出给集群其余部分,直接经由 configfs 写入内核,而不依赖 SSH、Python 守护进程或外部 target CLI。它明确不是分布式文件系统:它不会跨节点复制、条带化或池化存储。 架构由三个工作负载组成。pillar-controller 以 Deployment 形式运行,负责协调集群范围的 Pillar* CRD。pillar-agent 仅以 DaemonSet 形式运行在存储节点上,并负责主机上所有 configfs 写入。pillar-node 运行在每个 worker 上,处理 CSI Node 服务(initiator 连接、mkfs、bind-mount)。两个 DaemonSet 都使用 hostNetwork,以便 NVMe-oF/TCP 数据平面能够绑定到主机网络命名空间。 配置通过 CRD 声明式完成:PillarAgent 定位存储 agent,PillarStore 描述存储池(ZFS 池名、LVM VG、后端配置),PillarProtocol 描述网络协议配置,PillarStorageClass 将池和协议组合成自动生成的 StorageClass。内部 PillarVolumeState CRD 记录持久状态,用于从部分配置失败中恢复以及发布跟踪;控制器根据该记录强制执行 CSI 访问模式互斥。 一个显著的设计元素是陈旧操作防护。每个会更改卷资源的 agent 调用都携带一个防护令牌,该令牌由卷状态 UID(生命周期身份)和通过比较并交换递增的 publicationGeneration 计数器组成。agent 在存储节点本地磁盘的 /var/lib/pillar-csi/agent/generations/ 下为每个卷保留持久标记,该目录以 hostPath 挂载,因此标记在重启和重新启动后仍然存在。早于该标记的请求、来自已结束或已被替换生命周期的请求,或不携带令牌的请求,都会以 FAILED_PRECONDITION 被拒绝。README 指出一个升级注意事项:升级前请分离所有卷,因为早期版本不记录发布、生命周期或代际,并且不提供迁移垫片。 节点 stage 状态记录在 worker 上的 /var/lib/pillar-csi/node/ 下,通过临时文件、sync 和 rename 原子写入。NodeUnstageVolume 会读回该记录,因为 CO 在 unstage 时既不发送卷能力也不发送卷上下文。卸载决策委托给 mounter 的幂等 Unmount,将损坏挂载探测错误(EIO、ENOTCONN、ESTALE、EACCES)视为仍处于挂载状态,以便 kubelet 能够回收文件系统进入内核关闭状态的 Pod。 支持矩阵:已发布基于 NVMe-oF/TCP 的 ZFS zvol 和 LVM LV;iSCSI 已设计但尚未发布;用于 ZFS 数据集的 NFS 已设计但尚未发布。CSI 操作包括 CreateVolume、DeleteVolume、ControllerPublish/Unpublish、ControllerExpandVolume、NodeStage/Unstage、NodePublish/Unpublish、NodeExpandVolume、NodeGetVolumeStats、ValidateVolumeCapabilities 和 GetCapacity。访问模式为 ReadWriteOnce、ReadWriteOncePod 和 ReadOnlyMany;卷模式为 Filesystem(ext4/xfs)和 Block。 安装通过 Helm 完成。控制器与 agent 之间的 mTLS 为可选启用(cert-manager 模式或提供的 Secret 模式);默认是明文 gRPC。需要 Kubernetes 1.24 或更新版本。存储节点需要 nvmet 和 nvmet_tcp 内核模块;worker 节点需要 nvme_tcp 和 nvme_fabrics;init 容器在启动时运行 modprobe。 README 包含带有 CRD YAML 示例的快速入门、通过标准 kubectl describe 和日志进行故障排除,以及针对卡在 ExportSpecMissing 的旧卷的详细恢复流程,强调由操作员对 bindAddress、port 和 aclEnabled 做出明确决策,而不是根据运行时观察进行猜测。