首页
/ Kubernetes 集群 e2e 测试日志采集机制解析:cluster/log-dump 的使用、原理与迁移指南

Kubernetes 集群 e2e 测试日志采集机制解析:cluster/log-dump 的使用、原理与迁移指南

2026-09-06 18:53:30作者:裘旻烁

本篇技术指南聚焦 Kubernetes 官方仓库 cluster/log-dump 目录下的集群日志采集机制(log-dump.shlogexporter DaemonSet),说明它如何在大规模端到端(e2e)测试失败时批量抓取 master 与 node 日志、如何通过 GCS 直传与 SSH 兜底双通道工作,以及当前仓库为何将其标记为 deprecated、如何迁移到 kubernetes/test-infra 的新机制。读完你将掌握该目录中全部脚本/模板的调用参数、可配置环境变量,以及面向自有 provider 的扩展点与迁移步骤。

一、目录定位:cluster/log-dump 是做什么的

在 Kubernetes 源码仓库中,cluster/log-dump 目录只包含四个文件:

  • README.md:现状说明与迁移指引(本文主体依据);
  • log-dump.sh:共 716 行的 Bash 脚本,是日志采集的实际执行器;
  • logexporter-daemonset.yaml:用于在集群内以 DaemonSet 方式运行 logexporter 的模板;
  • OWNERS:目录维护者名单。

其职责正如 log-dump.sh 开头的注释所述:"Call this to dump all master and node logs into the folder specified in $1 (defaults to _artifacts). Only works if the provider supports SSH." 也就是在 CI/e2e 环境里,当集群出现异常时,把控制面组件日志、节点日志、systemd 服务日志乃至串口输出统一收集到本地(或 GCS),供测试框架作为 artifact 归档、定位故障。脚本作者也遗留了 TODO(log-dump.sh):理想情况下它应该归属 test/e2e,说明它本质上是为测试配套的基础设施脚本,而非集群运行时组件。

1.1 已被官方标记为 deprecated

README 的第一句话就给出明确结论:这个目录已被弃用(deprecated)。日志采集工具(log dumping utility)已从 kubernetes/kubernetes 仓库移植到了 kubernetes/test-infra 仓库的 logexporter/cluster 位置。因此:

  • 如果你需要改动 log-dump.sh 里的逻辑,官方要求先把自己的测试任务迁移到新机制,再谈修改;
  • 新发布的 kubekins-e2e 镜像中已经内置了新版 log-dump.sh
  • 想让测试任务直接使用镜像内置脚本,只需在测试 Job 中加入环境变量 USE_TEST_INFRA_LOG_DUMPING 并设为 true

需要强调:本文对旧机制的分析仍以当前仓库 cluster/log-dump/log-dump.sh 的实际实现为准,它与新机制在**采集目标、双通道设计(SSH / DaemonSet)**上高度一致,理解它有助于你更快迁移与二次开发。

二、旧机制双通道设计:SSH 直采与 logexporter DaemonSet

从源码结构看,这套机制存在两条并行的日志采集路径,二者由 main() 依据是否有 GCS 目标目录来决定:

main() 调用序列:
1. print-deprecation-note       —— 打印弃用提示
2. setup                        —— 探测项目、加载 kube-util.sh 等依赖
3. dump_masters                 —— 通过 SSH 把 master 日志抓到本地
4. 若 DUMP_ONLY_MASTER_LOGS=true,则跳过节点采集直接返回
5. 若设置了 gcs_artifacts_dir  → dump_nodes_with_logexporter(DaemonSet 上传 GCS)
   否则                        → dump_nodes(SSH 抓回本地)
6. detect_node_failures         —— 读取 GCE 实例组活动日志

脚本入口处(log-dump.sh)定义了三个位置参数:

readonly report_dir="${1:-_artifacts}"            # 本地归档目录,默认 _artifacts
readonly gcs_artifacts_dir="${2:-}"               # GCS 目录,非空则启用 logexporter 通道
readonly logexporter_namespace="${3:-logexporter}" # logexporter 运行命名空间,默认 logexporter

典型调用方式:

# 方式一:仅 SSH 抓取到本地 ./_artifacts
cluster/log-dump/log-dump.sh

# 方式二:指定本地目录
cluster/log-dump/log-dump.sh /tmp/my_artifacts

# 方式三:节点日志经 logexporter 直传 GCS,同时 master 日志仍抓本地
cluster/log-dump/log-dump.sh /tmp/my_artifacts gs://my-bucket/ci-logs/run-123

