victoriaMetrics无法获取抓取target的问题

问题描述

最近在新环境中部署了一个服务,其暴露的指标路径为:10299/metrics,配置文件如下(名称字段有修改):

apiVersion: v1
items:
- apiVersion: operator.victoriametrics.com/v1beta1
kind: VMServiceScrape
metadata:
labels:
app_id: audit
name: audit
namespace: default
spec:
endpoints:
- path: /metrics
targetPort: 10299
namespaceSelector:
matchNames:
- default
selector:
matchLabels:
app_id: audit

但在vmagent上查看其状态如下,vmagent无法发现该target:

一般排查方式

  1. 确保服务本身没问题,可以通过${podIp}:10299/metrics访问到指标
  2. 确保vmservicescrape-->service-->enpoints链路是通的,即配置的selector字段能够正确匹配到对应的资源
  3. 确保vmservicescrape格式正确。注:vmservicescrape资源格式不正确可能会导致vmagent无法加载配置,可以通过第5点检测到
  4. 确保vmagent中允许发现该命名空间中的target
  5. 在vmagent的UI界面执行reload,查看vmagent的日志是否有相关错误提示

经过排查发现上述方式均无法解决问题,更奇怪的是在vmagent的api/v1/targets中无法找到该target,说明vmagent压根没有发现该服务,即vmservicescrape配置没有生效。在vmagent中查看上述vmservicescrape生成的配置文件如下(其拼接了静态配置),可以看到它使用了kubernetes_sd_configs的方式来发现target:

- job_name: serviceScrape/default/audit/0
metrics_path: /metrics
relabel_configs:
- source_labels: [__meta_kubernetes_service_label_app_id]
regex: audit
action: keep
- source_labels: [__meta_kubernetes_pod_container_port_number]
regex: "10299"
action: keep
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
target_label: node
regex: Node;(.*)
replacement: ${1}
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
target_label: pod
regex: Pod;(.*)
replacement: ${1}
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
- source_labels: [__meta_kubernetes_pod_container_name]
target_label: container
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_service_name]
target_label: service
- source_labels: [__meta_kubernetes_service_name]
target_label: job
replacement: ${1}
- target_label: endpoint
replacement: "8080"
kubernetes_sd_configs:
- role: endpoints
namespaces:
own_namespace: false
names:
- default

代码分析

既然配置没有问题,那只能通过victoriametrics的kubernetes_sd_configs的运作方式看下到底是哪里出问题了。在victoriametrics的源码可以看到其拼接的target url如下:

scrapeURL := fmt.Sprintf("%s://%s%s%s%s", schemeRelabeled, addressRelabeled, metricsPathRelabeled, optionalQuestion, paramsStr)

其中:

  • schemeRelabeled:默认是http
  • metricsPathRelabeled:即生成的配置文件的metrics_path字段
  • optionalQuestionparamsStr没有配置,可以忽略

最主要的字段就是addressRelabeled,它来自一个名为"__address__"的标签

func mergeLabels(swc *scrapeWorkConfig, target string, extraLabels, metaLabels map[string]string) []prompbmarshal.Label {
...
m["job"] = swc.jobName
m["__address__"] = target
m["__scheme__"] = swc.scheme
m["__metrics_path__"] = swc.metricsPath
m["__scrape_interval__"] = swc.scrapeInterval.String()
m["__scrape_timeout__"] = swc.scrapeTimeout.String()
...
}

继续跟踪代码,可以看到该标签是通过sc.KubernetesSDConfigs[i].MustStart获取到的,从KubernetesSDConfigs的名称上看,它就是负责处理kubernetes_sd_configs机制的:

func (sc *ScrapeConfig) mustStart(baseDir string) {
swosFunc := func(metaLabels map[string]string) interface{} {
target := metaLabels["__address__"]
sw, err := sc.swc.getScrapeWork(target, nil, metaLabels)
if err != nil {
logger.Errorf("cannot create kubernetes_sd_config target %q for job_name %q: %s", target, sc.swc.jobName, err)
return nil
}
return sw
}
for i := range sc.KubernetesSDConfigs {
sc.KubernetesSDConfigs[i].MustStart(baseDir, swosFunc)
}
}

继续往下看,看看这个"__address__"字段到底是什么,函数调用如下:

MustStart --> cfg.aw.mustStart --> aw.gw.startWatchersForRole --> uw.reloadScrapeWorksForAPIWatchersLocked --> o.getTargetLabels

最后一个函数getTargetLabels是个接口方法

type object interface {
key() string // getTargetLabels must be called under gw.mu lock.
getTargetLabels(gw *groupWatcher) []map[string]string
}

getTargetLabels的实现如下,这就是kubernetes_sd_configs的各个role的具体实现。上述服务用到的是kubernetes_sd_configsrole为endpoints

实现如下:

func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []map[string]string {
var svc *Service
if o := gw.getObjectByRoleLocked("service", eps.Metadata.Namespace, eps.Metadata.Name); o != nil {
svc = o.(*Service)
}
podPortsSeen := make(map[*Pod][]int)
var ms []map[string]string
for _, ess := range eps.Subsets {
for _, epp := range ess.Ports {
ms = appendEndpointLabelsForAddresses(ms, gw, podPortsSeen, eps, ess.Addresses, epp, svc, "true")
ms = appendEndpointLabelsForAddresses(ms, gw, podPortsSeen, eps, ess.NotReadyAddresses, epp, svc, "false")
}
}
// See https://kubernetes.io/docs/reference/labels-annotations-taints/#endpoints-kubernetes-io-over-capacity
// and https://github.com/kubernetes/kubernetes/pull/99975
switch eps.Metadata.Annotations.GetByName("endpoints.kubernetes.io/over-capacity") {
case "truncated":
logger.Warnf(`the number of targets for "role: endpoints" %q exceeds 1000 and has been truncated; please use "role: endpointslice" instead`, eps.Metadata.key())
case "warning":
logger.Warnf(`the number of targets for "role: endpoints" %q exceeds 1000 and will be truncated in the next k8s releases; please use "role: endpointslice" instead`, eps.Metadata.key())
} // Append labels for skipped ports on seen pods.
portSeen := func(port int, ports []int) bool {
for _, p := range ports {
if p == port {
return true
}
}
return false
}
for p, ports := range podPortsSeen {
for _, c := range p.Spec.Containers {
for _, cp := range c.Ports {
if portSeen(cp.ContainerPort, ports) {
continue
}
addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
m := map[string]string{
"__address__": addr,
}
p.appendCommonLabels(m)
p.appendContainerLabels(m, c, &cp)
if svc != nil {
svc.appendCommonLabels(m)
}
ms = append(ms, m)
}
}
}
return ms
}

可以看到,"__address__"其实就是拼接了p.Status.PodIPcp.ContainerPort,而p则代表一个kubernetes的pod数据结构,因此要求:

  1. pod状态是running的,且能够正确分配到PodIP
  2. p.Spec.Containers[].ports[].ContainerPort中配置了暴露metrics target的端口

问题解决

鉴于上述分析,查看了一下环境中的deployment,发现该deployment只配置了8080端口,并没有配置暴露指标的端口10299。问题解决。

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app_id: audit
name: audit
namespace: default
spec:
...
template:
metadata:
...
spec:
containers:
- env:
- name: APP_ID
value: audit
ports:
- containerPort: 8080
protocol: TCP

