前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Prometheus安装与使用

Prometheus安装与使用

作者头像
码客说
发布2022-12-28 15:15:11
1.6K0
发布2022-12-28 15:15:11
举报
文章被收录于专栏:码客码客

前言

Prometheus 是一款基于时序数据库的开源监控告警系统,非常适合Kubernetes集群的监控。Prometheus的基本原理是通过HTTP协议周期性抓取被监控组件的状态,任意组件只要提供对应的HTTP接口就可以接入监控。不需要任何SDK或者其他的集成过程。这样做非常适合做虚拟化环境监控系统,比如VM、Docker、Kubernetes等。输出被监控组件信息的HTTP接口被叫做exporter 。

目前互联网公司常用的组件大部分都有exporter可以直接使用,比如Varnish、Haproxy、Nginx、MySQL、Linux系统信息(包括磁盘、内存、CPU、网络等等)。

Grafana 是一个仪表盘,而仪表盘必然是用来显示数据的。

Grafana 本身并不负责数据层,它只提供了通用的接口,让底层的数据库可以把数据给它。

而我们起的另一个服务,叫 Prometheus (中文名普罗米修斯数据库)则是负责存储和查询数据的。

也就是说,Grafana 每次要展现一个仪表盘的时候,会向 Prometheus 发送一个查询请求。

那么配置里的另一个服务 Prometheus-exporter 又是什么呢?

这个就是你真正监测的数据来源了,Prometheus-exporter 这个服务,会查询你的本地电脑的信息,比如内存还有多少、CPU 负载之类,然后将数据导出至普罗米修斯数据库。

三者的关系

image-20221227104652041
image-20221227104652041

准备工作

在所有节点上安装 ntpdate 工具,并进行时间同步(因为 Prometheus 对时间要求非常严格)

代码语言:javascript
复制
yum -y install ntpdate
/usr/sbin/ntpdate ntp1.aliyun.com

部署Node-Exporter

在部署Prometheus后,发现图像界面的Target中node状态异常,

因为prometheus无法通过 http://192.168.7.101:9100/metrics 接口取到监控数据。

代码语言:javascript
复制
mkdir /opt/apps
cd /root
# 下载地址页面:https://prometheus.io/download/
wget https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-amd64.tar.gz
tar -zxvf node_exporter-1.0.1.linux-amd64.tar.gz -C /data/tools/bigdata/
ln -s /data/tools/bigdata/node_exporter-1.0.1.linux-amd64 /opt/apps/node_exporter

设置用户和组

代码语言:javascript
复制
groupadd -g 9100 monitor
useradd -g 9100 -u 9100 -s /sbin/nologin -M monitor
chown -R monitor:monitor /data/tools/bigdata/node_exporter-1.0.1.linux-amd64

修改配置

代码语言:javascript
复制
vi /usr/lib/systemd/system/node_exporter.service

配置如下

代码语言:javascript
复制
[Unit]
Description=node-exporter service
After=network.target

[Service]
User=monitor
Group=monitor
KillMode=control-group
Restart=on-failure
RestartSec=60
# 启动参数可以使用 /opt/apps/node_exporter/node_exporter --help 查看
ExecStart=/opt/apps/node_exporter/node_exporter --collector.disable-defaults --log.level=error --collector.cpu --collector.meminfo --collector.cpu.info --collector.diskstats --collector.ipvs  --collector.loadavg --collector.netclass

[Install]
WantedBy=multi-user.target

重启服务

代码语言:javascript
复制
systemctl daemon-reload 
systemctl start node_exporter.service
systemctl enable node_exporter.service

这时候就能够访问

http://192.168.7.101:9100/metrics

部署Prometheus

安装与配置

下载

代码语言:javascript
复制
cd /root
# 下载不成功,可以使用浏览器下载,或者多线程下载器。https://prometheus.io/download/
wget https://github.com/prometheus/prometheus/releases/download/v2.22.0-rc.0/prometheus-2.22.0-rc.0.linux-amd64.tar.gz
tar -zxvf prometheus-2.22.0-rc.0.linux-amd64.tar.gz -C /data/tools/bigdata/
ln -s /data/tools/bigdata/prometheus-2.22.0-rc.0.linux-amd64 /opt/apps/prometheus

创建目录

代码语言:javascript
复制
mkdir /data/prometheus

设置用户和组

代码语言:javascript
复制
groupadd prometheus
useradd -g prometheus -s /sbin/nologin -M prometheus
chown -R prometheus:prometheus /data/tools/bigdata/prometheus-2.22.0-rc.0.linux-amd64 /data/prometheus

修改配置

代码语言:javascript
复制
vi /opt/apps/prometheus/prometheus.yml

内容如下