两条通道的取舍很清晰:master 数量少、日志量大且高度关键,始终走 SSH 本地抓取;node 数量可能成百上千,逐台 SSH 会耗尽文件描述符、耗时过长,因此优先以 DaemonSet 在每台节点上就近打包并直传 GCS,SSH 只作为兜底与补漏手段。

2.1 通道 A:SSH 抓取(dump_masters / dump_nodes)

dump_masterslog-dump.sh)与 dump_nodeslog-dump.sh)采用后台进程池并发执行 save-logs,并用 max_dump_processes=25log-dump.sh)限制同时在跑的 SSH 连接数,避免大集群下耗尽文件描述符。

save-logslog-dump.sh)对每台节点做的事依次为:

  1. 探测 journalctl:若节点可用 systemd journal,则导出安装/配置服务日志与内核日志:
    • master:kube-master-installation.servicekube-master-configuration.service
    • node:kube-node-installation.servicekube-node-configuration.service
    • 公共项:journalctl -k(内核)、-u ${svc}.service(遍历 systemd 服务列表)、以及可选的全量 systemd.log(当 LOG_DUMP_SYSTEMD_JOURNAL=true)。
  2. 不适用 journalctl 的旧式节点:改抓 kern.logdocker/log、supervisord 下的一组日志。
  3. 记录镜像清单ctr -n k8s.io images lsdocker images --all 分别输出 containerd / docker 拉取镜像来源到 images-containerd.logimages-docker.log
  4. 尝试导出覆盖率:若节点存在 /var/log/kubelet.cov,说明二进制开启了覆盖率插桩,则进入 docker 容器把 kube-apiserver.covkube-scheduler.covkube-controller-manager.cov(master)或 kube-proxy.cov(node)读出。
  5. chmod -R a+r /var/log 之后调用 copy-logs-from-node 批量拉取文件。

copy-logs-from-nodelog-dump.sh)在文件名后追加 * 以一并抓取被 logrotate 轮转的旧日志(大集群、长时运行场景下普遍存在),前缀 /var/log/ 后用 scp/gcloud 的 brace 展开形式批量下载;对 gce/gke 还会额外抓取串口输出写入 serial-1.log

dump_nodes 还额外支持两类特殊节点:

  • Windows 节点save-logs-windowslog-dump.sh)导出 Docker 事件日志与镜像列表,GKE 上会优先调用 GCP diagnostics 工具导出整机日志包;
  • Kubemark hollow 节点:当 ENABLE_HOLLOW_NODE_LOGS=true 时追加 kubelet-hollow-node-*.logkubeproxy-hollow-node-*.lognpd-hollow-node-*.loglog-dump.sh)。

2.2 通道 B:logexporter DaemonSet 直传 GCS

当传入 gcs_artifacts_dir 后,dump_nodes_with_logexporterlog-dump.sh)接管节点采集。它会:

  1. logexporter-daemonset.yaml 模板拷贝到临时目录;
  2. sed 逐个替换模板占位符(log-dump.sh):
    • {{.NodeSelector}}topology.kubernetes.io/zone: ${ZONE}(除非显式禁用);
    • {{.LogexporterNamespace}}{{.ServiceAccountCredentials}}(base64 后的 GCP 服务账号)、{{.CloudProvider}}{{.GCSPath}}{{.EnableHollowNodeLogs}}{{.DumpSystemdJournal}}{{.ExtraLogFiles}}{{.ExtraSystemdServices}}
  3. 通过 cluster/kubectl.sh 下发资源;创建失败则删除命名空间并回退到对全部节点走 SSH 采集
  4. 以每 15 秒一次的频率轮询 GCS 上各节点 logexporter 写入的 marker 文件(路径 <gcs>/logexported-nodes-registry),最长等待 90 + NUM_NODES/3 秒(log-dump.sh);
  5. 到达超时或全部成功后,把每个 logexporter Pod 自身的日志(kubectl logs)也抓到本地,便于排查采集过程本身的故障;
  6. 对 marker 缺失的失败节点(NON_LOGEXPORTED_NODES)再次回退 SSH 采集;当成功节点比例低于 LOG_DUMP_EXPECTED_SUCCESS_PERCENTAGE(默认 0)时置失败标志并最终以非 0 退出。

这里的关键设计是:DaemonSet 中的 Pod 会 "AlwaysRestart",因此模板要求 logexporter 长时间 sleep(24h)不退出(见 logexporter-daemonset.yaml 注释),工作完成后由调用方自行删除 DaemonSet。

三、logexporter-daemonset.yaml 模板逐段解读

