ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Prometheus Service Discovery 设计与实现指南:从接口规范到 VictoriaMetrics 落地实践

Prometheus Service Discovery 设计与实现指南:从接口规范到 VictoriaMetrics 落地实践 Prometheus Service Discovery 设计与实现指南从接口规范到 VictoriaMetrics 落地实践【免费下载链接】VictoriaMetricsVictoriaMetrics: fast, cost-effective monitoring solution and time series database项目地址: https://gitcode.com/GitHub_Trending/vi/VictoriaMetrics导读本文以 Prometheus 官方 Service Discovery服务发现简称 SD组件设计文档为主体系统讲解什么样的机制才适合做成 SDSD 如何向 Prometheus 映射元数据如何实现一个Discoverer与Config接口以及新增 SD 的检查清单等核心问题。当前仓库VictoriaMetrics通过vendor/github.com/prometheus/prometheus/discovery/完整引入该组件并在 lib/promscrape/discovery/ 下实现了 20 余种 Prometheus 兼容的 SD 机制Consul、Kubernetes、EC2、DNS、Docker、file_sd 等本文将结合这些真实源码与实践文档帮助读者既理解 SD 的抽象模型又能落地到 VictoriaMetrics / vmagent 的抓取配置实战中。一、Service Discovery 在监控体系中的位置在 Prometheus 兼容的抓取架构中抓取器需要知道去抓谁。scrape_configs中每个job_name下的*_sd_configs小节负责动态回答这个问题它从各类基础设施云厂商、服务注册中心、编排系统、DNS、文件等中发现一批机器或服务的地址把结果转成统一的 target 元数据再交给 relabeling 加工后形成最终的抓取目标。VictoriaMetrics 的单机版与 vmagent 均通过-promscrape.config指向的配置文件支持全部 Prometheus 兼容 SD完整列表见 docs/victoriametrics/sd_configs.mdazure_sd_configs、consul_sd_configs、consulagent_sd_configs、digitalocean_sd_configs、dns_sd_configs、docker_sd_configs、dockerswarm_sd_configs、ec2_sd_configs、eureka_sd_configs、file_sd_configs、gce_sd_configs、hetzner_sd_configs、http_sd_configs、kubernetes_sd_configs、kuma_sd_configs、linode_sd_configs、marathon_sd_configs、nomad_sd_configs、openstack_sd_configs、ovhcloud_sd_configs、puppetdb_sd_configs、static_configs、vultr_sd_configs、yandexcloud_sd_configs。一个值得注意的细节VictoriaMetrics 不支持在配置文件里写refresh_interval而是统一用命令行 flag如-promscrape.consulSDCheckInterval60s控制各类 SD 的刷新周期详情同样在 docs/victoriametrics/sd_configs.md 中说明。二、什么才是一个合理的 SD 机制Prometheus 对是否值得做成原生 SD有一套明确的判断标准核心诉求是集成基础设施里已有的服务发现方式而不是发明新方式。机制应当成熟且被广泛使用一个 SD 至少应在多个组织中实际使用能发现运行在某处的机器和/或服务。此外自解冻新 SD 引入限制以来新实现还要求有具备 push 权限的专职维护者。不做全新或变种的发现机制不应为了绕开用户缺乏 SD 或配置管理基础设施的现状而发明新的发现途径。发现同类软件不算服务发现例如向一个 Kafka 或 Cassandra 节点询问其他节点这不属于服务发现决定哪台机器成为 Kafka 节点的是机器数据库或配置管理系统那才是应该对接的 SD。高度定制化的场景交给file_sdPrometheus 的哲学是对无限变化的事物提供一个通用机制与 alertmanager webhook、remote read/write、node_exporter textfile collector 一脉相承。凡是需要对接关系型数据库等极端定制逻辑的场景一律推荐通过file_sd接入像 Chef 这类配置管理系统惯用做法也是用其模板能力把目标写成一个文件再交给file_sd读取。VictoriaMetrics 延续了这一约定file_sd_configs是配置解析中的一等公民其实现定义在 lib/promscrape/config.go// FileSDConfig represents file-based service discovery config. type FileSDConfig struct { Files []string yaml:files // refresh_interval is ignored. See -promscrape.fileSDCheckInterval }即file_sd只需声明files文件列表支持 glob刷新周期由-promscrape.fileSDCheckInterval统一控制配置加载时通过getFileSDScrapeWorklib/promscrape/config.go把每个文件中的 target 展开成 ScrapeWork。三、从 SD 到 Prometheus 的元数据映射模型SD 的通用原则是把发现机制中所有可能有用的信息都提取出来具体取舍交给用户用 relabeling 决定。这些信息统称为 metadata元数据。3.1 标签命名与暴露约定元数据以 key/value标签形式暴露在目标上key 统一加前缀__meta_sdname_key每个目标必须有一个__address__标签值为host:port优先使用 IP 地址以避免 DNS 解析除上述两类标签外不应暴露其他标签名。VictoriaMetrics 对这套模型有完整落地。以 Consul 为例其配置结构见 lib/promscrape/discovery/consul/consul.go而每个发现目标可用的元数据标签完整列出在 docs/victoriametrics/sd_configs.md包括__meta_consul_address、__meta_consul_dc、__meta_consul_health、__meta_consul_tag_tagname等所有 SD 的 meta 标签在 relabeling 完成后会被清理——lib/promscrape/config.go 的注释明确指出Remove labels starting from__meta_prefix这正对应本文开头提到的生命周期约定。3.2 数组、映射与多端口目标的规范化数组合并成单个标签值以逗号分隔并在首尾也加上逗号。例如[a, b, c]变成,a,b,c,。由于 relabeling 正则默认全量锚定这种写法让.*,a,.*无论a出现在列表何处都能正确匹配。规范范例是__meta_consul_tags。映射/哈希key/value 对全部加前缀暴露为标签。例如 EC2 的 tag 会产生__meta_ec2_tag_Descriptionmydescription。标签名只允许[_a-zA-Z0-9]非法字符须替换为下划线。多端口目标a) 暴露为列表b) 具名端口暴露为映射c) 每个端口各自作为独立 target。Kubernetes SD 采用每端口一目标的方式a) 与 b) 可以组合。机器型 SDOpenStack、EC2部分程度上的 Kubernetes可能有多块网卡目前只上报第一块/主网卡的信息即可。3.3 其他实现考量全量倾倒 可选过滤SD 的设计意图是把所有可能的目标全部给出例如 EC2 SD 的典型用法是把整个 region 的实例一次拿回在一个scrape_config内完成所有工作。当规模很大而只关心其中一小部分时允许利用 SD 自身机制提供过滤如 EC2DescribeInstances的Filter但要意识到这仅是性能优化——同样的过滤必须能用 relabeling 独立完成Prometheus 不为发明新的目标过滤方式只透传 SD 自带的功能。配置必须全部来自配置文件SD 实现不应通过读取环境变量或文件来获取配置EC2 的 SDK 依赖环境变量即是一个反例警示。VictoriaMetrics 的各 SD 配置同样遵循此约定配置字段内联HTTPClientConfig、ProxyClientConfig等统一结构。警惕速率限制有些 SD 的 API 速率限制低到无法实用文档中明确提到 Amazon ECS 因此被拒。多类型 SD 的选择若一个系统提供多种不同类型的 SD应用配置项选择当前使用哪一种而不是用一个大杂烩 SD返回全部再靠 relabeling 挑拣目前只有 Kubernetes 出现这种情况。失败即中止与 SD 通信失败时应中止而非返回部分数据宁可基于陈旧目标工作也不要基于残缺/错误元数据工作。不返回敏感信息SD 获得的信息在安全上不被视为敏感但绝不能在 metadata 中返回密钥——任何能访问 Prometheus 服务的人都能看到它们。四、编写一个 SD 机制Discoverer 接口与 TargetGroup4.1 数据载体targetgroup.GroupSD 发现的相似目标会被分组以 target group 列表的形式下发给 Prometheus。其定义在 vendor/github.com/prometheus/prometheus/discovery/targetgroup/targetgroup.go// Group is a set of targets with a common label set(production , test, staging etc.). type Group struct { // Targets is a list of targets identified by a label set. Each target is // uniquely identifiable in the group by its address label. Targets []model.LabelSet // Labels is a set of labels that is common across all targets in the group. Labels model.LabelSet // Source is an identifier that describes a group of targets. Source string }可以看到Group由三部分组成Targets每个目标一个 LabelSet、Labels组内所有目标共有的标签如job、Source组标识符。同一 SD 实例发出的所有 target group 的Source必须全局唯一——它是 Manager 追踪增删改的钥匙。4.2 核心接口Discoverer一个 SD 机制必须实现Discoverer接口定义在 vendor/github.com/prometheus/prometheus/discovery/discovery.go// Discoverer provides information about target groups. It maintains a set // of sources from which TargetGroups can originate. Whenever a discovery provider // detects a potential change, it sends the TargetGroup through its channel. type Discoverer interface { // Run hands a channel to the discovery provider (Consul, DNS, etc.) through which // it can send updated target groups. It must return when the context is canceled. // It should not close the update channel on returning. Run(ctx context.Context, up chan- []*targetgroup.Group) }Prometheus 会调用提供者的Run()来初始化发现机制机制随即把全部target group 发进 channel之后持续监听变化每次更新可以发送全部目标组也可以只发送变化/新增的目标组Manager对两种情况都能处理。4.3 发送语义全量、变更与清空假设某发现机制首次检索得到两个 group一个Source: file1对应 MySQL一个Source: file2对应 Postgres[]targetgroup.Group{ { Targets: []model.LabelSet{ { __instance__: 10.11.150.1:7870, hostname: demo-target-1, test: simple-test, }, { __instance__: 10.11.150.4:7870, hostname: demo-target-2, test: simple-test, }, }, Labels: model.LabelSet{ job: mysql, }, Source: file1, }, { Targets: []model.LabelSet{ { __instance__: 10.11.122.11:6001, hostname: demo-postgres-1, test: simple-test, }, { __instance__: 10.11.122.15:6001, hostname: demo-postgres-2, test: simple-test, }, }, Labels: model.LabelSet{ job: postgres, }, Source: file2, }, }分组方式是实现相关的甚至可以是每目标一组。更新时只需下发发生变化的整个 group。例如demo-postgres-2消失后下发targetgroup.Group{ Targets: []model.LabelSet{ { __instance__: 10.11.122.11:6001, hostname: demo-postgres-1, test: simple-test, }, }, Labels: model.LabelSet{ job: postgres, }, Source: file2, }若某个 group 的所有目标全部消失则下发Targets为空的 group例如所有job: postgres目标都没了targetgroup.Group{ Targets: nil, Source: file2, }这种空 Targets 即删除信号的协议与 lib/promscrape/config.go 中file_sd_configs的空目标处理逻辑相互印证抓取配置会在文件内容变化时重算 ScrapeWork 集合消失的目标随之被移除。五、让 Prometheus 认识你的 SDConfig 接口与注册机制SD 机制准备好之后还必须帮助 Prometheus发现它实现discovery.Config接口并在包内init函数中用discovery.RegisterConfig完成注册。5.1 Config 接口与 DiscovererOptionstype Config interface { // Name returns the name of the discovery mechanism. Name() string // NewDiscoverer returns a Discoverer for the Config // with the given DiscovererOptions. NewDiscoverer(DiscovererOptions) (Discoverer, error) // NewDiscovererMetrics returns the metrics used by the service discovery. NewDiscovererMetrics(prometheus.Registerer, RefreshMetricsInstantiator) DiscovererMetrics } type DiscovererOptions struct { Logger *slog.Logger // A registerer for the Discoverers metrics. Registerer prometheus.Registerer HTTPClientOptions []config.HTTPClientOption }注在当前仓库 vendor 的 discovery.go 中DiscovererOptions还包含Metrics DiscovererMetrics与SetName string字段说明该组件后续版本又补充了指标注册与集合命名能力。Name()的返回值应当简短、具描述性、全小写且唯一它有两个用途作为 Logger 的标签作为该 SD 在scrape_config/alertmanager_config中 YAML 键的一部分即${NAME}_sd_configs。5.2 注册机制的源码实现注册的核心逻辑在 vendor/github.com/prometheus/prometheus/discovery/registry.go// RegisterConfig registers the given Config type for YAML marshaling and unmarshaling. func RegisterConfig(config Config) { registerConfig(config.Name()_sd_configs, reflect.TypeOf(config), config) } func init() { // N.B.: static_configs is the only Config type implemented by default. // All other types are registered at init by their implementing packages. elemTyp : reflect.TypeFor[*targetgroup.Group]() registerConfig(staticConfigsKey, elemTyp, StaticConfig{}) }注意init()中的注释默认只有static_configs一种 Config 类型其余全部由各自实现包在init阶段注册。注册时通过反射动态构造字段使Configs的 YAML 编解码能把形如consul_sd_configs、kubernetes_sd_configs的键自动映射到对应类型见 discovery.go 中Configs.UnmarshalYAML的反射实现。若出现同名注册registerConfig会直接panic从机制上杜绝命名冲突。static_configs同样是一个 Config其Name()返回staticNewDiscoverer返回一个一次性发送全部静态组的 discovererdiscovery.go。VictoriaMetrics 侧对应的静态配置定义在 lib/promscrape/config.go并支持通过文件加载静态目标loadStaticConfigs支持 HTTP 读取与环境模板替换。5.3 Manager接收与同步Manager负责启动各 provider、汇总其 channel 输出并周期性地把最新 target group 集合同步出去。其实现细节见 vendor/github.com/prometheus/prometheus/discovery/manager.go默认以 5 秒updatert为周期把targets快照写入syncCh并维护poolKey{setName, provider}粒度的 provider 生命周期。这意味着 SD 的发现-变更与下游抓取目标重算是解耦的异步流程。六、新增一个 SD 的检查清单原文档给出了一份易踩坑清单逐条对应到 VictoriaMetrics 仓库可以找到实锤DeepEqual 校验把新配置加入config/testdata/conf.good.yml及相关测试确保配置可以被深度比较VictoriaMetrics 侧对应 lib/promscrape/config_test.go 对抓取配置的严格解析测试。目录相关配置若配置直接或间接包含文件路径如 TLSConfig、HTTPClientConfig 字段必须实现config.DirectorySetter以支持-promscrape.config相对路径基准目录的拼接。VictoriaMetrics 中每个 SD 的GetLabels(baseDir string)方法都接收基准目录参数例如 lib/promscrape/discovery/kuma/kuma.go 与 lib/promscrape/discovery/consul/consul.go。从 install 包导入SD 包必须在prometheus/discovery/install中被导入main通过导入 install 包注册全部内置 SD。VictoriaMetrics 的做法异曲同工——所有 SD 实现在 lib/promscrape/config.go 中被统一 import从而进入抓取配置解析器。文档登记在docs/configuration/configuration.md的scrape_config与alertmanager_config两处列出新 SD。VictoriaMetrics 则要求在 docs/victoriametrics/sd_configs.md 中登记并给出配置示例与 meta 标签清单。七、VictoriaMetrics 中的 SD 实现范式从源码结构看VictoriaMetrics 的每个 SD 都遵循一套高度一致的范式可以看作Config 接口思路在抓取器侧的工程化落地SDConfig 结构体声明该 SD 的全部 YAML 字段。例如 Consul 支持server、token、datacenter、namespace、partition、scheme、services、tags、node_meta、filter等lib/promscrape/discovery/consul/consul.goKuma 则只有server与client_idlib/promscrape/discovery/kuma/kuma.go。凡是refresh_interval、fetch_timeout等字段统一注释掉并在注释中说明由命令行 flag 提供。GetLabels(baseDir)返回[]*promutil.Labels把 API 返回的实例/服务信息转换为带__meta_*前缀的标签集合。这是提取全部有用信息原则的直接体现。MustStop()通过configMap.Delete(sdc)释放 API 客户端等资源。SDCheckInterval flag每个 SD 在包内声明一个-promscrape.nameSDCheckIntervalflag例如 Kuma 的-promscrape.kumaSDCheckInterval默认 30s。这与配置来自配置文件原则并行不悖——刷新频率属于部署参数故由命令行统一管理。各 SD 的单元测试文件与实现一一对应如consul_test.go、kubernetes/pod_test.go、ec2/instance_test.go等覆盖了从 API 响应解析到 meta 标签生成的全过程可作为编写新 SD 时的参考样板。八、实战在 vmagent 中启用一个 SD以最简单的file_sd_configs为例演示完整落地路径。配置文件可对照 lib/promscrape/testdata/scrape_config_files/1.yml 与 lib/promscrape/testdata/file_sd_1.ymlscrape_configs: - job_name: job1 static_configs: - targets: [foo, bar]static_configs与file_sd_configs在 lib/promscrape/config.go 中分别通过getStaticScrapeWork与getFileSDScrapeWork展开file-based SD 的目标还会附带__meta_filepath标签lib/promscrape/config.go便于 relabeling 按来源文件区分目标。启用抓取vmagent -promscrape.config/path/to/prometheus.yml \ -remoteWrite.urlhttp://victoria-metrics:8428/api/v1/write单机版 VictoriaMetrics 也可直接抓取不写 remoteWritevictoria-metrics -promscrape.config/path/to/prometheus.yml排障时可用内置的 dry-run 严格校验配置lib/promscrape/config.go 中的定义说明vmagent -promscrape.config/path/to/prometheus.yml -promscrape.config.dryRuntrue若希望静默跳过不支持字段而非报错可将-promscrape.config.strictParse设为false。各类 SD 的具体配置字段与 meta 标签均以 docs/victoriametrics/sd_configs.md 与 docs/victoriametrics/relabeling.md 为准。结语Service Discovery 的价值在于把基础设施里已有的发现能力翻译成统一的__meta_*标签模型从而让 relabeling 成为唯一的目标加工入口。理解了Discoverer/Config两个接口与 target group 的增量协议就能判断一个机制是否适合做成 SD、以及如何正确地把它集成进 Prometheus 生态而 VictoriaMetrics 在lib/promscrape/discovery/下 20 余个 SD 的高度一致实现则为按规范编写新 SD提供了可直接参考的工程范本。【免费下载链接】VictoriaMetricsVictoriaMetrics: fast, cost-effective monitoring solution and time series database项目地址: https://gitcode.com/GitHub_Trending/vi/VictoriaMetrics创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表