写的 exporter 做个记录,除了业务逻辑不同,模板都是一个,语言是 golang
main 方法
/**
* @Author: xuyasong
* @Description:
* @File: main
* @Version: 1.0.0
* @Date: 2019/2/22
*/
package main
import (
"flag"
"log"
"net/http"
"demo/collector"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
// 命令行参数
listenAddr = flag.String("web.listen-port", "9002", "An port to listen on for web interface and telemetry.")
metricsPath = flag.String("web.telemetry-path", "/metrics", "A path under which to expose metrics.")
metricsNamespace = flag.String("metric.namespace", "bec", "Prometheus metrics namespace, as the prefix of metrics name")
)
func main() {
flag.Parse()
metrics := collector.NewMetrics(*metricsNamespace)
registry := prometheus.NewRegistry()
registry.MustRegister(metrics)
http.Handle(*metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>A Prometheus Exporter</title></head>
<body>
<h1>A Prometheus Exporter</h1>
<p><a href='/metrics'>Metrics</a></p>
</body>
</html>`))
})
log.Printf("Starting Server at http://localhost:%s%s", *listenAddr, *metricsPath)
log.Fatal(http.ListenAndServe(":" + *listenAddr, nil))
}
Collector方法
/**
* @Author: xuyasong
* @Description:
* @File: network
* @Version: 1.0.0
* @Date:
*/
package collector
import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"sync"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
)
type Metrics struct {
metrics map[string]*prometheus.Desc
mutex sync.Mutex
}
func newGlobalMetric(namespace string, metricName string, docString string, labels []string) *prometheus.Desc {
return prometheus.NewDesc(namespace+"_"+metricName, docString, labels, nil)
}
func NewMetrics(namespace string) *Metrics {
return &Metrics{
metrics: map[string]*prometheus.Desc{
"pod_network_receive_bytes": newGlobalMetric(namespace, "pod_network_receive_bytes", "network receive bytes of pod ", []string{"pod_name", "namespace", "node_name"}),
}
}
/**
* 接口:Describe
* 功能:传递结构体中的指标描述符到channel
*/
func (c *Metrics) Describe(ch chan<- *prometheus.Desc) {
for _, m := range c.metrics {
ch <- m
}
}
/**
* 接口:Collect
* 功能:抓取最新的数据,传递给channel
*/
func (c *Metrics) Collect(ch chan<- prometheus.Metric) {
c.mutex.Lock() // 加锁
defer c.mutex.Unlock()
// do something ,add metric to channel
ch <- prometheus.MustNewConstMetric(c.metrics["pod_network_receive_bytes"], prometheus.CounterValue, 0, pod.podName, pod.namespace, hostname)
}
部署
Dockerfile
FROM nginx:stable-alpine
MAINTAINER xuyasong
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN mkdir -p /opt/bin && chown -R root:root /opt \
&& apk update&&apk add --no-cache wget curl less util-linux
COPY bin/demo-exporter /opt/bin/demo-exporter
COPY scripts /opt/bin/scripts
CMD ["/opt/bin/scripts/entrypoint.sh"]
entrypoint.sh
#!/bin/sh
cd /opt
mkdir -p log
chmod 755 log
bin/demo-exporter 2>>log/demo-exporter.log
deployment部署:
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: demo-exporter
namespace: monitor
labels:
k8s-app: demo-exporter
spec:
selector:
matchLabels:
k8s-app: demo-exporter
template:
metadata:
labels:
k8s-app: demo-exporter
annotations:
"prometheus.io/scrape": "true"
spec:
containers:
- name: demo-exporter
image: demo-exporter
imagePullPolicy: Always
resources:
limits:
cpu: "1"
memory: "500Mi"
requests:
cpu: "1"
memory: "200Mi"
securityContext:
privileged: true
volumeMounts:
- mountPath: /opt/log
name: demo-exporter-log
volumes:
- hostPath:
path: /var/demo-exporter
name: demo-exporter-log
---
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: "true"
labels:
k8s-app: demo-exporter
name: demo-exporter
namespace: monitor
spec:
ports:
- name: http-metrics
port: 9006
protocol: TCP
targetPort: 9006
selector:
k8s-app: demo-exporter
type: ClusterIP
说点什么
1 评论 在 "Prometheus自定义exporter"
[…] 还有各种场景下的自定义 exporter,如日志提取后面会再做介绍。 […]