logexporter-daemonset.yaml 是一个典型的 "作业模板",共 81 行,由三个对象构成(全部集中在 {{.LogexporterNamespace}} 命名空间内):

对象 要点 说明
Namespace {{.LogexporterNamespace}} 隔离 logexporter 自身资源,事后整体删除
Secret google-service-account(类型 Opaque 挂载 service-account.json,供 logexporter 向 GCS 鉴权上传
DaemonSet logexporterapps/v1matchLabels: app: logexporter 每节点一 Pod,就近采集并上传

容器的关键配置:

  • 镜像:gcr.io/k8s-testimages/logexporter:v20200401-c3269f485(历史 pin 版本);
  • 通过 fieldRef 注入 spec.nodeNameNODE_NAME,命令行以 --node-name=$(NODE_NAME) 传给二进制,确保每 Pod 只处理所在节点;
  • 命令行携带 --cloud-provider--gcs-path--gcloud-auth-file-path=/etc/service-account/service-account.json--enable-hollow-node-logs--dump-systemd-journal--extra-log-files--extra-systemd-services,与脚本侧的环境变量一一对应;
  • --sleep-duration=24h:配合 AlwaysRestart 策略,防止任务未完成就被重启;
  • 只读挂载三个卷:service-account Secret(/etc/service-account)、宿主机 /var/log/var/log)、宿主机 /etc/workspace/etc);
  • 资源请求极小:cpu: 10m / memory: 10Mi,尽量不干扰被测集群;
  • nodeSelector 保留为占位符 {{.NodeSelector}},由脚本填入 zone 标签,可让 DaemonSet 只覆盖目标可用区的节点。

模板头部注释(logexporter-daemonset.yaml)同时是一份使用须知:由于 DaemonSet Pod 会因 AlwaysRestart 反复拉起,必须由使用者自行检测"工作是否完成"并删除 DaemonSet,或设定外部超时,脚本侧正是靠 GCS marker 轮询完成这一职责。

四、可配置项与环境变量汇总

结合 log-dump.shcluster/gce/config-default.shcluster/gce/config-test.sh,可被外部覆盖的变量如下:

变量 默认值 作用
位置参数 1 _artifacts 本地归档目录
位置参数 2 非空则启用 logexporter GCS 直传通道
位置参数 3 logexporter logexporter 资源所在命名空间
LOG_DUMP_SYSTEMD_SERVICES containerd 追加采集的 systemd 服务;GCE 默认配置(config-default/config-test)均透传此变量
LOG_DUMP_EXTRA_FILES 追加采集的额外日志文件名
LOG_DUMP_SAVE_SERVICES 追加采集的额外 systemd 服务
LOG_DUMP_SYSTEMD_JOURNAL false 为 true 时额外导出全量 journal 至 systemd.log
LOG_DUMP_SSH_KEY / LOG_DUMP_SSH_USER 使用自定义实例列表(非 gce/aws)时 SSH 所需凭据,缺失则退出
LOG_DUMP_SAVE_LOGS 自定义实例列表模式下追加采集的日志文件
LOG_DUMP_SSH_TIMEOUT_SECONDS 对整批 SSH 采集的尽力而为式总超时,超时即停止新起任务
LOG_DUMP_EXPECTED_SUCCESS_PERCENTAGE 0 logexporter 成功节点占比低于该值时以非 0 退出
DUMP_ONLY_MASTER_LOGS true 时跳过全部节点采集
ENABLE_HOLLOW_NODE_LOGS true 时采集 Kubemark hollow 节点日志
LOGDUMP_ONLY_N_RANDOM_NODES 只随机抽取 N 台 Linux 节点抓日志(大集群省时)
GOOGLE_APPLICATION_CREDENTIALS logexporter 上传 GCS 的服务账号 JSON 路径
KUBERNETES_PROVIDER 由 cluster 脚本设置 决定走哪条采集路径与哪些 provider 专属日志
USE_TEST_INFRA_LOG_DUMPING(新机制) false true 让 kubekins-e2e 作业采用 test-infra 新版脚本

provider 能力矩阵(来自 log-dump.sh)也非常重要:

  • master 支持 SSH 的 provider:gceaws
  • node 支持 SSH 的 provider:gcegkeaws
  • 支持 gcloud 命令(含串口输出、Windows 采集)的 provider:gcegke
  • 其余 provider 必须实现自定义扩展(见下节),否则会打印 "Unknown cloud-provider" 并跳过。

