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 项目在启动和采集周期中,各目录之间的调用关系与数据流向。箭头方向表示依赖或数据传递方向。

Exporter 标准化目录依赖与数据流 Exporter 标准化目录依赖与数据流 cmd/main.go pkg/config pkg/collector metrics/ internal/auth internal/middleware config/*.yaml 采集作业平台(安全权限注入) 说明:实线为启动时依赖,虚线为运行时配置注入。采集作业平台通过 internal/auth 和 config/ 注入安全权限。

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 白名单、请求签名校验),无需修改采集器核心代码。
采集作业平台安全权限注入流程 采集作业平台安全权限注入流程 采集作业平台 写入 config/*.yaml 挂载到 internal/auth 注入 internal/middleware Exporter 进程(安全启动)
核心收益: 标准化目录结构使得采集作业平台无需修改 Exporter 源码即可完成安全权限配置。平台只需操作 config/ 目录和 internal/ 的挂载点,Exporter 通过约定好的接口自动加载,实现“平台-Exporter”的安全解耦。