debug-buttercup by trailofbits/skills
npx skills add https://github.com/trailofbits/skills --skill debug-buttercupcrs 命名空间中的 Pod 处于 CrashLoopBackOff、OOMKilled 或重启状态crs Kubernetes 命名空间之外的问题所有 Pod 都在命名空间 crs 中运行。关键服务:
| 层级 | 服务 |
|---|---|
| 基础设施 | redis, dind, litellm, registry-cache |
| 编排 | scheduler, task-server, task-downloader, scratch-cleaner |
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 模糊测试 | build-bot, fuzzer-bot, coverage-bot, tracer-bot, merger-bot |
| 分析 | patcher, seed-gen, program-model, pov-reproducer |
| 接口 | competition-api, ui |
始终从排查开始。首先运行这三个命令:
# 1. Pod 状态 - 查找重启、CrashLoopBackOff、OOMKilled
kubectl get pods -n crs -o wide
# 2. 事件 - 问题发生的时间线
kubectl get events -n crs --sort-by='.lastTimestamp'
# 3. 仅警告 - 过滤噪音
kubectl get events -n crs --field-selector type=Warning --sort-by='.lastTimestamp'
然后缩小范围:
# 为什么某个特定的 Pod 重启了?检查 Last State Reason (OOMKilled, Error, Completed)
kubectl describe pod -n crs <pod-name> | grep -A8 'Last State:'
# 检查实际资源限制与预期限制
kubectl get pod -n crs <pod-name> -o jsonpath='{.spec.containers[0].resources}'
# 已崩溃容器的日志 (--previous = 已终止的容器)
kubectl logs -n crs <pod-name> --previous --tail=200
# 当前日志
kubectl logs -n crs <pod-name> --tail=200
高重启次数不一定意味着问题正在持续发生 —— 重启次数会在 Pod 的生命周期内累积。始终要区分:
--tail 显示日志缓冲区的末尾,其中可能包含旧消息。使用 --since=300s 来确认问题当前是否正在发生。--timestamps 有助于跨服务关联事件。describe pod 中检查 Last State 的时间戳,以查看最近一次崩溃实际发生的时间。当许多 Pod 在同一时间附近重启时,在调查单个 Pod 之前,先检查是否存在共享依赖故障。最常见的级联故障:Redis 宕机 -> 每个服务都收到 ConnectionError/ConnectionRefusedError -> 大规模重启。在多个 --previous 日志中查找相同的错误 —— 如果它们都显示 redis.exceptions.ConnectionError,那么调试 Redis,而不是单个服务。
# 一次获取服务的所有副本日志
kubectl logs -n crs -l app=fuzzer-bot --tail=100 --prefix
# 实时流式传输
kubectl logs -n crs -l app.kubernetes.io/name=redis -f
# 将所有日志收集到磁盘(现有脚本)
bash deployment/collect-logs.sh
# 每个 Pod 的 CPU/内存
kubectl top pods -n crs
# 节点级别
kubectl top nodes
# 节点状况 (disk pressure, memory pressure, PID pressure)
kubectl describe node <node> | grep -A5 Conditions
# Pod 内部的磁盘使用情况
kubectl exec -n crs <pod> -- df -h
# 是什么占用了磁盘
kubectl exec -n crs <pod> -- sh -c 'du -sh /corpus/* 2>/dev/null'
kubectl exec -n crs <pod> -- sh -c 'du -sh /scratch/* 2>/dev/null'
Redis 是核心。当它宕机时,一切都会级联故障。
# Redis Pod 状态
kubectl get pods -n crs -l app.kubernetes.io/name=redis
# Redis 日志 (AOF 警告, OOM, 连接问题)
kubectl logs -n crs -l app.kubernetes.io/name=redis --tail=200
# 连接到 Redis CLI
kubectl exec -n crs <redis-pod> -- redis-cli
# 在 redis-cli 内部:关键诊断
INFO memory # used_memory_human, maxmemory
INFO persistence # aof_enabled, aof_last_bgrewrite_status, aof_delayed_fsync
INFO clients # connected_clients, blocked_clients
INFO stats # total_connections_received, rejected_connections
CLIENT LIST # 查看谁已连接
DBSIZE # 总键数
# AOF 配置
CONFIG GET appendonly # AOF 是否启用?
CONFIG GET appendfsync # fsync 策略: everysec, always, 或 no
# /data 挂载在什么上?(磁盘 vs tmpfs 对 AOF 性能很重要)
kubectl exec -n crs <redis-pod> -- mount | grep /data
kubectl exec -n crs <redis-pod> -- du -sh /data/
Buttercup 使用带有消费者组的 Redis 流。队列名称:
| 队列 | 流键 |
|---|---|
| 构建 | fuzzer_build_queue |
| 构建输出 | fuzzer_build_output_queue |
| 崩溃 | fuzzer_crash_queue |
| 已确认漏洞 | confirmed_vulnerabilities_queue |
| 下载任务 | orchestrator_download_tasks_queue |
| 就绪任务 | tasks_ready_queue |
| 补丁 | patches_queue |
| 索引 | index_queue |
| 索引输出 | index_output_queue |
| 已追踪漏洞 | traced_vulnerabilities_queue |
| POV 请求 | pov_reproducer_requests_queue |
| POV 响应 | pov_reproducer_responses_queue |
| 删除任务 | orchestrator_delete_task_queue |
# 检查流长度(待处理消息)
kubectl exec -n crs <redis-pod> -- redis-cli XLEN fuzzer_build_queue
# 检查消费者组延迟
kubectl exec -n crs <redis-pod> -- redis-cli XINFO GROUPS fuzzer_build_queue
# 检查每个消费者的待处理消息
kubectl exec -n crs <redis-pod> -- redis-cli XPENDING fuzzer_build_queue build_bot_consumers - + 10
# 任务注册表大小
kubectl exec -n crs <redis-pod> -- redis-cli HLEN tasks_registry
# 任务状态计数
kubectl exec -n crs <redis-pod> -- redis-cli SCARD cancelled_tasks
kubectl exec -n crs <redis-pod> -- redis-cli SCARD succeeded_tasks
kubectl exec -n crs <redis-pod> -- redis-cli SCARD errored_tasks
消费者组:build_bot_consumers, orchestrator_group, patcher_group, index_group, tracer_bot_group。
Pod 将时间戳写入 /tmp/health_check_alive。存活探针检查文件的新鲜度。
# 检查健康文件的新鲜度
kubectl exec -n crs <pod> -- stat /tmp/health_check_alive
kubectl exec -n crs <pod> -- cat /tmp/health_check_alive
如果一个 Pod 处于重启循环中,健康检查文件很可能因为主进程被阻塞(例如等待 Redis、I/O 卡住)而过期。
所有服务都通过 OpenTelemetry 导出追踪和指标。如果部署了 Signoz (global.signoz.deployed: true),请使用其 UI 进行跨服务的分布式追踪。
# 检查是否配置了 OTEL
kubectl exec -n crs <pod> -- env | grep OTEL
# 验证 Signoz Pod 是否正在运行(如果已部署)
kubectl get pods -n platform -l app.kubernetes.io/name=signoz
追踪对于诊断缓慢的任务处理、识别流水线中的哪个服务是瓶颈以及关联跨 scheduler -> build-bot -> fuzzer-bot 链的事件特别有用。
# PVC 状态
kubectl get pvc -n crs
# 检查 corpus tmpfs 是否已挂载、其大小和后备类型
kubectl exec -n crs <pod> -- mount | grep corpus_tmpfs
kubectl exec -n crs <pod> -- df -h /corpus_tmpfs 2>/dev/null
# 检查是否设置了 CORPUS_TMPFS_PATH
kubectl exec -n crs <pod> -- env | grep CORPUS
# 完整的磁盘布局 - 哪些在真实磁盘上,哪些在 tmpfs 上
kubectl exec -n crs <pod> -- df -h
当 global.volumes.corpusTmpfs.enabled: true 时,会设置 CORPUS_TMPFS_PATH。这会影响 fuzzer-bot、coverage-bot、seed-gen 和 merger-bot。
当行为与预期不符时,验证 Helm 值是否实际生效:
# 检查 Pod 的实际资源限制
kubectl get pod -n crs <pod-name> -o jsonpath='{.spec.containers[0].resources}'
# 检查 Pod 的实际卷定义
kubectl get pod -n crs <pod-name> -o jsonpath='{.spec.volumes}'
Helm 值模板中的拼写错误(例如错误的键名)会静默回退到 Chart 的默认值。如果部署的资源与值模板不匹配,请检查键名是否不匹配。
有关每个服务的详细症状、根本原因和修复方法,请参阅 references/failure-patterns.md。
快速参考:
kubectl logs -n crs -l app=dind --tail=100 -- 查找 docker 守护进程崩溃、存储驱动错误kubectl logs -n crs -l app=scheduler --tail=-1 --prefix | grep "WAIT_PATCH_PASS\|ERROR\|SUBMIT"运行自动化的排查快照:
bash {baseDir}/scripts/diagnose.sh
传递 --full 以同时转储所有 Pod 的最近日志:
bash {baseDir}/scripts/diagnose.sh --full
这将一次性收集 Pod 状态、事件、资源使用情况、Redis 健康状况和队列深度。
每周安装次数
703
代码仓库
GitHub 星标数
3.9K
首次出现
2026年2月11日
安全审计
安装于
opencode630
codex629
claude-code629
gemini-cli621
github-copilot614
cursor613
crs namespace are in CrashLoopBackOff, OOMKilled, or restartingcrs Kubernetes namespaceAll pods run in namespace crs. Key services:
| Layer | Services |
|---|---|
| Infra | redis, dind, litellm, registry-cache |
| Orchestration | scheduler, task-server, task-downloader, scratch-cleaner |
| Fuzzing | build-bot, fuzzer-bot, coverage-bot, tracer-bot, merger-bot |
| Analysis | patcher, seed-gen, program-model, pov-reproducer |
| Interface | competition-api, ui |
Always start with triage. Run these three commands first:
# 1. Pod status - look for restarts, CrashLoopBackOff, OOMKilled
kubectl get pods -n crs -o wide
# 2. Events - the timeline of what went wrong
kubectl get events -n crs --sort-by='.lastTimestamp'
# 3. Warnings only - filter the noise
kubectl get events -n crs --field-selector type=Warning --sort-by='.lastTimestamp'
Then narrow down:
# Why did a specific pod restart? Check Last State Reason (OOMKilled, Error, Completed)
kubectl describe pod -n crs <pod-name> | grep -A8 'Last State:'
# Check actual resource limits vs intended
kubectl get pod -n crs <pod-name> -o jsonpath='{.spec.containers[0].resources}'
# Crashed container's logs (--previous = the container that died)
kubectl logs -n crs <pod-name> --previous --tail=200
# Current logs
kubectl logs -n crs <pod-name> --tail=200
High restart counts don't necessarily mean an issue is ongoing -- restarts accumulate over a pod's lifetime. Always distinguish:
--tail shows the end of the log buffer, which may contain old messages. Use --since=300s to confirm issues are actively happening now.--timestamps on log output helps correlate events across services.Last State timestamps in describe pod to see when the most recent crash actually occurred.When many pods restart around the same time, check for a shared-dependency failure before investigating individual pods. The most common cascade: Redis goes down -> every service gets ConnectionError/ConnectionRefusedError -> mass restarts. Look for the same error across multiple --previous logs -- if they all say redis.exceptions.ConnectionError, debug Redis, not the individual services.
# All replicas of a service at once
kubectl logs -n crs -l app=fuzzer-bot --tail=100 --prefix
# Stream live
kubectl logs -n crs -l app.kubernetes.io/name=redis -f
# Collect all logs to disk (existing script)
bash deployment/collect-logs.sh
# Per-pod CPU/memory
kubectl top pods -n crs
# Node-level
kubectl top nodes
# Node conditions (disk pressure, memory pressure, PID pressure)
kubectl describe node <node> | grep -A5 Conditions
# Disk usage inside a pod
kubectl exec -n crs <pod> -- df -h
# What's eating disk
kubectl exec -n crs <pod> -- sh -c 'du -sh /corpus/* 2>/dev/null'
kubectl exec -n crs <pod> -- sh -c 'du -sh /scratch/* 2>/dev/null'
Redis is the backbone. When it goes down, everything cascades.
# Redis pod status
kubectl get pods -n crs -l app.kubernetes.io/name=redis
# Redis logs (AOF warnings, OOM, connection issues)
kubectl logs -n crs -l app.kubernetes.io/name=redis --tail=200
# Connect to Redis CLI
kubectl exec -n crs <redis-pod> -- redis-cli
# Inside redis-cli: key diagnostics
INFO memory # used_memory_human, maxmemory
INFO persistence # aof_enabled, aof_last_bgrewrite_status, aof_delayed_fsync
INFO clients # connected_clients, blocked_clients
INFO stats # total_connections_received, rejected_connections
CLIENT LIST # see who's connected
DBSIZE # total keys
# AOF configuration
CONFIG GET appendonly # is AOF enabled?
CONFIG GET appendfsync # fsync policy: everysec, always, or no
# What is /data mounted on? (disk vs tmpfs matters for AOF performance)
kubectl exec -n crs <redis-pod> -- mount | grep /data
kubectl exec -n crs <redis-pod> -- du -sh /data/
Buttercup uses Redis streams with consumer groups. Queue names:
| Queue | Stream Key |
|---|---|
| Build | fuzzer_build_queue |
| Build Output | fuzzer_build_output_queue |
| Crash | fuzzer_crash_queue |
| Confirmed Vulns | confirmed_vulnerabilities_queue |
| Download Tasks | orchestrator_download_tasks_queue |
| Ready Tasks | tasks_ready_queue |
| Patches | patches_queue |
| Index | index_queue |
| Index Output | index_output_queue |
| Traced Vulns | traced_vulnerabilities_queue |
| POV Requests | pov_reproducer_requests_queue |
| POV Responses | pov_reproducer_responses_queue |
| Delete Task | orchestrator_delete_task_queue |
# Check stream length (pending messages)
kubectl exec -n crs <redis-pod> -- redis-cli XLEN fuzzer_build_queue
# Check consumer group lag
kubectl exec -n crs <redis-pod> -- redis-cli XINFO GROUPS fuzzer_build_queue
# Check pending messages per consumer
kubectl exec -n crs <redis-pod> -- redis-cli XPENDING fuzzer_build_queue build_bot_consumers - + 10
# Task registry size
kubectl exec -n crs <redis-pod> -- redis-cli HLEN tasks_registry
# Task state counts
kubectl exec -n crs <redis-pod> -- redis-cli SCARD cancelled_tasks
kubectl exec -n crs <redis-pod> -- redis-cli SCARD succeeded_tasks
kubectl exec -n crs <redis-pod> -- redis-cli SCARD errored_tasks
Consumer groups: build_bot_consumers, orchestrator_group, patcher_group, index_group, tracer_bot_group.
Pods write timestamps to /tmp/health_check_alive. The liveness probe checks file freshness.
# Check health file freshness
kubectl exec -n crs <pod> -- stat /tmp/health_check_alive
kubectl exec -n crs <pod> -- cat /tmp/health_check_alive
If a pod is restart-looping, the health check file is likely going stale because the main process is blocked (e.g. waiting on Redis, stuck on I/O).
All services export traces and metrics via OpenTelemetry. If Signoz is deployed (global.signoz.deployed: true), use its UI for distributed tracing across services.
# Check if OTEL is configured
kubectl exec -n crs <pod> -- env | grep OTEL
# Verify Signoz pods are running (if deployed)
kubectl get pods -n platform -l app.kubernetes.io/name=signoz
Traces are especially useful for diagnosing slow task processing, identifying which service in a pipeline is the bottleneck, and correlating events across the scheduler -> build-bot -> fuzzer-bot chain.
# PVC status
kubectl get pvc -n crs
# Check if corpus tmpfs is mounted, its size, and backing type
kubectl exec -n crs <pod> -- mount | grep corpus_tmpfs
kubectl exec -n crs <pod> -- df -h /corpus_tmpfs 2>/dev/null
# Check if CORPUS_TMPFS_PATH is set
kubectl exec -n crs <pod> -- env | grep CORPUS
# Full disk layout - what's on real disk vs tmpfs
kubectl exec -n crs <pod> -- df -h
CORPUS_TMPFS_PATH is set when global.volumes.corpusTmpfs.enabled: true. This affects fuzzer-bot, coverage-bot, seed-gen, and merger-bot.
When behavior doesn't match expectations, verify Helm values actually took effect:
# Check a pod's actual resource limits
kubectl get pod -n crs <pod-name> -o jsonpath='{.spec.containers[0].resources}'
# Check a pod's actual volume definitions
kubectl get pod -n crs <pod-name> -o jsonpath='{.spec.volumes}'
Helm values template typos (e.g. wrong key names) silently fall back to chart defaults. If deployed resources don't match the values template, check for key name mismatches.
For detailed per-service symptoms, root causes, and fixes, see references/failure-patterns.md.
Quick reference:
kubectl logs -n crs -l app=dind --tail=100 -- look for docker daemon crashes, storage driver errorskubectl logs -n crs -l app=scheduler --tail=-1 --prefix | grep "WAIT_PATCH_PASS\|ERROR\|SUBMIT"Run the automated triage snapshot:
bash {baseDir}/scripts/diagnose.sh
Pass --full to also dump recent logs from all pods:
bash {baseDir}/scripts/diagnose.sh --full
This collects pod status, events, resource usage, Redis health, and queue depths in one pass.
Weekly Installs
703
Repository
GitHub Stars
3.9K
First Seen
Feb 11, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode630
codex629
claude-code629
gemini-cli621
github-copilot614
cursor613
Azure 升级评估与自动化工具 - 轻松迁移 Functions 计划、托管层级和 SKU
64,099 周安装