使用 Sidecar 日志时缺少 TaskRun 结果

问题描述

当启用 results-from: sidecar-logs 时,如果 controller 无法读取 Pod 日志,PipelineRun 或 TaskRun 可能无法解析结果。这通常表现为在结果收集期间缺少 Task 结果或 Pipeline 结果。

错误表现

  • PipelineRun 显示结果收集失败:

    Failed to get PipelineResult from TaskRun Results for PipelineRun <pipelinerun-name>: invalid pipelineresults [<result-name>], the referenced results don't exist
  • TaskRun 显示缺少 Task 结果引用:

    Invalid task result reference: Could not find result with name variables for task <task-name>
  • Pod 仍然存在,但无法检索 sidecar 日志:

    unable to retrieve container logs for containerd://<container-id>

根因分析

为了绕过 4 KB 的 termination message 限制,Tekton 可以使用 results-from: sidecar-logs 从 sidecar 日志中读取结果(这是 Tekton v0.61.0 以来的 beta 功能)。此机制依赖 Kubernetes Pod 日志 API 来获取 sidecar 输出。如果日志 API 无法返回数据,Tekton 就无法解析结果,从而导致缺少 TaskResult 或 PipelineResult 引用。

常见触发原因包括:

  • Pod 仍然存在,但 Pod 日志不可用。
  • 在使用基于文件日志的节点上,/var/log/containers 或 /var/log/pods 下的条目被删除,或轮转过于激进。
  • kubelet 或容器运行时暂时不一致,或者发生重启。
  • 在收集结果之前,Pod 或容器的垃圾回收已删除日志。

故障排查

  1. 验证 TektonConfig 和 feature-flags ConfigMap 中是否启用了 results-from: sidecar-logs。
    $ kubectl get tektonconfig config -o yaml
    
    spec:
      pipeline:
        results-from: sidecar-logs
    $ kubectl get configmap feature-flags -n tekton-pipelines -o yaml
    
    data:
      results-from: sidecar-logs
  2. 检查 PipelineRun 和 TaskRun 事件,确认是否存在结果收集失败。
    $ kubectl describe pipelinerun -n ${namespace} ${pipelinerun_name}
    
    Failed to get PipelineResult from TaskRun Results for PipelineRun <pipelinerun-name>: invalid pipelineresults [<result-name>], the referenced results don't exist
    $ kubectl describe taskrun -n ${namespace} ${taskrun_name}
    
    Invalid task result reference: Could not find result with name variables for task <task-name>
  3. 直接检查 sidecar 日志。如果以下命令返回类似下面的错误,说明日志已无法访问:
    $ kubectl logs -n ${namespace} ${taskrun_pod} -c sidecar-tekton-log-results
    
    unable to retrieve container logs for containerd://<container-id>
  4. 检查 Tekton controller 是否已配置 Pod 日志 RBAC。缺少 RBAC 权限也会导致日志检索失败:
    $ kubectl auth can-i get pods/log \
      -n ${namespace} \
      --as=system:serviceaccount:tekton-pipelines:tekton-pipelines-controller
    
    yes
  5. 在节点上验证 Pod 日志文件和符号链接是否仍然存在,并确认 kubelet/containerd 运行正常。

解决方案

推荐的做法是更长时间保留已终止的 Pods,以便在收集结果时仍可访问 sidecar 日志。

  1. 在控制平面上增大 terminated-pod-gc-threshold(例如设置为 1000),并观察行为。
    • 这样做的原因:在繁忙环境中,很多 TaskRun Pod 可能会在同一时间完成。如果已终止 Pod 的数量超过阈值,pod GC 会立即删除它们。一旦 Pod 被删除,sidecar 的日志 API 就不可用,结果也就无法收集。提高阈值可以延迟这段清理窗口,并给 Tekton 更多时间读取 sidecar 日志并提取结果。
    • 如何修改:请参阅 kube-controller-manager flags 中的 --terminated-pod-gc-threshold。
    • 如何评估大小:估算在短时间窗口内(例如 1 分钟)有多少 Pod 进入 Succeeded 或 Failed 状态,然后预留一定余量。可使用平台的工作负载指标或 pipeline 完成数量来近似峰值每分钟完成数,并将阈值设置为高于该峰值。
    • 注意:在托管 Kubernetes 服务(例如 EKS、AKS 或 GKE)中,如果用户无法访问控制平面,则此参数可能无法配置。
  2. 确保节点磁盘空间充足。
    • 这样做的原因:当节点出现磁盘压力时,kubelet 和 containerd 可能会积极清理日志和 Pod 目录。这可能会在 controller 读取之前删除或截断 sidecar 日志。
    • 如何修改:请查看 KubeletConfiguration 中的 kubelet 驱逐配置,并根据容量规划调整磁盘压力阈值。
    • 运维建议:监控平台中的构建节点存储使用情况,并在磁盘压力触发驱逐或日志清理之前提前进行清理。
  3. 确认日志保留设置(例如 kubelet 日志轮转)与预期的 pipeline 持续时间一致。
    • 这样做的原因:如果日志轮转过快或保留的文件过少,即使 Pod 仍然存在,sidecar 输出也可能在结果解析之前消失。
    • 如何修改:检查 KubeletConfiguration 中的 containerLogMaxSize 和 containerLogMaxFiles。
  4. 考虑切回默认的 termination-message 方法。
    • 这样做的原因:termination-message 方法不依赖 Pod 日志,因此可以完全避免上述日志可用性问题。
    • 权衡:此方法对结果大小有 4 KB 限制。如果 Task 结果超过此限制,pipeline 将失败。当需要更大的结果时,这可能会对用户体验产生负面影响。
    • 如何修改:在 TektonConfig 中将 results-from: termination-message 进行设置。请注意,如果 Tekton 是通过 TektonConfig 部署的,直接修改 feature-flags ConfigMap 不会生效,因为 operator 会协调并覆盖 ConfigMap 的更改。

预防措施

  • 监控集群中 Pod 日志 API 的可用性。
  • 保持 Task 结果大小合理,并尽可能尽早收集结果。
  • 将 beta 功能视为在不稳定日志环境中可能比 GA 功能更不稳定,并定期审查其使用情况。

相关内容