成功流水线的结果文件去了哪里?
一句话总结
Workflow 成功、中间文件清理、最终结果保留,是三项不同契约。只有分别验证这三项,才能相信 CI 的绿色状态并进入下一项工作。
为什么需要它
夜间数据任务已经成功,但早晨读取结果的团队找不到文件。负责人增加 retry 次数,并提高 container memory。这会有帮助吗?如果不是生产任务失败,而是成功后的 cleanup policy 连最终结果也一并删除,那么这些调整只会让任务更快成功、更可靠地删掉文件。只有先区分失败层次,恢复方向才会正确。
也有相反的事故:结果已经正确生成,temporary file 却持续累积。Workflow 列表显示 Succeeded,因此没有告警。如果负责清理的 ServiceAccount 失去 Kubernetes 权限,业务 container 的 exit code 与 GC error 可以同时呈现不同结果。本模块会使用真实 S3-compatible storage 与真实 container,分别复现这两类事故。
工作原理
路径就是执行边界
producer 在 Pod 内的 /work/temp.txt 写入,executor 将该文件上传到 object storage key,consumer 再从 storage key 下载。local file path 与 S3 key 不是同一概念。两个不同 Pod 在本地使用相同路径可能完全安全,但如果上传到同一 bucket 的相同 key,后一次上传就可能覆盖先前结果。
generateName 会降低 Kubernetes object name 冲突,但不会自动改变 S3 key。若在 output key 中加入 {{workflow.uid}},本次执行的 identifier 就会延伸到存储路径。再把 producer UID 写入文件内容,并由 consumer 与自己的 UID 对照,就能获得比“文件存在”更强的验证,还可以发现误读其他执行留下的正常文件。
本实验的两次正常执行分别使用 runs/<실행 UID>/temp.txt 与 runs/<실행 UID>/final.json。冲突实验则让两次执行共享同一 batch 的 shared path。为避免删除其他实验尝试的 shared file,实验 helper 每次都会区分 batch,只在同一次尝试内部制造预期冲突。
何时删除,保留什么
Workflow 级 spec.artifactGC.strategy 是清理的默认策略。OnWorkflowCompletion 以完成为触发点,OnWorkflowDeletion 则以删除 Workflow 为触发点。单个 output artifact 的 artifactGC.strategy: Never 会把该文件排除在清理对象之外,从而表达“删除中间产物,保留最终结果”的策略。
这里的 Never 并不等于备份。storage 消失或 operator 删除 object 后,文件仍会消失。实验 storage 是 VM 内可随时丢弃的 emptyDir,因此 session 结束后不会保留。生产环境必须另行设计 persistent volume、可恢复 backup、access control、TLS 与 retention period。
读取 Workflow success 与确认文件保留也是两件不同的事。本实验会比较实际读取字节中的 UID 与 hash;判断删除时,则同时确认 authenticated list query 和 404 NoSuchKey。不能把连接失败或 403 解释为“文件已经删除”。
Kubernetes 权限与 storage 权限彼此独立
GC Pod 首先要读取 WorkflowArtifactGCTask,并把处理结果写入 status。所需 Kubernetes 权限包括该 resource 的 list/watch,以及 status subresource 的 patch。之后,删除 S3 object 还需要 storage account 权限。如果已经修复 Kubernetes Role,S3 仍返回 AccessDenied,说明看到的是另一个层次。不要混淆两套权限体系。
应像 kubectl auth can-i patch workflowartifactgctasks --subresource=status 一样,明确指定 subresource。若只传入 workflowartifactgctasks/status 这个 argument,可能会被解释成其他含义,得到错误的 no。不仅要保存命令结果,也要把实际询问的内容纳入证据。
本实验故意让没有权限的 GC 留下 ArtifactGCError 与 forbidden 日志,而业务状态仍可能是 Succeeded。强制删除 error 与 finalizer、把状态变绿,并不等于恢复。应保留原始失败证据,绑定最小 Role,再使用新的 Workflow UID 验证清理与保留是否正常。不要假设先前已经失败的 GC 会自动重新处理。
现场会遇到的情况
在 model training 中,应删除巨大的中间 checkpoint,同时保留最终 model 与 evaluation report。数据转换任务中,同一时段重叠运行的两次 retry 不应删除彼此输入。对于受监管 report,最好把“任务成功”与“结果可以重新读取并验证”作为两项独立指标管理。还要注意,业务失败、清理失败和 retention 配置错误,可能分别由不同负责人处理。
LabHub 的环境验证也曾遇到 service 显示 Ready,正常 S3 upload 却返回 500。原因是小型实验 volume 的容量已经被初始 metadata 占用。如果只验证匿名请求得到 403,就会漏掉该故障。这正是要同时设置允许请求成功的 control group,以及拒绝请求失败的反例的原因。
下一项实验要做什么
首先确认 storage access boundary。把 shared key 修正为 UID-specific key,比较两次执行;然后分别分析遗漏 final retention 与 GC 权限失败。使用最小权限验证新执行,并观察 shared key 冲突和删除时 GC。最后,使用真实 UID 说明:同样的 Succeeded 也可能对应不同的 storage 结果。helper 的完成消息只表示实验执行结束,不等于实验评分通过。