# node-exporter

## 概述 <a href="#gai-shu" id="gai-shu"></a>

Prometheus从2016年加入CNCF，到2018年8月毕业，现在已经成为Kubernetes的官方监控方案，接下来的几篇文章将详细解读Promethues(2.x)

Prometheus可以从Kubernetes集群的各个组件中采集数据，比如kubelet中自带的cadvisor，api-server等，而node-export就是其中一种来源

Exporter是Prometheus的一类数据采集组件的总称。它负责从目标处搜集数据，并将其转化为Prometheus支持的格式。与传统的数据采集组件不同的是，它并不向中央服务器发送数据，而是等待中央服务器主动前来抓取，默认的抓取地址为[http://CURRENT\_IP:9100/metrics](http://current_ip:9100/metrics)​

node-exporter用于采集服务器层面的运行指标，包括机器的loadavg、filesystem、meminfo等基础监控，类似于传统主机监控维度的zabbix-agent

node-export由prometheus官方提供、维护，不会捆绑安装，但基本上是必备的exporter

## 功能 <a href="#gong-neng" id="gong-neng"></a>

node-exporter用于提供\*NIX内核的硬件以及系统指标。

* 如果是windows系统，可以使用[WMI exporter](https://github.com/martinlindhe/wmi_exporter)​
* 如果是采集NVIDIA的GPU指标，可以使用[prometheus-dcgm](https://github.com/NVIDIA/gpu-monitoring-tools/tree/master/exporters/prometheus-dcgm) ​

根据不同的\*NIX操作系统，node-exporter采集指标的支持也是不一样的，如：

* diskstats 支持 Darwin, Linux
* cpu 支持Darwin, Dragonfly, FreeBSD, Linux, Solaris等，

详细信息参考：[node\_exporter](https://github.com/prometheus/node_exporter)​

我们可以使用 --collectors.enabled参数指定node\_exporter收集的功能模块,或者用--no-collector指定不需要的模块，如果不指定，将使用默认配置。

## 部署 <a href="#bu-shu" id="bu-shu"></a>

#### 二进制部署： <a href="#er-jin-zhi-bu-shu" id="er-jin-zhi-bu-shu"></a>

* 下载地址：从[https://github.com/prometheus/node\_exporter/releases](https://github.com/prometheus/node_exporter/releases)​
* 解压文件：tar -xvzf _\*\*_.tar.gz
* 开始运行：./node\_exporter

./node\_exporter -h 查看帮助

```
usage: node_exporter [<flags>]
​
Flags:
  -h, --help
  --collector.diskstats.ignored-devices
  --collector.filesystem.ignored-mount-points
  --collector.filesystem.ignored-fs-types      
  --collector.netdev.ignored-devices      
  --collector.netstat.fields      
  --collector.ntp.server="127.0.0.1"
  .....
```

./node\_exporter运行后，可以访问[http://${IP}:9100/metrics，就会展示对应的指标列表](http://${ip}:9100/metrics%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%B1%95%E7%A4%BA%E5%AF%B9%E5%BA%94%E7%9A%84%E6%8C%87%E6%A0%87%E5%88%97%E8%A1%A8)​

#### Docker安装： <a href="#docker-an-zhuang" id="docker-an-zhuang"></a>

```
docker run -d \
  --net="host" \
  --pid="host" \
  -v "/:/host:ro,rslave" \
  quay.io/prometheus/node-exporter \
  --path.rootfs /host
```

#### k8s中安装： <a href="#k-8szhong-an-zhuang" id="k-8szhong-an-zhuang"></a>

node-exporter.yaml文件：

```
apiVersion: v1
kind: Service
metadata:
  annotations:
    prometheus.io/scrape: 'true'
  labels:
    app: node-exporter
    name: node-exporter
  name: node-exporter
spec:
  clusterIP: None
  ports:
  - name: scrape
    port: 9100
    protocol: TCP
  selector:
    app: node-exporter
  type: ClusterIP
----
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: node-exporter
spec:
  template:
    metadata:
      labels:
        app: node-exporter
      name: node-exporter
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/tryk8s/node-exporter:latest
        name: node-exporter
        ports:
        - containerPort: 9100
          hostPort: 9100
          name: scrape
      hostNetwork: true
      hostPID: true
```

kubectl create -f node-exporter.yaml

得到一个daemonset和一个service对象，部署后，为了能够让Prometheus能够从当前node exporter获取到监控数据，这里需要修改Prometheus配置文件。编辑prometheus.yml并在scrape\_configs节点下添加以下内容:

```
scrape_configs:
  # 采集node exporter监控数据
  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']
```

也可以使用`prometheus.io/scrape: 'true'`标识来自动获取service的metric接口

```
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
```

配置完成后，重启prometheus就能看到对应的指标

#### 查看指标： <a href="#cha-kan-zhi-biao" id="cha-kan-zhi-biao"></a>

**直接查看：**

如果是二进制或者docker部署，部署成功后可以访问：[http://${IP}:9100/metrics](http://${ip}:9100/metrics)​

会输出下面格式的内容，包含了node-exporter暴露的所有指标：

```
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 6.1872e-05
go_gc_duration_seconds{quantile="0.25"} 0.000119463
go_gc_duration_seconds{quantile="0.5"} 0.000151156
go_gc_duration_seconds{quantile="0.75"} 0.000198764
go_gc_duration_seconds{quantile="1"} 0.009889647
go_gc_duration_seconds_sum 0.257232201
go_gc_duration_seconds_count 1187
```

```
# HELP node_cpu Seconds the cpus spent in each mode.
# TYPE node_cpu counter
node_cpu{cpu="cpu0",mode="guest"} 0
node_cpu{cpu="cpu0",mode="guest_nice"} 0
node_cpu{cpu="cpu0",mode="idle"} 68859.19
node_cpu{cpu="cpu0",mode="iowait"} 167.22
node_cpu{cpu="cpu0",mode="irq"} 0
node_cpu{cpu="cpu0",mode="nice"} 19.92
node_cpu{cpu="cpu0",mode="softirq"} 17.05
node_cpu{cpu="cpu0",mode="steal"} 28.1
```

**Prometheus查看：**

类似go\_gc\_duration\_seconds和node\_cpu就是metric的名称，如果使用了Prometheus,则可以在[http://${IP}:9090/页面的指标中搜索到以上的指标：](http://${ip}:9090/%E9%A1%B5%E9%9D%A2%E7%9A%84%E6%8C%87%E6%A0%87%E4%B8%AD%E6%90%9C%E7%B4%A2%E5%88%B0%E4%BB%A5%E4%B8%8A%E7%9A%84%E6%8C%87%E6%A0%87%EF%BC%9A)​

![](http://www.xuyasong.com/wp-content/uploads/2019/01/15479529862683.jpg)

![](http://www.xuyasong.com/wp-content/uploads/2019/01/15479529681146.jpg)

常用指标类型有：

```
node_cpu：系统CPU使用量
node_disk*：磁盘IO
node_filesystem*：文件系统用量
node_load1：系统负载
node_memeory*：内存使用量
node_network*：网络带宽
node_time：当前系统时间
go_*：node exporter中go相关指标
process_*：node exporter自身进程相关运行指标
```

**Grafana查看：**

Prometheus虽然自带了web页面，但一般会和更专业的Grafana配套做指标的可视化，Grafana有很多模板，用于更友好地展示出指标的情况，如[Node Exporter for Prometheus](https://grafana.com/dashboards/8919)​

![](http://www.xuyasong.com/wp-content/uploads/2019/01/15479532586518.jpg)

在grafana中配置好变量、导入模板就会有上图的效果。

## 深入解读 <a href="#shen-ru-jie-du" id="shen-ru-jie-du"></a>

node-exporter是Prometheus官方推荐的exporter，类似的还有

* ​[HAProxy exporter](https://github.com/prometheus/haproxy_exporter)​
* ​[Collectd exporter](https://github.com/prometheus/collectd_exporter)​
* ​[SNMP exporter](https://github.com/prometheus/snmp_exporter)​
* ​[MySQL server exporter](https://github.com/prometheus/mysqld_exporter)​
* ....

官方推荐的都会在[https://github.com/prometheus下，在\[exporter推荐页\](https://prometheus.io/docs/instrumenting/exporters/)，也会有很多第三方的exporter，由个人或者组织开发上传，如果有自定义的采集需求，可以自己编写\[exporter\](https://prometheus.io/docs/instrumenting/writing\_exporters/)，具体的案例可以参考后续的\[自定义Exporter\]文章](https://github.com/prometheus%E4%B8%8B%EF%BC%8C%E5%9C%A8\[exporter%E6%8E%A8%E8%8D%90%E9%A1%B5]\(https://prometheus.io/docs/instrumenting/exporters/\)%EF%BC%8C%E4%B9%9F%E4%BC%9A%E6%9C%89%E5%BE%88%E5%A4%9A%E7%AC%AC%E4%B8%89%E6%96%B9%E7%9A%84exporter%EF%BC%8C%E7%94%B1%E4%B8%AA%E4%BA%BA%E6%88%96%E8%80%85%E7%BB%84%E7%BB%87%E5%BC%80%E5%8F%91%E4%B8%8A%E4%BC%A0%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%89%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E9%87%87%E9%9B%86%E9%9C%80%E6%B1%82%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%B7%B1%E7%BC%96%E5%86%99\[exporter]\(https://prometheus.io/docs/instrumenting/writing_exporters/\)%EF%BC%8C%E5%85%B7%E4%BD%93%E7%9A%84%E6%A1%88%E4%BE%8B%E5%8F%AF%E4%BB%A5%E5%8F%82%E8%80%83%E5%90%8E%E7%BB%AD%E7%9A%84\[%E8%87%AA%E5%AE%9A%E4%B9%89Exporter]%E6%96%87%E7%AB%A0)​

### 版本问题 <a href="#ban-ben-wen-ti" id="ban-ben-wen-ti"></a>

因为node\_exporter是比较老的组件，有一些最佳实践并没有merge进去，比如符合Prometheus命名规范([https://prometheus.io/docs/practices/naming/),因此建议使用较新的0.16和0.17版本，目前(2019.1)最新版本为0.17](https://prometheus.io/docs/practices/naming/\),%E5%9B%A0%E6%AD%A4%E5%BB%BA%E8%AE%AE%E4%BD%BF%E7%94%A8%E8%BE%83%E6%96%B0%E7%9A%840.16%E5%92%8C0.17%E7%89%88%E6%9C%AC%EF%BC%8C%E7%9B%AE%E5%89%8D\(2019.1\)%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%E4%B8%BA0.17)​

一些指标名字的变化（[详细比对](https://github.com/prometheus/node_exporter/tree/master/docs)）

```
* node_cpu ->  node_cpu_seconds_total
* node_memory_MemTotal -> node_memory_MemTotal_bytes
* node_memory_MemFree -> node_memory_MemFree_bytes
* node_filesystem_avail -> node_filesystem_avail_bytes
* node_filesystem_size -> node_filesystem_size_bytes
* node_disk_io_time_ms -> node_disk_io_time_seconds_total
* node_disk_reads_completed -> node_disk_reads_completed_total
* node_disk_sectors_written -> node_disk_written_bytes_total
* node_time -> node_time_seconds
* node_boot_time -> node_boot_time_seconds
* node_intr -> node_intr_total
```

解决版本问题的方法有两种：

* 一是在机器上启动两个版本的node-exporter，都让prometheus去采集。
* 二是使用[指标转换器](https://github.com/prometheus/node_exporter/blob/master/docs/example-16-compatibility-rules.yml),他会将旧指标名称转换为新指标

对于grafana的展示，可以找同时支持两套指标的dashboard模板

### Collector <a href="#collector" id="collector"></a>

node-exporter的主函数：

```
// Package collector includes all individual collectors to gather and export system metrics.
package collector
​
import (
    "fmt"
    "sync"
    "time"
​
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/common/log"
    "gopkg.in/alecthomas/kingpin.v2"
)
​
// Namespace defines the common namespace to be used by all metrics.
const namespace = "node"
```

可以看到exporter的实现需要引入github.com/prometheus/client\_golang/prometheus库，client\_golang是prometheus的官方go库，既可以用于集成现有应用，也可以作为连接Prometheus HTTP API的基础库。

比如定义了基础的数据类型以及对应的方法：

```
Counter：收集事件次数等单调递增的数据
Gauge：收集当前的状态，比如数据库连接数
Histogram：收集随机正态分布数据，比如响应延迟
Summary：收集随机正态分布数据，和 Histogram 是类似的
```

```
switch metricType {
        case dto.MetricType_COUNTER:
            valType = prometheus.CounterValue
            val = metric.Counter.GetValue()
​
        case dto.MetricType_GAUGE:
            valType = prometheus.GaugeValue
            val = metric.Gauge.GetValue()
​
        case dto.MetricType_UNTYPED:
            valType = prometheus.UntypedValue
            val = metric.Untyped.GetValue()
```

client\_golang库的详细解析可以参考：[theory-source-code](https://www.infoq.cn/article/Prometheus-theory-source-code)