默认按角色采集的日志文件清单(log-dump.sh)包括:master 侧 kube-apiserver.logkube-apiserver-audit.logkube-scheduler.logkube-controller-manager.logcloud-controller-manager.logetcd.logetcd-events.logglbc.logcluster-autoscaler.logkube-addon-manager.logkonnectivity-server.logfluentd.log 等;node 侧 kube-proxy.logcontainers/konnectivity-agent-*.logkubelet.cov 等;此外 aws 追加 cloud-init-output.log,gce/gke 追加 startupscript.log

五、面向自定义部署的扩展点

脚本在 log-dump.sh 显式设计了扩展钩子:若当前 shell 环境里定义了名为 log_dump_custom_get_instances 的 Bash 函数,脚本就进入自定义实例列表模式。该函数需接受一个角色参数(masternode),并在标准输出逐行返回主机名:

# 在调用脚本前于当前 shell 定义,示例骨架(伪代码)
log_dump_custom_get_instances() {
  case "$1" in
    master) your_tool list masters ;;
    node)   your_tool list nodes   ;;
  esac
}
export -f log_dump_custom_get_instances

进入该模式后,setuplog-dump.sh)不再要求 KUBE_ROOT/cluster 下的 GCE/GKE 探测能力:若是 GKE 会额外加载 cluster/gce/util.sh 复用 ssh-to-node;否则要求显式提供 LOG_DUMP_SSH_KEYLOG_DUMP_SSH_USERdump_mastersdump_nodesdump_nodes_with_logexporter 三处都会优先从该函数读取实例清单,从而实现把日志采集复用到自建集群或云厂商上。

另一个隐藏扩展点位于 detect_node_failureslog-dump.sh):对 gce/gke,它会按实例组读取 GCP activity log 中的 compute.instances.hostErrorcompute.instances.automaticRestart 事件,以表格形式把节点故障(含自动重启)一并输出到归档,便于区分"集群故障"与"底层宿主机故障"。

六、向 test-infra 新机制的迁移路径(README 核心指引)

回到 cluster/log-dump/README.md,当前仓库对使用者的正式建议可以归纳为三步,这也是迁移到新机制的标准动作:

  1. 把测试 Job 切换到新版机制:不要在本仓库内继续维护 log-dump.sh。新版 kubekins-e2e 镜像发布时已自动附带 test-infra 版 log-dump.sh;要让 Job 使用它,只需在测试 Job 中设置环境变量:

    USE_TEST_INFRA_LOG_DUMPING=true
    

    随后旧的 GCE/GKE 集群日志采集即可由 kubekins-e2e 内的新脚本接管,无需再引用本仓库 cluster/log-dump

  2. 确认你的 provider 属于受支持集合:目前(README 写作时点)新 log-dump 机制只支持 GCE 与 GKE 两种 provider。如果你的测试仍使用这两者,迁移后无需额外开发。

  3. 为非 GCE/GKE provider 做两件事

    • 在 test-infra 的 kubetest 中修改 logDumpPath 函数,加入对你所用 provider 的处理逻辑(决定日志归档路径与触发方式);
    • 相应调整 test-infra 版 log-dump.sh(对应本仓库旧版位于 cluster/log-dump/log-dump.sh)以适配你的环境。

之所以要求"先迁移再修改",是因为新版脚本在 kubekins-e2e 镜像内持续演进、随镜像发布自动生效,新功能与修复只会落在 test-infra 一侧;继续在本仓库改旧版会导致两份实现分叉、修复无法回流。从源码也可观察到这种"分叉管理"痕迹:旧版脚本每次运行都会先打印 100 个 - 组成的弃用横幅(print-deprecation-notelog-dump.sh),提醒尽快迁移。

七、小结

cluster/log-dump 虽然已进入弃用周期,但其设计骨架——master 日志走 SSH、node 日志经 logexporter DaemonSet 直传 GCS、失败节点自动回退 SSH、O(#nodes) 的 marker 轮询核对——为大规模 e2e 集群的故障现场保全提供了完整参考实现。无论你是要在旧集群上临时抓取现场日志,还是要为自己的 provider 二次开发采集器,都可以从 log-dump.shlogexporter-daemonset.yaml 中直接借鉴:并发上限 max_dump_processes* 通配抓取轮转日志、GCS marker 注册表、log_dump_custom_get_instances 自定义钩子等设计,至今仍是可复用的工程范本;而生产环境的长期归宿,则是随 USE_TEST_INFRA_LOG_DUMPING=true 接入的 test-infra 新版机制。

登录后查看全文
热门项目推荐
相关项目推荐