代码语言:javascript
复制
global:
  # 采集周期
  scrape_interval: 60s
  external_labels:
    monitor: 'codelab-monitor'

scrape_configs:
  # prometheus 自身监控
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  
  # node_exporter 监控数据采集 
  - job_name: 'node'
    static_configs:
      - targets:
          - "192.168.7.101:9100"
    relabel_configs:
      - source_labels: [__address__]
        regex: (.+):[0-9]+
        target_label: host

检查配置文件

代码语言:javascript
复制
/opt/apps/prometheus/promtool check config /opt/apps/prometheus/prometheus.yml

成功提示

SUCCESS: 0 rule files found

修改服务

代码语言:javascript
复制
vi /usr/lib/systemd/system/prometheus.service

如下

代码语言:javascript
复制
[Unit]
Description=prometheus
After=network.target 

[Service]
User=prometheus
Group=prometheus
WorkingDirectory=/opt/apps/prometheus
ExecStart=/opt/apps/prometheus/prometheus
[Install]
WantedBy=multi-user.target

启动

代码语言:javascript
复制
systemctl daemon-reload 
systemctl start prometheus.service
systemctl enable prometheus.service

lsof -i:9090

启动 promethues 后,可以通过 9090 端口访问web页面

http://192.168.7.101:9090/

具体的数据:

http://192.168.7.101:9090/metrics

例如输入

代码语言:javascript
复制
node_load1

我们就能看到

image-20221227142345425
image-20221227142345425

使用influxdb

默认情况下 Prometheus 会将采集的数据存储到本机的 /opt/apps/prometheus/data 目录,存储数据的大小受限和扩展不便;

所以这里使用 influxdb 作为后端的数据库来存储数据。

安装influxdb

1)安装

代码语言:javascript
复制
wget https://dl.influxdata.com/influxdb/releases/influxdb-1.7.8.x86_64.rpm
yum -y localinstall influxdb-1.7.8.x86_64.rpm
cp /etc/influxdb/influxdb.conf /etc/influxdb/influxdb.conf.default
systemctl enable --now influxdb

2)验证

代码语言:javascript
复制
influx

创建数据库

代码语言:javascript
复制
# 创建库
create database prometheus;
# 查看库
show databases;
# 使用库
use prometheus;
# 查看表
show measurements;
exit

3)配置 Prometheus 集成 infuxdb

代码语言:javascript
复制
vi /opt/apps/prometheus/prometheus.yml

在最后面添加:

代码语言:javascript
复制
remote_write:
  - url: "http://localhost:8086/api/v1/prom/write?db=prometheus"
remote_read:
  - url: "http://localhost:8086/api/v1/prom/read?db=prometheus"

重启

代码语言:javascript
复制
systemctl restart prometheus

注意:

如果你们 influxdb 配置密码,请参考 官网文档 来进行配置。

重启后,所有的表就都生成了

代码语言:javascript
复制
use prometheus;
select * from node_load1;

就可以看到如下

image-20221227142846407
image-20221227142846407

用户操作

打开连接

代码语言:javascript
复制
influx

创建用户

代码语言:javascript
复制
create user influx with password 'influxdb';

创建一个管理员用户,给他所有权限

代码语言:javascript
复制
create user "admin" with password 'influxdb' with all privileges;

查看用户

代码语言:javascript
复制
show users

修改密码

代码语言:javascript
复制
set password for influx = 'influxdb'

删除用户

代码语言:javascript
复制
drop user admin

Java连接

pom.xml引入相关jar文件,如下:

代码语言:javascript
复制
<!-- 引入influxdb依赖 -->
<dependency>
  <groupId>org.influxdb</groupId>
  <artifactId>influxdb-java</artifactId>
  <version>2.8</version>
</dependency>

influxDB工具类封装:

代码语言:javascript
复制
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.influxdb.InfluxDB;
import org.influxdb.InfluxDB.ConsistencyLevel;
import org.influxdb.InfluxDBFactory;
import org.influxdb.dto.BatchPoints;
import org.influxdb.dto.Point;
import org.influxdb.dto.Point.Builder;
import org.influxdb.dto.Pong;
import org.influxdb.dto.Query;
import org.influxdb.dto.QueryResult;

/**
 * InfluxDB数据库连接操作类
 */

public class InfluxDBConnection {
    // 用户名
    private String username;
    // 密码
    private String password;
    // 连接地址
    private final String openurl;
    // 数据库
    private final String database;
    // 保留策略
    private final String retentionPolicy;

    private InfluxDB influxDB;

    public InfluxDBConnection(
            String username,
            String password,
            String openurl,
            String database,
            String retentionPolicy
    ) {
        this.username = username;
        this.password = password;
        this.openurl = openurl;
        this.database = database;
        this.retentionPolicy = retentionPolicy == null || retentionPolicy.equals("") ? "autogen" : retentionPolicy;
        influxDbBuild();
    }