victoriaMetrics无法获取抓取target的问题的更多相关文章

  1. python微信聊天机器人改进版,定时或触发抓取天气预报、励志语录等,向好友推送

    最近想着做一个微信机器人,主要想要实现能够每天定时推送天气预报或励志语录,励志语录要每天有自动更新,定时或当有好友回复时,能够随机推送不同的内容.于是开始了分析思路.博主是采用了多线程群发,因为微信对 ...

  2. 使用NodeJs,实现数据抓取

    学习笔记 前言 近期做一个数据抓爬工具,最开始使用的是C#控制台应用,同时正则表达式去过滤数据,看着还行,可每次运行都依附于.net framework很是不爽,于是想整点其他的方法.本人还是比较喜欢 ...

  3. 抓取某东的TT购买记录分析TT购买趋势

    最近学习了一些爬虫技术,想做个小项目检验下自己的学习成果,在逛某东的时候,突然给我推荐一个TT的产品,点击进去浏览一番之后就产生了抓取TT产品,然后进行数据分析,看下那个品牌的TT卖得最好. 本文通过 ...

  4. Python爬虫入门教程 30-100 高考派大学数据抓取 scrapy

    1. 高考派大学数据----写在前面 终于写到了scrapy爬虫框架了,这个框架可以说是python爬虫框架里面出镜率最高的一个了,我们接下来重点研究一下它的使用规则. 安装过程自己百度一下,就能找到 ...

  5. Android登录client,验证码的获取,网页数据抓取与解析,HttpWatch基本使用

    大家好,我是M1ko.在互联网时代的今天,假设一个App不接入互联网.那么这个App一定不会有长时间的生命周期,因此Android网络编程是每个Android开发人员必备的技能.博主是在校大学生,自学 ...

  6. httpWebRequest获取流和WebClient的文件抓取

    httpWebRequest获取流和WebClient的文件抓取 昨天写一个抓取,遇到了一个坑,就是在获取网络流的时候,人为的使用了stream.Length来获取流的长度,获取的时候会抛出错误,查了 ...

  7. 抓取oracle建表语句及获取建表ddl语句

    抓取oracle建表语句及获取建表ddl语句 1.抓取代码如下: 1.1.产生表的语法资料 DECLARE-- v_notPartTable VARCHAR2(1000):= '&2'; -- ...

  8. 网络抓取功能实现 将获取的结果进行过滤并写入到TXT文档中

    下面是自己编写的 网络抓取功能实现 将获取的结果进行过滤并写入到TXT文档中 (以防忘记) 原创哟 import java.io.BufferedReader;import java.io.Buffe ...

  9. PHP获取cookie、Token、模拟登录、抓取数据、解析生成json

    本文介绍使用PHP获取cookie,获取Token.以及模拟登录.然后抓取数据.最后解析生成json的的过程. 0. 设置Cookie路径 set_time_limit(0); //使用的cookie ...

随机推荐

  1. 《自动控制原理》个人笔记(来自ppt课件)

    控制的含义 控制(CONTROL)----某个主体使某个客体按照一定的目的动作.主体–人:人工控制: 机器:自动控制客体–指一件物体,一套装置,一个物化过程,一个特定系统. 人工控制与自动控制 人在控 ...

  2. MATLAB与Carsim联合仿真时提示matlab not found的解决方法(CarSim在联合仿真时提示找不到MATLAB的解决方法)

    CarSim8.02并没有提供选择联合仿真的MATLAB/Simulink的版本的功能,CarSim总是与最后安装的MATLAB/Simulink进行联合仿真,如果安装有多个matlab版本则只打开最 ...

  3. 总结一下各种0.5px的线

    在PC端用1px的边框线,看起来还好,但在手机端看起来就很难看了,而0.5px的分割线会有种精致的感觉.用普通写法border:solid 0.5px red;iPhone可以正常显示,android ...

  4. ES6-11学习笔记--类与继承

    ES5 中的类与继承: 类的定义: function People(name, age) { // this指向当前实例化对象 console.log(this); // 实例属性 this.name ...

  5. python-统计字符个数

    输入一个字符串,统计其中数字字符及小写字符的个数 输入格式: 输入一行字符串 输出格式: 共有?个数字,?个小写字符 输入样例: helo134ss12 输出样例: 共有5个数字,6个小写字符 代码: ...

  6. sparksql Seq生成DataFrame

    首先,使用样例类: case class User(id:Int,name: String,gender:String, age: Int) 之后使用Seq创建Dataframe val alice: ...

  7. 【每日日报】第三十四天---Scanner类的应用

    1 今天继续看书 Scanner类的应用 1 package File; 2 import java.util.Scanner; 3 4 public class ScannerDemo { 5 pu ...

  8. Spring框架技术

    Spring框架技术 SSM(Spring+SpringMVC+Mybatis)阶段的学习,也算是成功出了Java新手村. 前面我们已经学习过Mybatis了. 从这里开始,很多的概念理解起来就稍微有 ...

  9. Unity中制作血条2.0

    ##1.血量显示 不必像之前那样添加Slider组件 直接创建Image 在添加Source Image之后,将Image Type 修改为Filled 通过修改Fill Mode就可以显示不同效果 ...

  10. [资源] 桃宝上十几块买的C#教程网盘

    我粗略的看了下觉得挺好的,分享给大家 链接:https://pan.baidu.com/s/1iHuLUXde4_L7NB-Zw9JWNg 提取码:1314