hrodrig/groot
GitHub: hrodrig/groot
GROOT 是一个用 Go 编写的 Kubernetes 集群诊断 CLI 工具,通过并发执行 kubectl 命令,一键将节点、事件、Pod 日志等诊断信息收集并打包为归档文件,适用于故障排查与应急响应场景。
Stars: 1 | Forks: 0
# GROOT — Kubernetes 诊断 CLI
**☸** _将集群诊断信息收集到一个归档文件中_
[](https://github.com/hrodrig/groot/releases)
[](https://github.com/hrodrig/groot/releases)
[](https://go.dev/)
[](./LICENSE)
[](https://pkg.go.dev/github.com/hrodrig/groot)
[](https://github.com/hrodrig/groot/actions/workflows/ci.yml)
[](https://codecov.io/gh/hrodrig/groot)
[](https://goreportcard.com/report/github.com/hrodrig/groot)
[](https://dev.to/hrodrig/groot-one-archive-for-cluster-diagnostics-2d76)
[](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/) 文档索引。
` 只有在**资产文件名在每次发布时完全相同**的情况下才有效。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, 二进制发布, 压缩文件, 安全应急响应, 并行处理, 开源工具, 故障排查, 数据打包, 无线安全, 日志审计, 日志收集, 程序破解, 系统管理, 节点信息, 请求拦截, 资源描述, 运维工具, 集群监控, 集群诊断