    public InfluxDBConnection(
            String openurl,
            String database,
            String retentionPolicy
    ) {
        this.openurl = openurl;
        this.database = database;
        this.retentionPolicy = retentionPolicy == null || retentionPolicy.equals("") ? "autogen" : retentionPolicy;
        influxDbBuild();
    }

    /**
     * 创建数据库
     *
     * @param dbName
     */
    @SuppressWarnings("deprecation")
    public void createDB(String dbName) {
        influxDB.createDatabase(dbName);
    }

    /**
     * 删除数据库
     *
     * @param dbName
     */
    @SuppressWarnings("deprecation")
    public void deleteDB(String dbName) {
        influxDB.deleteDatabase(dbName);
    }

    /**
     * 测试连接是否正常
     *
     * @return true 正常
     */
    public boolean ping() {
        boolean isConnected = false;
        Pong pong;
        try {
            pong = influxDB.ping();
            if (pong != null) {
                isConnected = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return isConnected;
    }

    /**
     * 连接时序数据库 ,若不存在则创建
     *
     * @return
     */
    public InfluxDB influxDbBuild() {
        if (influxDB == null) {
            if (username == null || password == null) {
                influxDB = InfluxDBFactory.connect(openurl);
            } else {
                influxDB = InfluxDBFactory.connect(openurl, username, password);
            }

        }
        influxDB.setRetentionPolicy(retentionPolicy);
        influxDB.setLogLevel(InfluxDB.LogLevel.NONE);
        return influxDB;
    }

    /**
     * 创建自定义保留策略
     *
     * @param policyName  策略名
     * @param duration    保存天数
     * @param replication 保存副本数量
     * @param isDefault   是否设为默认保留策略
     */
    public void createRetentionPolicy(String policyName, String duration, int replication, Boolean isDefault) {
        String sql = String.format("CREATE RETENTION POLICY \"%s\" ON \"%s\" DURATION %s REPLICATION %s ", policyName,
                database, duration, replication);
        if (isDefault) {
            sql = sql + " DEFAULT";
        }
        this.query(sql);
    }

    /**
     * 创建默认的保留策略
     * default,保存天数:30天,保存副本数量:1
     * 设为默认保留策略
     */
    public void createDefaultRetentionPolicy() {
        String command = String.format(
                "CREATE RETENTION POLICY \"%s\" ON \"%s\" DURATION %s REPLICATION %s DEFAULT",
                "default",
                database,
                "30d",
                1
        );
        this.query(command);
    }

    /**
     * 查询
     *
     * @param command 查询语句
     * @return
     */
    public QueryResult query(String command) {
        return influxDB.query(new Query(command, database));
    }

    /**
     * 插入
     *
     * @param measurement 表
     * @param tags        标签
     * @param fields      字段
     */
    public void insert(String measurement, Map<String, String> tags, Map<String, Object> fields, long time,
                       TimeUnit timeUnit) {
        Builder builder = Point.measurement(measurement);
        builder.tag(tags);
        builder.fields(fields);
        if (0 != time) {
            builder.time(time, timeUnit);
        }
        influxDB.write(database, retentionPolicy, builder.build());
    }

    /**
     * 批量写入测点
     *
     * @param batchPoints
     */
    public void batchInsert(BatchPoints batchPoints) {
        influxDB.write(batchPoints);
        // influxDB.enableGzip();
        // influxDB.enableBatch(2000,100,TimeUnit.MILLISECONDS);
        // influxDB.disableGzip();
        // influxDB.disableBatch();
    }

    /**
     * 批量写入数据
     *
     * @param database        数据库
     * @param retentionPolicy 保存策略
     * @param consistency     一致性
     * @param records         要保存的数据(调用BatchPoints.lineProtocol()可得到一条record)
     */
    public void batchInsert(final String database, final String retentionPolicy, final ConsistencyLevel consistency,
                            final List<String> records) {
        influxDB.write(database, retentionPolicy, consistency, records);
    }

    /**
     * 删除
     *
     * @param command 删除语句
     * @return 返回错误信息
     */
    public String deleteMeasurementData(String command) {
        QueryResult result = influxDB.query(new Query(command, database));
        return result.getError();
    }

    /**
     * 关闭数据库
     */
    public void close() {
        influxDB.close();
    }

    /**
     * 构建Point
     *
     * @param measurement
     * @param time
     * @param fields
     * @return
     */
    public Point pointBuilder(String measurement, long time, Map<String, String> tags, Map<String, Object> fields) {
        Point point = Point.measurement(measurement).time(time, TimeUnit.MILLISECONDS).tag(tags).fields(fields).build();
        return point;
    }
}

查询数据

InfluxDB支持一次查询多个SQL,SQL之间用逗号隔开即可。

代码语言:javascript
复制
import org.influxdb.dto.QueryResult;

import java.util.List;
import java.util.stream.Collectors;

public class Test {
    public static void main(String[] args) {
        InfluxDBConnection influxDBConnection = new InfluxDBConnection("http://192.168.7.101:8086", "prometheus", null);
        QueryResult results = influxDBConnection
                .query("SELECT * FROM node_load1 order by time desc limit 1000");
        //results.getResults()是同时查询多条SQL语句的返回值,此处我们只有一条SQL,所以只取第一个结果集即可。
        QueryResult.Result oneResult = results.getResults().get(0);
        if (oneResult.getSeries() != null) {
            List<List<Object>> valueList = oneResult
                    .getSeries()
                    .stream()
                    .map(QueryResult.Series::getValues)
                    .collect(Collectors.toList())
                    .get(0);
            if (valueList != null && valueList.size() > 0) {
                System.out.println(valueList.size());
                for (List<Object> value : valueList) {
                    // 数据库中字段1取值
                    String field1 = value.get(0) == null ? null : value.get(0).toString();
                    // 数据库中字段2取值
                    String field2 = value.get(1) == null ? null : value.get(1).toString();
                    System.out.println("field1:"+field1);
                }
            }
        }
    }
}

插入数据

InfluxDB的字段类型,由第一条插入的值得类型决定;tags的类型只能是String型,可以作为索引,提高检索速度。

代码语言:javascript
复制
public static void main(String[] args) {
  InfluxDBConnection influxDBConnection = new InfluxDBConnection(
    "influx", 
    "influxdb", 
    "http://192.168.7.101:8086", 
    "prometheus", 
    null
  );
  Map<String, String> tags = new HashMap<String, String>();
  tags.put("tag1", "标签值");
  Map<String, Object> fields = new HashMap<String, Object>();
  fields.put("field1", "哈哈");
  // 数值型,InfluxDB的字段类型,由第一天插入的值得类型决定
  fields.put("field2", 3.141592657);
  // 时间使用毫秒为单位
  influxDBConnection.insert("表名", tags, fields, System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}

部署Grafana

下载

代码语言:javascript
复制
cd /root
wget https://dl.grafana.com/oss/release/grafana-7.2.1.linux-amd64.tar.gz
tar -zxvf grafana-7.2.1.linux-amd64.tar.gz -C /data/tools/bigdata/
ln -s /data/tools/bigdata/grafana-7.2.1 /opt/apps/grafana

修改配置

代码语言:javascript
复制
cp /opt/apps/grafana/conf/sample.ini /opt/apps/grafana/conf/grafana.ini
vi /opt/apps/grafana/conf/grafana.ini

修改内容如下

代码语言:javascript
复制
[paths]
data = /data/grafana
logs = /opt/logs/grafana
plugins = /opt/apps/grafana/plugins
[log]
mode = file
level = warn

添加用户

代码语言:javascript
复制
groupadd -g 9100 monitor
useradd -g 9100 -u 9100 -s /sbin/nologin -M monitor
mkdir -p /data/grafana /opt/logs/grafana
chown -R monitor:monitor /data/tools/bigdata/grafana-7.2.1 /data/grafana /opt/logs/grafana

修改服务

代码语言:javascript
复制
vi /usr/lib/systemd/system/grafana.service

内容如下

代码语言:javascript
复制
[Unit]
Description=grafana service
After=network.target

[Service]
User=monitor
Group=monitor
KillMode=control-group
Restart=on-failure
RestartSec=60
ExecStart=/opt/apps/grafana/bin/grafana-server -config /opt/apps/grafana/conf/grafana.ini -pidfile /opt/apps/grafana/grafana.pid -homepath /opt/apps/grafana

[Install]
WantedBy=multi-user.target

配置生效与重启

代码语言:javascript
复制
systemctl daemon-reload
systemctl restart grafana.service
systemctl enable grafana.service
netstat -lntp | grep grafana

结果如下

代码语言:javascript
复制
tcp6       0      0 :::3000                 :::*                    LISTEN      1547/grafana-server

访问

http://192.168.7.101:3000/

默认账号密码都是 admin

使用Docker安装

https://github.com/Kalasearch/grafana-tutorial

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 准备工作
  • 部署Node-Exporter
  • 部署Prometheus
    • 安装与配置
      • 使用influxdb
        • 安装influxdb
        • 用户操作
        • Java连接
    • 部署Grafana
    • 使用Docker安装
    相关产品与服务
    对象存储
    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档