一、服务部分

1.添加依赖

        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2.spring-boot application.yaml中配置

management:
  endpoint:
    prometheus:
      enabled: true
  endpoints:
    web:
      exposure:
        include: 'prometheus'

3. 注册bean,修改可见指标

    @Bean
    MeterRegistryCustomizer<MeterRegistry> metricsConfig() {
        return registry -> registry.config().meterFilter(new PrometheusMeterFilter());
    }

    static class PrometheusMeterFilter implements MeterFilter {
        @Override
        public MeterFilterReply accept(Meter.Id id) {
            //此判断条件自定义,可用name来标识,如果不自定义,会将一些spring的指标给返回
            if (id.getName().contains("")) { 
                return MeterFilterReply.NEUTRAL;
            }
            return MeterFilterReply.DENY;
        }
    }

4.注册指标

    @Autowired
    private MeterRegistry registry;
    
    public void regist(){
        //ToDoubleFunction 中泛型可以自定义,对应第二个参数的类型
        Gauge.builder("name", "", value -> {
            //此方法在每次prometheus主动调用该服务的指标接口时调用, /actuator/prometheus
            return 0;
        }).tags(Tags.empty()).register(registry);
    }

二、自定义prometheus容器镜像

1.编写代码实现nacos服务发现文件刷盘


(1)刷盘的json格式

[
	{
		"targets": [
			"192.168.0.002:8080"
		],
		"labels": {}
	},
	{
		"targets": [
			"192.168.0.001:8080"
		],
		"labels": {}
	}
]

(2)代码(此处实现使用go语言,15s每次)

package main

import (
	"encoding/json"
	"fmt"
	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
	"os"
	"strconv"
	"strings"
	"time"
)

type NacosEntity struct {
	Targets []string          `json:"targets"`
	Labels  map[string]string `json:"labels"`
}

//代码可以用任何语言实现,需刷盘到指定文件,以便prometheus读取到
func main() {
	nacos_address := os.Getenv("NACOS_SERVER_ADDRESS")
	namespace := os.Getenv("NACOS_NAMESPACE")
	username := os.Getenv("NACOS_USER")
	password := os.Getenv("NACOS_PASSWORD")
	service_name := os.Getenv("SERVICE_NAME")
	group_name := os.Getenv("GROUP_NAME")
	refresh_rate_str := os.Getenv("REFRESH_RATE")
	if username == "" {
		username = "nacos"
	}
	if password == "" {
		password = "nacos"
	}
	if group_name == "" {
		group_name = "DEFAULT_GROUP"
	}
	if refresh_rate_str == "" {
		refresh_rate_str = "15"
	}
	refresh_rate, err9 := strconv.Atoi(refresh_rate_str)
	if err9 != nil {
		refresh_rate = 15
		fmt.Println("refresh_rate err:", err9)
	}
	clientConfig := constant.ClientConfig{
		NamespaceId:         namespace,
		TimeoutMs:           5000,
		NotLoadCacheAtStart: true,
		LogDir:              "/tmp/nacos/log",
		CacheDir:            "/tmp/nacos/cache",
		LogLevel:            "debug",
		Password:            username,
		Username:            password,
	}
	serverConfigs := make([]constant.ServerConfig, 0)
	url_array := strings.Split(nacos_address, ",")
	for _, node := range url_array {
		ip_port := strings.Split(node, ":")
		port, _ := strconv.ParseUint(ip_port[1], 10, 64)
		serverConfigs = append(serverConfigs, constant.ServerConfig{
			IpAddr:      ip_port[0],
			ContextPath: "/nacos",
			Port:        port,
			Scheme:      "http",
		})
	}
	namingClient, err := clients.NewNamingClient(
		vo.NacosClientParam{
			ClientConfig:  &clientConfig,
			ServerConfigs: serverConfigs,
		},
	)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer namingClient.CloseClient()

	ticker := time.NewTicker(time.Duration(refresh_rate) * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			namingClient.SelectInstances(vo.SelectInstancesParam{})
			instances, err2 := namingClient.SelectAllInstances(vo.SelectAllInstancesParam{
				ServiceName: service_name,
				GroupName:   group_name, // default value is DEFAULT_GROUP
			})
			if err2 != nil {
				fmt.Println(err2)
				continue
			}
			target_array := make([]NacosEntity, 0)
			for _, instance := range instances {
				if instance.Healthy {
					var ta NacosEntity
					ta.Labels = make(map[string]string)
					ip_port := instance.Ip + ":" + strconv.Itoa(int(instance.Port))
					ta.Targets = append(ta.Targets, ip_port)
                    //label中的标签会出现在指标标签中,如果需要,可以自定义添加
					//ta.Labels["ip"] = instance.Ip
					target_array = append(target_array, ta)
				}

			}
			data, err3 := json.Marshal(target_array)
			if err3 != nil {
				fmt.Println("error:", err3)
			} else {
				writeToFile(data)
			}
		}
	}
}

func writeToFile(data []byte) {
	f, err := os.OpenFile("/opt/discovery.json", os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.ModePerm)
	if err != nil {
		fmt.Println("文件打开失败", err)
	}
	defer f.Close()
	f.Write(data)
}

2.prometheus yml配置

global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets:

rule_files:

scrape_configs:
  - job_name: "test-service"
    metrics_path: '/actuator/prometheus'
    scrape_interval: 15s
    file_sd_configs:
      - files: ['/opt/discovery.json']
        refresh_interval: 15s

3. 打包

(1)Dockerfile

FROM 基础镜像
#此基础镜像中需包含prometheus

ENV RETENTTION_TIME=30d

ENV STORAGE_PATH=/data/prometheus

ENV CONFIG_PATH=/opt/prometheus/prometheus.yml

COPY ./prometheus.yml /opt/prometheus/prometheus.yml

COPY ./nacos-prometheus-load /opt/nacos-prometheus-load

COPY ./run.sh /opt/run.sh

RUN chmod +777 /opt/run.sh

WORKDIR /opt

RUN mkdir -p -m 777 /data/prometheus
RUN mkdir -p -m 777 /opt/prometheus

ENTRYPOINT ["sh", "-c", "/opt/run.sh"]

(2)run.sh

/opt/nacos-prometheus-load &  #刷盘程序打包后的程序
/opt/prometheus2481/prometheus --config.file=$CONFIG_PATH --storage.tsdb.retention.time=$RETENTTION_TIME --storage.tsdb.path=$STORAGE_PATH --web.console.libraries=/usr/share/prometheus/console_libraries --web.console.templates=/usr/share/prometheus/consoles --web.enable-lifecycle

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