hrodrig/groot

GitHub: hrodrig/groot

GROOT 是一个用 Go 编写的 Kubernetes 集群诊断 CLI 工具,通过并发执行 kubectl 命令,一键将节点、事件、Pod 日志等诊断信息收集并打包为归档文件,适用于故障排查与应急响应场景。

Stars: 1 | Forks: 0

# GROOT — Kubernetes 诊断 CLI **☸** _将集群诊断信息收集到一个归档文件中_ [![Release](https://img.shields.io/github/v/release/hrodrig/groot?display_name=tag&label=release&logo=github)](https://github.com/hrodrig/groot/releases) [![Version](https://img.shields.io/github/v/tag/hrodrig/groot?label=version&logo=github)](https://github.com/hrodrig/groot/releases) [![Go](https://img.shields.io/badge/Go-1.26-00ADD8?logo=go)](https://go.dev/) [![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE) [![pkg.go.dev](https://pkg.go.dev/badge/github.com/hrodrig/groot)](https://pkg.go.dev/github.com/hrodrig/groot) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/fa24bf39be040205.svg)](https://github.com/hrodrig/groot/actions/workflows/ci.yml) [![Codecov](https://codecov.io/gh/hrodrig/groot/branch/main/graph/badge.svg)](https://codecov.io/gh/hrodrig/groot) [![Go Report Card](https://goreportcard.com/badge/github.com/hrodrig/groot)](https://goreportcard.com/report/github.com/hrodrig/groot) [![Article on DEV](https://img.shields.io/badge/dev.to-article-0A0A0A?logo=devdotto&logoColor=white)](https://dev.to/hrodrig/groot-one-archive-for-cluster-diagnostics-2d76) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/hrodrig/groot/) **仓库:** [github.com/hrodrig/groot](https://github.com/hrodrig/groot) · **发布版:** [GitHub Releases](https://github.com/hrodrig/groot/releases) · **文章:** [DEV 上的 GROOT — 用于集群诊断的单个归档文件](https://dev.to/hrodrig/groot-one-archive-for-cluster-diagnostics-2d76) *徽章:* **release** = 最新的 [GitHub *Release*](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases)(已发布的说明/资产)。**version** = 仓库中最新的 **git tag**。如果推送了标签但尚未发布 Release,它们可能会有所不同——该标签的安装资产仍位于 [tags](https://github.com/hrodrig/groot/tags) / 发布页面上。默认分支中的 `VERSION` 文件是下一个发布版本号的可靠来源。**Codecov** 显示了来自 **`main`** 分支 CI 上传的合并测试覆盖率(参见 [Codecov](https://codecov.io/gh/hrodrig/groot))。**dev.to** 链接到 [DEV Community](https://dev.to/) 上的配套演练文章。**Ask DeepWiki** 打开了此仓库的 [DeepWiki](https://deepwiki.com/hrodrig/groot/) 文档索引。

GROOT — Kubernetes diagnostics CLI

