3. Exporter 项目结构标准化
在 Prometheus 生态中,Exporter 是采集端最核心的组件。一个标准化的项目结构不仅能降低新成员的认知成本,还能让 CI/CD、代码审查、安全扫描和采集作业平台的权限注入变得可预测。本章定义一套经过生产验证的目录布局,并解释每个目录的职责与最佳实践。
3.1 推荐的目录结构总览
以下结构适用于 Go 语言实现的 Exporter,同时兼容 Python/Java 项目的等价映射。核心原则是:可编译入口与业务逻辑分离、内部实现不对外暴露、配置与指标定义集中管理。
my-exporter/
├── cmd/
│ └── my-exporter/
│ └── main.go # 程序入口,仅做初始化与启动
├── pkg/
│ ├── collector/ # 采集器实现(每个指标组一个文件)
│ │ ├── cpu_collector.go
│ │ ├── memory_collector.go
│ │ └── disk_collector.go
│ ├── config/ # 配置解析与校验
│ │ └── config.go
│ └── logger/ # 日志封装(可选)
│ └── logger.go
├── internal/
│ ├── auth/ # 安全鉴权逻辑(、mTLS)
│ │ └── auth.go
│ ├── middleware/ # HTTP 中间件(限流、审计)
│ │ └── middleware.go
│ └── version/ # 版本信息(编译时注入)
│ └── version.go
├── config/
│ ├── my-exporter.yaml # 默认配置文件
│ └── rules/ # 告警规则(可选)
│ └── alerts.yml
├── metrics/
│ ├── metrics.go # 指标注册与描述定义
│ └── metrics_test.go # 指标单元测试
├── scripts/
│ ├── build.sh # 构建脚本
│ └── docker-entrypoint.sh # 容器入口
├── deploy/
│ ├── Dockerfile
│ ├── docker-compose.yaml
│ └── kubernetes/
│ ├── deployment.yaml
│ └── service.yaml
├── docs/
│ ├── README.md
│ └── DEVELOPMENT.md
├── go.mod
├── go.sum
└── Makefile
3.2 各目录职责与最佳实践
| 目录 | 核心职责 | 最佳实践 |
|---|---|---|
| cmd/ | 程序入口,解析命令行参数,启动 HTTP 服务 | 每个二进制一个子目录;main 函数不超过 50 行;不包含业务逻辑 |
| pkg/ | 可被外部引用的公共库(采集器、配置、日志) | 对外暴露的接口要稳定;避免循环依赖;采集器按资源类型拆分文件 |
| internal/ | 私有实现(鉴权、中间件、版本) | Go 编译器强制禁止外部导入;适合存放安全敏感逻辑 |
| config/ | 静态配置文件与告警规则 | YAML 格式优先;提供完整注释的示例文件;敏感字段用环境变量覆盖 |
| metrics/ | Prometheus 指标注册、描述、类型定义 | 每个指标附带 HELP 和 TYPE 注释;单元测试覆盖指标名称与标签 |
| scripts/ | 构建、测试、部署辅助脚本 | 统一使用 bash 或 Makefile 调用;容器入口脚本需处理信号转发 |
| deploy/ | 容器化与编排配置 | Dockerfile 使用多阶段构建;K8s 清单包含资源限制与健康检查 |
| docs/ | 项目文档 | README 包含快速开始、指标列表、配置说明;DEVELOPMENT 包含本地开发步骤 |
安全提示: internal 目录是存放鉴权逻辑和 TLS 证书加载的首选位置。在采集作业平台扩展安全权限配置时,平台会通过环境变量或挂载文件向 internal/auth 注入 或证书路径,外部采集器无法直接访问这些敏感逻辑。
3.3 目录依赖关系与数据流
下图展示了标准化 Exporter 项目在启动和采集周期中,各目录之间的调用关系与数据流向。箭头方向表示依赖或数据传递方向。
3.4 关键目录深度解析
3.4.1 cmd/ —— 极简入口
- 职责:解析命令行参数(flag 或 cobra),加载配置,启动 HTTP 监听。
- 禁止:在 main.go 中编写采集逻辑、指标注册或数据库操作。
- 最佳实践:main 函数只做三件事——初始化配置、创建采集器、启动 HTTP 服务。
// cmd/my-exporter/main.go
package main
import (
"net/http"
"my-exporter/pkg/collector"
"my-exporter/pkg/config"
"my-exporter/internal/middleware"
)
func main() {
cfg := config.Load("config/my-exporter.yaml")
col := collector.New(cfg)
mux := http.NewServeMux()
mux.Handle("/metrics", middleware.Auth(col))
http.ListenAndServe(":8080", mux)
}
3.4.2 pkg/collector —— 采集器实现
- 职责:实现 Prometheus
Collector接口,每个文件对应一个资源类型。 - 最佳实践:使用
prometheus.NewDesc定义指标描述,在Collect方法中更新指标值。 - 安全约束:采集器不应直接处理鉴权或 TLS,这些由 internal/middleware 统一拦截。
3.4.3 internal/ —— 安全与中间件隔离
- auth:实现 校验、mTLS 证书验证、RBAC 角色映射。采集作业平台通过环境变量
AUTH_或挂载证书文件注入。 - middleware:提供 HTTP 中间件链,包括限流(rate limit)、审计日志(audit log)、请求 ID 注入。
- version:通过
-ldflags在编译时注入版本号和 Git Commit。
安全警告: 切勿将 internal 目录中的鉴权密钥硬编码在代码中。采集作业平台扩展安全权限配置时,应通过环境变量或 Kubernetes Secret 挂载的方式动态注入,并在 internal/auth 中实现热加载。
3.4.4 metrics/ —— 指标定义与测试
- 职责:集中管理所有 Prometheus 指标的
Desc定义、常量标签、指标类型(Gauge/Counter/Histogram)。 - 最佳实践:每个指标附带
HELP和TYPE注释,便于自动生成文档。 - 测试:
metrics_test.go验证指标名称不重复、标签符合命名规范、类型正确。
// metrics/metrics.go
package metrics
import "github.com/prometheus/client_golang/prometheus"
var (
CpuUsageGauge = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "node_cpu_usage_ratio",
Help: "Current CPU usage ratio (0-1).",
},
[]string{"cpu", "mode"},
)
HttpRequestTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "exporter_http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"method", "path", "status"},
)
)
3.5 目录结构对比:标准化 vs 非标准化
| 维度 | 标准化结构 | 非标准化结构(常见问题) |
|---|---|---|
| 入口清晰度 | cmd/ 唯一入口,main 函数极简 | main.go 散落在根目录或 pkg 中,难以定位 |
| 安全隔离 | internal/ 强制私有,外部无法导入鉴权逻辑 | 鉴权代码放在 pkg/ 中,被外部项目意外依赖 |
| 配置管理 | config/ 目录 + pkg/config 解析,职责分离 | 配置解析与采集器代码混在一起,难以维护 |
| 指标可测试性 | metrics/ 独立目录,单元测试覆盖指标定义 | 指标定义散落在多个 collector 文件中,测试困难 |
| 平台集成 | internal/auth 预留注入点,平台可安全扩展 | 无统一注入点,平台需修改 Exporter 源码 |
3.6 采集作业平台视角:目录结构与安全权限的映射
在采集作业平台扩展安全权限配置时,标准化目录结构提供了清晰的注入点:
- config/my-exporter.yaml:平台通过配置管理模块,动态写入
auth.或tls.cert_path字段。 - internal/auth:平台以 Sidecar 模式或 Init Container 方式,将证书/ 文件挂载到指定路径,Exporter 启动时自动加载。
- internal/middleware:平台可注入自定义中间件(如 IP 白名单、请求签名校验),无需修改采集器核心代码。
核心收益: 标准化目录结构使得采集作业平台无需修改 Exporter 源码即可完成安全权限配置。平台只需操作 config/ 目录和 internal/ 的挂载点,Exporter 通过约定好的接口自动加载,实现“平台-Exporter”的安全解耦。