GROOT 是一个 Go CLI(使用 Cobra + Viper),可收集广泛的 Kubernetes 诊断信息,包括 worker/节点详细信息、控制平面日志、namespace 资源、pod 日志和事件。 ## 目录 - [功能](#features) - [要求](#requirements) - [安装或更新](#install-or-update) - [快速开始](#quick-start) - [首次运行](#first-run) - [使用示例](#usage-examples) - [配置](#config) - [配置参考(所有键)](#configuration-reference-all-keys) - [解析与优先级](#resolution-and-precedence) - [输出命名](#output-naming) - [控制台输出模式](#console-output-modes) - [典型收集数据](#typical-collected-data) - [通知](#notifications) - [无特权容器](#rootless-container) - [安全说明](#security-note) - [参与贡献](#get-involved) [↑ 返回顶部](#readme-top) ## 功能 - 使用 Cobra CLI 的 `collect` 命令 - Viper YAML 配置 + 环境变量覆盖 - 并发执行 `kubectl` 以加快收集速度 - 面向 worker/节点和控制平面的日志收集 - 输出文件夹 + `.tar.gz` 归档生成 - 可选通知(Slack、Discord、Teams、PagerDuty、Telegram、通用 webhook) - 支持无特权容器镜像 [↑ 返回顶部](#readme-top) ## 要求 - `kubectl` 已配置并连接到目标集群 - 具备读取日志/资源的 RBAC 权限 - 如果您[从源码构建](#quick-start)(`make build`)或使用 [`go install`](#install-with-go) 来获取 CLI,则需要 **Go 1.26+** [↑ 返回顶部](#readme-top) ## 安装或更新 预构建的 **`.deb`**、**`.rpm`**、**`.tar.gz`**(以及 Windows 上的 **`.zip`**)可在 **[GitHub Releases](https://github.com/hrodrig/groot/releases)** 和 **[最新发布版](https://github.com/hrodrig/groot/releases/latest)** 中找到。本 README 顶部的 **release** 徽章一目了然地显示了当前标签。 **为什么不为每个文件提供一个单一的 `latest` URL?** GitHub 的 `…/releases/latest/download/` 只有在**资产文件名在每次发布时完全相同**的情况下才有效。GoReleaser 会在文件名中加上**不带 `v` 的 semver 版本号**(例如 **`groot_0.1.10_amd64.deb`**),而下载 URL 路径使用的是**带 `v` 的 git tag**(`…/download/v0.1.10/…`)。不要在文件名中使用带有 `TAG=v0.1.10` 的 `groot_${TAG}_…`——这会导致 **404**。可选方案:**从发布页面挑选名称**、使用**下面的代码片段**,或者使用**徽章**。 ### 安装最新的 `.deb` (Debian / Ubuntu, `amd64`) ``` # 最新发布的 release tag (python3 或 jq)。Asset 基名没有 "v" — 请参阅下文的 VER。 TAG="$(curl -fsSL https://api.github.com/repos/hrodrig/groot/releases/latest | python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"])')" # 备选方案:TAG="$(curl -fsSL https://api.github.com/repos/hrodrig/groot/releases/latest | jq -r .tag_name)" [ -n "$TAG" ] || { echo "Could not resolve tag (empty). Install python3 or jq, or set TAG manually from the Releases page." >&2; exit 1; } VER="${TAG#v}" # e.g. v0.1.10 -> 0.1.10 (matches GoReleaser .deb filename) DEB="groot_${VER}_amd64.deb" URL="https://github.com/hrodrig/groot/releases/download/${TAG}/${DEB}" TMP="/tmp/${DEB}" # 下载到 /tmp 以便用户 _apt 可以读取该文件(当 $HOME 为 700 模式时,apt 通常无法读取 ~/.deb)。 if ! curl -fsSL "$URL" -o "$TMP"; then echo "Download failed (curl exit $?). Check URL: $URL" >&2 exit 1 fi if [ ! -f "$TMP" ]; then echo "Expected $TMP after download — not found." >&2 exit 1 fi sudo apt install "$TMP" ``` 将代码块**整体粘贴**,或使用 `&&` 链接,这样在 **`curl`** 失败后 **`apt` 就不会运行**。**`curl -f`** 在遇到 HTTP 错误(如 404 等)时会以非零状态退出。 **`apt` + `_apt` / `$HOME` 下的“Permission denied”:** 如果您将 `.deb` 文件通过 `curl` 下载到 **`~`** 目录并运行 `sudo apt install ./groot_….deb`,Debian/Ubuntu 可能会警告 **`_apt` 无法读取该文件**(主目录不是全局可执行的)。请像上面那样使用 **`/tmp`**,或者使用 `sudo cp "$DEB" /tmp/` 然后 `sudo apt install "/tmp/$DEB"`。 **`groot_v0.1.6_amd64.deb` 出现 404:** GitHub 上的文件名是 **`groot_0.1.6_amd64.deb`**(基本名称中没有 `v`)。**空的 `TAG`:** 如果 `jq`/`python3` 执行失败,您将得到 `.../download//groot__amd64.deb` 并且 `apt` 会得到 **`./groot__amd64.deb`**。 `groot` 将被安装到 `/usr/bin`。该软件包会在 **`/etc/groot/groot.yml.sample`** 放置一个**示例**(来自仓库中的 `configs/groot.yml.sample`)。如果没有指定 **`--config`**,查找顺序依次是 **`./groot.yml`**、**`~/.groot/groot.yml`**、**`/etc/groot/groot.yml`**、**`/etc/groot/groot.yml.sample`**。您可以在 **`~/.groot/`** 下保留一份用户专属的副本,使用 **`sudo cp /etc/groot/groot.yml.sample /etc/groot/groot.yml`** 设置全局配置,或者使用 **`--config /path/to/file.yaml`**。在 ARM64 架构上,请在下载文件名中使用 `arm64`。 ### 固定标签示例(如果您愿意,可以从发布页面复制) | 格式 | 示例(URL 路径中的标签为 **`v0.1.10`**;构件基本名称使用不带 `v` 的 **`0.1.10`**) | |--------|------------------------------------------------------------------| | **`.deb`** | `curl -fsSL -o /tmp/groot_0.1.10_amd64.deb https://github.com/hrodrig/groot/releases/download/v0.1.10/groot_0.1.10_amd64.deb` 然后 `sudo apt install /tmp/groot_0.1.10_amd64.deb`(使用 `/tmp` 以便在 `$HOME` 为 `700` 权限时 `_apt` 能够读取该文件) | | **`.rpm`** | `curl -fsSLO https://github.com/hrodrig/groot/releases/download/v0.1.10/groot_0.1.10_amd64.rpm` 然后 `sudo rpm -Uvh groot_0.1.10_amd64.rpm` 或 `sudo dnf install ./groot_0.1.10_amd64.rpm` | | **`.tar.gz`** | `curl -fsSLO https://github.com/hrodrig/groot/releases/download/v0.1.10/groot_0.1.10_linux_amd64.tar.gz` 然后 `tar xzf groot_0.1.10_linux_amd64.tar.gz` 并在解压后的目录中运行 `./groot` | **更新:** 下载新版本并再次运行相同的安装命令(对于 `.deb` 使用 `rpm -Uvh`、`apt install`,或者替换 tarball 目录树)。 **Windows:** 使用与您的架构对应的 **`.zip`** 资产,解压后,在 `kubectl` 可用的地方运行 `groot.exe`。 接着[配置](#first-run)并运行 `groot collect`(或先运行 `groot --print-sample-config > groot.yml`)。 [↑ 返回顶部](#readme-top) ## 快速开始 从克隆此仓库开始构建: ``` make build ./bin/groot --print-sample-config > groot.yml # 在收集前,编辑 groot.yml:将示例值替换为你的 cluster 设置(namespaces、targets、 # kubeconfig、输出路径、可选的 notify webhooks/tokens)。 ./bin/groot collect ``` 如果您是从**发布包**安装的,请在您的 `PATH` 中使用 `groot`,而不是 `./bin/groot`。 ### 使用 Go 安装 在任何装有 Go **1.26+** 的机器上(安装到 `$(go env GOPATH)/bin`;确保该目录在您的 `PATH` 中): ``` go install github.com/hrodrig/groot/cmd/groot@latest ``` 如果您想要固定版本(例如 `@v0.1.10`),请使用**发布标签**代替 `@latest`。模块文档:[pkg.go.dev/github.com/hrodrig/groot](https://pkg.go.dev/github.com/hrodrig/groot)。 有用的运行时标志(全局或与 `collect` 一起使用): - `--version` 打印版本、commit、分支和构建日期 - `--test-connection` 验证 Kubernetes 连接并退出 - `--verbose` 将每个执行的命令显示为 `CMD`,以及 `OK`/`ERR` 结果 - `--quiet` 抑制正常的**控制台**输出(INFO/WARN/CMD/OK)并仅打印错误;**通知集成仍会运行**(Slack、Discord、Teams、PagerDuty、Telegram、通用),除非您在配置中禁用它们或使用 `--no-notify` - `--no-notify` 在成功收集后跳过所有通知(当您在 cron 中只想要归档文件时很有用)。与环境变量 `GROOT_NO_NOTIFY=1`(或 `true` / `yes`,不区分大小写)效果相同 - `--no-color` 禁用 ANSI 颜色 - `--message "label text"` 将清理后的后缀附加到归档文件和与捕获相关的输出名称中 - `--kubeconfig /path/to/config` 覆盖来自文件/环境变量的 kubeconfig - **仅限 `collect`:** `--since` 将 **pod** 日志收集限制为比指定持续时间更新的行(`kubectl logs --since`)。**纯数字**将被视为**小时**(例如 `--since=24` → `24h`)。其他形式遵循 Go 持续时间格式(`24h`、`45m`、`90s`)。传递时将覆盖配置中的 `collection.pod_logs_since`。 [↑ 返回顶部](#readme-top) ## 首次运行 如果您还没有配置文件,可以打印示例并保存: ``` ./bin/groot --print-sample-config > groot.yml ``` 生成的文件**只是一个模板**。打开 `groot.yml` 并根据您的环境设置**属于您自己的**值——例如 `kubeconfig`(如果不使用默认值)、`collection.namespaces`、`collection.targets` 下的工作负载(deployments、StatefulSets、DaemonSets、Helm releases)、`output_dir` / `file_prefix` 以及任何 `notify.*` 的 URL 或密钥。在您修改之前,示例中的名称和已禁用的通知块不会与真实的集群匹配。 然后运行: ``` ./bin/groot collect ``` 默认的配置发现顺序(当未提供 `--config` 时)。**第一个存在的文件**优先;如果都不存在,则应用内置默认值,然后在适用的情况下由 `GROOT_*` 环境变量进行覆盖: 1. `./groot.yml` 2. `~/.groot/groot.yml` 3. `/etc/groot/groot.yml` 4. `//groot/groot.yml.sample`(来自 `.deb` / `.rpm` 包的示例) 您始终可以使用 `--config` 覆盖文件发现(参见[使用示例](#usage-examples))。 [↑ 返回顶部](#readme-top) ## 使用示例 下面的路径是 `make build` 之后的 `./bin/groot`;如果您是从 [Releases](#install-or-update) 或 `make install` 安装的,请以同样的方式使用您 `PATH` 中的 `groot`(例如 `groot collect ...`)。 ### 使用特定的配置文件 **`./`**、**`~/.groot/`** 和 **`/etc/groot/`** 下的路径(`groot.yml`、`groot.yml.sample`)会被自动发现(参见[首次运行](#first-run))。任何其他路径**必须**显式传递: ``` ./bin/groot collect --config /path/to/my-groot.yml ./bin/groot collect --config ./groot-mi-test.yml ``` 从仓库根目录,编辑您的副本之后: ``` ./bin/groot collect --config groot-mi-test.yml ``` ### 检查 Kubernetes 访问和配置(不收集) ``` ./bin/groot --config ./groot-mi-test.yml --test-connection ./bin/groot collect --config ./groot-mi-test.yml --test-connection ``` ### Cron 任务:安静的控制台,无外部通知 仅控制台(如果在 YAML 中启用,Slack/Discord 等仍会运行): ``` ./bin/groot collect --config /path/to/groot.yml --quiet ``` 为此运行跳过**所有**通知通道(仍会创建归档);与环境变量 `GROOT_NO_NOTIFY=1` / `true` / `yes` 效果相同: ``` ./bin/groot collect --config /path/to/groot.yml --quiet --no-notify 0 * * * * GROOT_NO_NOTIFY=1 /usr/local/bin/groot collect --config /home/you/.groot/prod.yml --quiet ``` ### 自定义捕获标签 (`--message`) ``` ./bin/groot collect --config groot.yml --message "staging-network-audit-2026-04-28" ``` ### Pod 日志:过去 N 小时 (`--since`) 与 YAML 中的 `collection.pod_logs_since` 相同;**纯数字 = 小时**(此处为过去 24 小时的 pod 日志): ``` ./bin/groot collect --config groot.yml --since=24 ``` **空的 `*.log` 文件是正常的**,当您缩小时间窗口时:`kubectl logs --since=…` 只返回**比该持续时间新**的行。如果一个 pod 在该窗口期间没有输出,Groot 仍然会写入文件(通常是 **0 字节**)——这**不是** Groot 的 bug,它意味着**在该时间间隔内没有 stdout/stderr 输出**。可以与 `kubectl logs … --tail=50`(不带 `--since`)进行比较以查看最近的活动,并选择一个符合您需求的窗口。 ### 覆盖单次运行的 kubeconfig ``` ./bin/groot collect --config groot.yml --kubeconfig /path/to/other-kubeconfig ``` [↑ 返回顶部](#readme-top) ## 配置 编辑 `groot.yml`(或任何使用 `--config` 传递的文件),并使每个部分与您的集群和操作需求保持一致。不要将附带的示例当作直接可用的配置。 **带有注释的**模板(每个键都在注释中进行了解释)是 **[`configs/groot.yml.sample`](configs/groot.yml.sample)** ——与 `groot --print-sample-config` 的输出相同。当您希望在 YAML 旁边获得逐行指导时,请使用该文件。 示例配置(已简化;完整注释见上述仓库文件): ``` kubeconfig: "" output_dir: "./out" file_prefix: "groot-capture" collection: timeout: 20m worker_concurrency: 6 namespaces: - kube-system - default targets: default: deployments: - api statefulsets: - redis daemonsets: - node-agent helm_releases: - my-release include_pod_logs: true include_previous_logs: true pod_log_tail_lines: 1500 # pod_logs_since: "24" # optional: pod logs only; bare hours or duration (24h, 45m) include_node_details: true extra_kubectl: - "get componentstatuses" - "get csr" notify: slack: enabled: false # One URL, or several separated by ';' (e.g. team A; team B webhooks) webhook_url: "" discord: enabled: false # Discord server Settings → Integrations → Webhooks (same ';' for multiple URLs) webhook_url: "" teams: enabled: false # Same ';' convention as Slack for multiple Teams incoming webhooks webhook_url: "" pagerduty: enabled: false # Events API v2 integration key(s); multiple keys separated by ';' routing_key: "" severity: "warning" source: "groot" telegram: enabled: false token: "" # One chat id, or several (group/user) ids separated by ';' with the same bot chat_id: "" generic: enabled: false # POST JSON with one root string field only: {"":""} (see README → Notifications). webhook_url: "" json_key: "text" headers: {} ``` ### 配置参考(所有键) #### 顶层 | 键 | 作用 | |-----|----------------| | **`kubeconfig`** | 每次调用时传递给 `kubectl --kubeconfig` 的路径。如果为空,则使用进程的 **`KUBECONFIG`** 环境变量或 kubectl 的默认搜索顺序。单次运行中 **`groot --kubeconfig`** 仍会覆盖此设置(参见[解析与优先级](#resolution-and-precedence))。 | | **`output_dir`** | 基础目录:每次运行都会在此处创建一个**带时间戳**的文件夹,然后在其旁边写入 **`-.tar.gz`**。支持 **`~`** 和 **`${VAR}`** 展开。 | | **`file_prefix`** | 配置中的逻辑前缀(默认为 `groot-capture`)。为将来的捕获命名**保留**;目前归档文件使用 **`-`** 加上可选的 **`--message`**。 | | **`collection`** | 用于调整超时、并行性、namespace、pod 日志、额外的只读 kubectl 等(见下文)。 | | **`notify`** | 成功收集后的可选 webhook 和 API(参见[通知](#notifications))。 | #### `collection` | 键 | 作用 | |-----|----------------| | **`timeout`** | 整个 **`groot collect`** 运行的最大总时间(Go `context` 截止时间)。 | | **`worker_concurrency`** | **并行** kubectl worker 的数量。 | | **`namespaces`** | 对于每个条目,Groot 会运行 **`kubectl get all -n -o wide`** 并将其输出到 **`/resources.txt`**,并确保捕获树中存在 **`/`**。 | | **`targets`** | 仅用于每个 namespace 的 **pod 日志**过滤。键是 **namespace 名称**。其下的配置包括:**`deployments`**、**`statefulsets`**、**`daemonsets`**、**`helm_releases`**(字符串列表)。如果一个 namespace **至少有一个**非空列表,则只有标签与这些工作负载匹配的 pod 才会获得**日志**任务。如果某个 namespace **没有** `targets` 条目,或者条目的**所有列表均为空**,则该 namespace 的 pod 日志将保持**广泛**收集(所有 pod)。匹配使用的是 **`app.kubernetes.io/name`**、**`app.kubernetes.io/instance`**、**`app`**,以及与 **`helm_releases`** 对应的 Helm 实例(参见[解析与优先级](#resolution-and-precedence)下的 **工作负载过滤行为**)。 | | **`include_pod_logs`** | 当为 **`true`** 时,会为工作负载 pod 和控制平面 pod 排入 **`kubectl logs`** 任务(受 **`targets`**、**`pod_log_tail_lines`**、**`pod_logs_since`** 限制)。当为 **`false`** 时,跳过所有 pod 日志任务。 | | **`include_previous_logs`** | 当为 **`true`** 时,还会运行 **`kubectl logs --previous`** 并输出到 **`*.previous.log`**(标记为可选,因此缺少以前的容器不会导致运行失败)。 | | **`pod_log_tail_lines`** | 当 **`>0`** 时,将 **`--tail N`** 传递给 pod 日志命令。**`0`** 表示**不使用 `--tail`**(完整的日志流——可能非常大)。 | | **`pod_logs_since`** | 设置后,仅将 **`--since=…`** 传递给 **pod 日志**命令(仅纯数字 = **小时**,例如 **`24`** → **`24h`**;否则为 Go 持续时间格式,如 **`24h`**、**`45m`**)。当设置了该标志时,**`groot collect --since`** 会覆盖此值。捕获目录和 **`.tar.gz`** 的基本名称会在时间戳之后包含 **`since-`**,以便在磁盘上可以识别带有日志窗口的运行(参见[输出命名](#output-naming))。 | | **`include_node_details`** | 当为 **`true`** 时,对于每个节点,在 **`nodes/`** 下运行 **`kubectl describe`** 和 **`kubectl top node`**。 | | **`extra_kubectl`** | 额外的**只读** kubectl 命令行列表(按空格分割,**无 shell**)。在加载时加入允许列表;请参阅下面关于允许的动词的说明。 | #### `notify`(每个通道) | 块 / 字段 | 作用 | |----------------|----------------| | **`slack`**、**`discord`**、**`teams`**:**`enabled`**、**`webhook_url`** | 当为 **`enabled: true`** 时,向传入的 webhook URL 发送 POST 单行摘要。多个 URL:用 **`;`** 分隔。当 YAML 为空时,URL 也可以来自 **`GROOT_NOTIFY_*_WEBHOOK_URL`** 环境变量。 | | **`pagerduty`**:**`enabled`**、**`routing_key`**、**`severity`**、**`source`** | Events API v2 触发器;**`severity`** 可为 **`critical`**、**`error`**、**`warning`** 或 **`info`**。多个路由密钥:用 **`;`** 分隔。环境变量:**`GROOT_NOTIFY_PAGERDUTY_ROUTING_KEY`**。 | | **`telegram`**:**`enabled`**、**`token`**、**`chat_id`** | Bot token 和 chat id(s);多个 chat id:用 **`;`** 分隔。环境变量回退:**`GROOT_NOTIFY_TELEGRAM_TOKEN`**、**`GROOT_NOTIFY_TELEGRAM_CHAT_ID`**。 | | **`generic`**:**`enabled`**、**`webhook_url`**、**`json_key`**、**`headers`** | 自定义 POST:一个 JSON 字符串字段,命名为 **`json_key`**(默认为 **`text`**),其值为摘要。可选的 **`headers`** 用于身份验证等。环境变量:**`GROOT_NOTIFY_GENERIC_WEBHOOK_URL`**。 | 环境变量使用 `GROOT_` 前缀(Viper)。嵌套的 YAML 键通过将 `.` 替换为 `_` 映射到环境变量名称(例如 `collection.timeout` → `GROOT_COLLECTION_TIMEOUT`)。当设置了进程的 `KUBECONFIG` 环境变量时,YAML 中的 `kubeconfig` 仍然会被其覆盖(参见[解析与优先级](#resolution-and-precedence))。 常见示例: - `GROOT_OUTPUT_DIR`、`GROOT_FILE_PREFIX` - `GROOT_COLLECTION_TIMEOUT`、`GROOT_COLLECTION_WORKER_CONCURRENCY`、`GROOT_COLLECTION_INCLUDE_POD_LOGS`(布尔值)、`GROOT_COLLECTION_POD_LOG_TAIL_LINES`、`GROOT_COLLECTION_POD_LOGS_SINCE`、… - 通知密钥(当 `enabled: true` 且 YAML 字段为空时也会读取):`GROOT_NOTIFY_SLACK_WEBHOOK_URL`、`GROOT_NOTIFY_DISCORD_WEBHOOK_URL`、`GROOT_NOTIFY_TEAMS_WEBHOOK_URL`、`GROOT_NOTIFY_TELEGRAM_TOKEN`、`GROOT_NOTIFY_TELEGRAM_CHAT_ID`、`GROOT_NOTIFY_GENERIC_WEBHOOK_URL`、`GROOT_NOTIFY_PAGERDUTY_ROUTING_KEY` - `GROOT_NO_NOTIFY=1`(或 `true` / `yes`):与运行时的 `--no-notify` 效果相同 **`collection.extra_kubectl`:** 每个字符串都会按空格分割,并作为额外的 `kubectl` 参数传递(无 shell)。在加载时,Groot 只接受**面向读取**的子命令:`get`、`describe`、`explain`、`top`、`logs`、`api-resources`、`api-versions`、`version`、`cluster-info`、`wait`,以及 `config view …` 和 `auth can-i …`。其他任何命令都会立即导致 `collect` 失败并报出配置错误,这样可防止拼写错误或复制粘贴意外将额外命令变成破坏性动词(`delete`、`exec`、`apply` 等)。 当通知通道已启用但缺少所需凭据时,`groot` 会快速失败并给出清晰的配置错误。 [↑ 返回顶部](#readme-top) ## 解析与优先级 配置文件优先级: 1. `--config` 显式路径 2. `./groot.yml` 3. `~/.groot/groot.yml` 4. `/etc/groot/groot.yml` 5. `/etc/groot/groot.yml.sample` 6. 默认值 `kubeconfig` 优先级: 1. `--kubeconfig /path/to/config` 2. `KUBECONFIG` 3. YAML 中的 `kubeconfig` 值 4. 如果全部为空,则使用 `kubectl` 默认行为 工作负载过滤行为 (`collection.targets`): - 对于每个 namespace,您可以定义 `deployments`、`statefulsets`、`daemonsets` 和 `helm_releases` - 如果 namespace 具有目标,则该 namespace 的 pod 日志将限制为这些工作负载 - 如果 namespace 没有目标,pod 日志将保持默认的广泛收集行为 - `helm_releases` 与 `app.kubernetes.io/instance` 匹配 `pod_log_tail_lines` 行为: - `0`:收集完整日志(无 `--tail`;在需要整个日志流时使用) - `>0`:仅收集每个 pod 的最后 N 行 - 同时适用于当前和 `--previous` 的 pod 日志 `pod_logs_since 和 **`collect --since`**(仅限 pod 日志): - 为工作负载和控制平面 pod 日志任务添加 `kubectl logs --since=…`;其他诊断信息不受影响 - 在 YAML 或环境变量中,**仅包含数字的字符串**将被解释为**整小时**(`"24"` → `24h`);否则该值必须解析为 Go 持续时间格式(`24h`、`45m`、…) - 当设置了标志时,**`groot collect --since=…`** 会覆盖该次运行的 `collection.pod_logs_since` `include_previous_logs` 行为: - `true`:还会收集每个 pod 的 `kubectl logs --previous` 并输出到 `*.previous.log` - `false`:仅收集当前的 pod 日志 `output_dir` 路径展开: - 支持 `~`(主目录),例如 `~/tmp/groot-out` - 支持环境变量,例如 `${HOME}/tmp/groot-out` [↑ 返回顶部](#readme-top) ## 输出命名 捕获输出的名称为: - 目录:``,或者当设置了 **`collection.pod_logs_since`**(或 **`collect --since`**)时,为 **`-since-`**,其中 **``** 是持续时间在文件系统中的安全表示形式(例如 **`12h`**、**`45m`**),这样您无需打开归档即可一目了然地看到日志窗口 - 归档:与目录相同的开头标记,随后是 **`-[-].tar.gz`**(例如 `20260503-081049-since-12h-my-cluster.tar.gz`) `--message` 在使用前会经过清理: - 转换为小写 - 去除开头/结尾的空格 - 移除重音/变音符号 - 将空格和 `_` 转换为 `-` - 移除不受支持的文件系统字符 - 折叠重复的短划线 示例: - 输入:`--message "network routing issue"` - 后缀:`network-routing-issue` - 输出:`20260428-123200-my-cluster-network-routing-issue.tar.gz` - 当 **`pod_logs_since`**(或 **`--since`**)设置为 **`12h`** 且没有消息时:`20260428-123200-since-12h-my-cluster.tar.gz` 目录布局: - `nodes/` - `extras/` - 每个已配置 namespace 的一个目录(例如 `kube-system/`、`default/`) - pod 日志文件:`__.log`(启用时为 `.previous.log`),控制平面 pod 在 `kube-system/` 下也使用相同的模式 - 创建归档后,时间戳目录将被自动删除 在 `.tar.gz` 内部,每个路径都带有捕获文件夹名称的前缀(`/…`,例如 `20260502-174207/kube-system/…` 或 `20260503-081049-since-12h/kube-system/…`)。解压到共享目录(例如 `~/tmp/groot-out`)会将每次运行保留在其自己的子目录中,而不是将 `kube-system/`、`cloudbridge/` 等混合在解压根目录下。由旧版 Groot 生成的归档文件在 tar 根目录中可能仍是平面布局。 [↑ 返回顶部](#readme-top) ## 控制台输出模式 - 默认:汇总的 `INFO` 行 - `--verbose`:添加每个命令的 `CMD` / `OK` / `ERR` - `--quiet`:抑制正常的**控制台**输出,仅打印错误;**不会**禁用 webhook/API 通知 - `--no-notify`:为此运行跳过每个通知通道(配置中仍然可以包含 `enabled: true`;当您希望对外部系统保持静默时,可在 cron 中使用)。等效环境变量:`GROOT_NO_NOTIFY=1` - `--no-color`:禁用 ANSI 颜色 [↑ 返回顶部](#readme-top) ## 典型收集数据 - `kubectl cluster-info` - `kubectl get nodes -o wide` - `kubectl get pods -A -o wide` - `kubectl get events -A` - `kubectl describe node ` - `kubectl top node ` - `kubectl logs -n --all-containers` → 在每个 namespace 目录下命名为 `__.log` 的文件(处于 pending/unscheduled 状态的 pod 使用 `unknown-node`) - `kube-system` 中的控制平面 pod 日志(`tier=control-plane`,如果可用)使用相同的 `__.log` 模式 - `extras/kubeconfig.txt` 派生自 kubeconfig(`context`、`cluster`、`user`、`server`) [↑ 返回顶部](#readme-top) ## 通知 在配置中启用每个通道: - Slack Incoming Webhook(`notify.slack.webhook_url` 或 `GROOT_NOTIFY_SLACK_WEBHOOK_URL`)。对于多个通道,在同一个值上放置几个完整的 webhook URL,以 `;` 分隔(空格可选);Groot 会按顺序通知每个 URL,并在任何请求失败时报告组合错误。 - **Discord** Incoming Webhook(`notify.discord.webhook_url` 或 `GROOT_NOTIFY_DISCORD_WEBHOOK_URL`):相同的以 `;` 分隔的 URL 列表。Payload 为 `{"content":""}`,符合 [Discord webhook API](https://discord.com/developers/docs/resources/webhook#execute-webhook) 规范。超过 2000 个字符的消息将被截断并附加 `...`,以保持请求有效。 - Teams Incoming Webhook —— 对于 `notify.teams.webhook_url` / `GROOT_NOTIFY_TEAMS_WEBHOOK_URL` 使用相同的以 `;` 分隔的列表。 - **PagerDuty** [Events API v2](https://developer.pagerduty.com/docs/events-api-v2-overview)(`notify.pagerduty` 或 `GROOT_NOTIFY_PAGERDUTY_ROUTING_KEY`):`routing_key` 是 Events v2 集成密钥(由 `;` 分隔的多个密钥,每个都会触发自己的 `trigger` 事件)。`severity` 必须是 `critical`、`error`、`warning` 或 `info`(默认为 `warning`)。`source` 默认为 `groot`。事件的 `payload.summary` 与其他通道的行相同;`payload.custom_details` 包括 `total`、`success`、`failed`、`duration`、`output_dir` 和 `archive_path`。成功交付预期会收到 PagerDuty 返回的 HTTP **202** 响应。 - Telegram Bot API(`notify.telegram.token` + `chat_id`,或 `GROOT_NOTIFY_TELEGRAM_TOKEN` / `GROOT_NOTIFY_TELEGRAM_CHAT_ID`)。一个 bot token;多个目的地在同一个 `chat_id` 字符串中使用以 `;` 分隔的多个 chat id(向每个聊天发送相同的消息)。 - **通用 HTTP webhook**(`notify.generic` 或 `GROOT_NOTIFY_GENERIC_WEBHOOK_URL`):带有 `Content-Type: application/json` 和请求体 `{"":""}` 的 `POST` 请求。默认的 `json_key` 为 `text`。对于 Discord,请改用 **`notify.discord`**(包含正确的 `content` 字段和长度限制)。可选的 `headers`(YAML map)将在每次请求时发送。多个端点:在 `webhook_url` 中以 `;` 分隔完整的 URL。 **通用 webhook — 范围(在依赖它之前请阅读本节):** - **它发送的内容:** 根节点正好是一个 JSON 对象,包含**一个字符串字段**,其名称由您通过 `json_key` 设置。该值始终是 Groot 的单行收集摘要(与其他通道的文本相同)。示例:`{"text":"GROOT finished. total=…"}`。 - **它不能做的事情:** 没有任意的请求体模板(您不能将摘要放在多个字段中,不能将其包装在嵌套对象中,也不能在该单一键值对之外混合使用固定键)。没有非 JSON 请求体(没有纯文本、`application/x-www-form-urlencoded`、XML)。如果集成需要额外的字段、签名 (HMAC) 或自定义布局,请使用小型代理服务或日后扩展 Groot。 **已实现的通道:** Slack、Discord、Teams、PagerDuty (Events v2)、Telegram 以及如上所述的通用 JSON webhook。没有内置的电子邮件等。 [↑ 返回顶部](#readme-top) ## 无特权容器 ``` make docker-build make docker-buildx make scan docker run --rm \ -v "$HOME/.kube:/home/nonroot/.kube:ro" \ -v "$(pwd)/out:/app/out" \ groot:local ``` 对于严格的无特权运行时,请使用 Podman: ``` podman build -t groot:local . podman run --rm \ -v "$HOME/.kube:/home/nonroot/.kube:ro" \ -v "$(pwd)/out:/app/out" \ groot:local ``` [↑ 返回顶部](#readme-top) ## 安全说明 收集的日志可能包含敏感数据。请根据您的安全策略处理归档文件。 [↑ 返回顶部](#readme-top) ## 参与贡献 觉得 Groot 有用吗?我们很乐意得到您的帮助,使其变得更好。您可以: - **报告错误** 或 **提出功能建议** — [发起 issue](https://github.com/hrodrig/groot/issues) - **贡献代码** — 参阅 [CONTRIBUTING.md](./CONTRIBUTING.md) 了解如何提交 pull request - **为仓库加星** — 这有助于其他人发现 Groot 感谢您使用 Groot。 [↑ 返回顶部](#readme-top)
标签:Awesome, EVTX分析, Go语言, Pandas, Pod日志, tar.gz, 二进制发布, 压缩文件, 安全应急响应, 并行处理, 开源工具, 故障排查, 数据打包, 无线安全, 日志审计, 日志收集, 程序破解, 系统管理, 节点信息, 请求拦截, 资源描述, 运维工具, 集群监控, 集群诊断