主页

采用kube-prometheus方案,架构图如下

图片1.jpg

1.1 安装kube-prometheus

Prometheus-operator:https://github.com/prometheus-operator/prometheus-operator.git

Kube-prometheus:https://github.com/prometheus-operator/kube-prometheus.git

1.1.1 下载安装资源文件

git clone -b release-0.8 --single-branch https://github.com/prometheus-operator/kube-prometheus.git

1.1.2 修改为国内镜像

监控容器

需要修改如下镜像地址,镜像需要提前同步到国内或者内网

[root@k8s-master01 ~]# cd kube-prometheus/manifests && grep -r "image:" .
./alertmanager-alertmanager.yaml:  #image: quay.io/prometheus/alertmanager:v0.21.0
./alertmanager-alertmanager.yaml:  image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/alertmanager:v0.21.0

./blackbox-exporter-deployment.yaml:        #image: quay.io/prometheus/blackbox-exporter:v0.18.0
./blackbox-exporter-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/blackbox-exporter:v0.18.0
./blackbox-exporter-deployment.yaml:        #image: jimmidyson/configmap-reload:v0.5.0
./blackbox-exporter-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/configmap-reload:v0.5.0
./blackbox-exporter-deployment.yaml:        #image: quay.io/brancz/kube-rbac-proxy:v0.8.0
./blackbox-exporter-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/kube-rbac-proxy:v0.8.0

./grafana-deployment.yaml:        #image: grafana/grafana:7.5.4
./grafana-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/grafana:7.5.4

./kube-state-metrics-deployment.yaml:        #image: k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.0.0
./kube-state-metrics-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/kube-state-metrics:v2.0.0
./kube-state-metrics-deployment.yaml:        #image: quay.io/brancz/kube-rbac-proxy:v0.8.0
./kube-state-metrics-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/kube-rbac-proxy:v0.8.0
./kube-state-metrics-deployment.yaml:        #image: quay.io/brancz/kube-rbac-proxy:v0.8.0
./kube-state-metrics-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/kube-rbac-proxy:v0.8.0

./node-exporter-daemonset.yaml:        #image: quay.io/prometheus/node-exporter:v1.1.2
./node-exporter-daemonset.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/node-exporter:v1.1.2
./node-exporter-daemonset.yaml:        #image: quay.io/brancz/kube-rbac-proxy:v0.8.0
./node-exporter-daemonset.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/kube-rbac-proxy:v0.8.0

./prometheus-adapter-deployment.yaml:        #image: directxman12/k8s-prometheus-adapter:v0.8.4
./prometheus-adapter-deployment.yaml:        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/k8s-prometheus-adapter:v0.8.4

./prometheus-prometheus.yaml:  #image: quay.io/prometheus/prometheus:v2.26.0
./prometheus-prometheus.yaml:  image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/prometheus:v2.26.0

Oprator

cd kube-prometheus/manifests/setup
vim prometheus-operator-deployment.yaml
   spec:
      containers:
      - args:
        - --kubelet-service=kube-system/kubelet
        #- --prometheus-config-reloader=quay.io/prometheus-operator/prometheus-config-reloader:v0.47.0
        - --prometheus-config-reloader=registry.cn-qingdao.aliyuncs.com/zz_google_containers/prometheus-config-reloader:v0.47.0
        #image: quay.io/prometheus-operator/prometheus-operator:v0.47.0
        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/prometheus-operator:v0.47.0
        name: prometheus-operator
        ....
        #image: quay.io/brancz/kube-rbac-proxy:v0.8.0
        image: registry.cn-qingdao.aliyuncs.com/zz_google_containers/kube-rbac-proxy:v0.8.0
        name: kube-rbac-proxy
        ......

1.1.3 安装prometheus-operator

cd kube-prometheus/manifests/setup && kubectl create -f .

1.1.4 安装监控资源

cd kube-prometheus/manifests && kubectl create -f .

1.1.5 修改默认serviceMonitor

默认的serviceMonitor资源会有KubeControllerManagerDownKubeSchedulerDown 错误,需要单独提前修改kubernetes-serviceMonitorKubeControllerManager.yamlkubernetes-serviceMonitorKubeScheduler.yaml

  • kubernetes-serviceMonitorKubeControllerManager.yaml

          sourceLabels:
          - __name__
        port: http-metrics #https-metrics修改为http-metrics
        scheme: http #https修改为http
        #tlsConfig:   # 注释跳过tls验证,也可不注释
        #  insecureSkipVerify: true
      jobLabel: app.kubernetes.io/name
      namespaceSelector:
        matchNames:
        - kube-system
      selector:
        matchLabels:
          app.kubernetes.io/name: kube-controller-manager #不需要修改,但之后创建的service需要是这个label
  • kubernetes-serviceMonitorKubeScheduler.yaml

    apiVersion: monitoring.coreos.com/v1
    kind: ServiceMonitor
    metadata:
      labels:
        app.kubernetes.io/name: kube-scheduler
      name: kube-scheduler
      namespace: monitoring
    spec:
      endpoints:
      - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
        interval: 30s
        port: http-metrics # https-metrics改为http-metrics
        scheme: http       # https改为http
        #tlsConfig:         #可注释
        #  insecureSkipVerify: true
      jobLabel: app.kubernetes.io/name
      namespaceSelector:
        matchNames:
        - kube-system
      selector:
        matchLabels:
          app.kubernetes.io/name: kube-scheduler  #不需要修改,但之后创建的service需要是这个label

1.1.6 添加Ingress资源

grafana默认的用户名密码都是admin

为alertmanager-main、grafana、prometheus-k8s Service资源建立Ingress资源

k8s集群需要提前安装ingress,并将域名解析到安装了Ingress的节点

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: monitor-ingresses
  namespace: monitoring
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
    - host: alert.node1.com
      http:
        paths:
          - backend:
              service:
                name: alertmanager-main
                port:
                  number: 9093
            path: /
            pathType: Prefix
    - host: grafana.node1.com
      http:
        paths:
          - backend:
              service:
                name: grafana
                port:
                  number: 3000
            path: /
            pathType: Prefix
    - host: prometheus.node1.com
      http:
        paths:
          - backend:
              service:
                name: prometheus-k8s
                port:
                  number: 9090
            path: /
            pathType: Prefix

1.2 Metrics类型

  • Counter:只增不减的计数器

    例如:http_requests_total、node_cpu等

  • Gauge:可增可减

    例如:主机的cpu、内存、磁盘使用率、当前并发量等

  • Histogram和Summary:用于统计和分析样本的分布情况

    直方图参考如下文档:https://www.cnblogs.com/ryanyangcs/p/11309373.html

1.3 Metrics字段信息说明

metrics接口返回的格式开头

HELP:说明
TYPE:metrics类型
....
alertmanager_alerts_invalid_total{version="v1"}@139383232 0 #存储在prometheus的格式

1.4 PromQL查询语法

详细文档参考:https://fuckcloudnative.io/prometheus/3-prometheus/basics.html

Prometheus 提供了一种功能表达式语言 PromQL,允许用户实时选择和汇聚时间序列数据。表达式的结果可以在浏览器中显示为图形,也可以显示为表格数据,或者由外部系统通过 HTTP API 调用。

1.4.1 表达式语言数据类型

在 Prometheus 的表达式语言中,表达式或子表达式包括以下四种类型之一:

  • 瞬时向量(Instant vector) : 一组时间序列,每个时间序列包含单个样本,它们共享相同的时间戳。也就是说,表达式的返回值中只会包含该时间序列中的最新的一个样本值。而相应的这样的表达式称之为瞬时向量表达式
  • 区间向量(Range vector) :一组时间序列,每个时间序列包含一段时间范围内的样本数据。
  • 标量(Scalar) :一个浮点型的数据值。
  • 字符串(String) :一个简单的字符串值。

根用户输入的表达式返回的数据类型是否合法取决于用例的不同,例如:瞬时向量表达式返回的数据类型是唯一可以直接绘制成图表的数据类型。

1.4.2 字面量

(1) 字符串

字符串可以用单引号、双引号或反引号指定为文字常量。

(2) 标量

标量浮点值可以字面上写成 [-](digits)[.(digits)] 的形式。

1.4.3 时间序列过滤器

(1) 瞬时向量过滤器

瞬时向量过滤器允许在指定的时间戳内选择一组时间序列和每个时间序列的单个样本值。在最简单的形式中,近指定指标(metric)名称。这将生成包含此指标名称的所有时间序列的元素的瞬时向量。

例如:选择指标名称为 prometheus_http_requests_total 的所有时间序列:

prometheus_http_requests_total

可以通过向花括号({})里附加一组标签来进一步过滤时间序列。

例如:选择指标名称为 prometheus_http_requests_totalcode 值为200,job 标签值为 prometheus-k8s 的时间序列:

prometheus_http_requests_total{code="200", job="prometheus-k8s"}

PromQL 还支持用户根据时间序列的标签匹配模式来对时间序列进行过滤,目前主要支持两种匹配模式:完全匹配和正则匹配。总共有以下几种标签匹配运算符:

  • = : 选择与提供的字符串完全相同的标签。
  • != : 选择与提供的字符串不相同的标签。
  • =~ : 选择正则表达式与提供的字符串(或子字符串)相匹配的标签。
  • !~ : 选择正则表达式与提供的字符串(或子字符串)不匹配的标签。

例如:

  • 过滤出具有handler="/login"的label的数据

    http_request_total{handler=~".*login.*"}
  • 剔除某个label

    http_request_total{handler!~".*login.*"}
  • 匹配两个值

    http_request_total{handler=~"/login|/password"}

(2) 区间向量过滤器

区间向量与瞬时向量的工作方式类似,唯一的差异在于在区间向量表达式中我们需要定义时间选择的范围,时间范围通过时间范围选择器 [] 进行定义,以指定应为每个返回的区间向量样本值中提取多长的时间范围。

时间范围通过数字来表示,单位可以使用以下其中之一的时间单位:

  • s - 秒
  • m - 分钟
  • h - 小时
  • d - 天
  • w - 周
  • y - 年

例如:选择在过去 5 分钟内指标名称为 http_requests_totaljob 标签值为 prometheus 的所有时间序列:

http_requests_total{job="prometheus"}[5m]

(3) 时间位移操作

在瞬时向量表达式或者区间向量表达式中,都是以当前时间为基准

http_request_total{} # 瞬时向量表达式,选择当前最新的数据
http_request_total{}[5m] # 区间向量表达式,选择以当前时间为基准,5分钟内的数据

而如果我们想查询,5 分钟前的瞬时样本数据,或昨天一天的区间内的样本数据呢? 这个时候我们就可以使用位移操作,位移操作的关键字为 offset

例如:查询时间过去 5 分钟的 http_requests_total

注意:offset 关键字需要紧跟在选择器({})后面。

http_requests_total offset 5m

1.4.4 操作符

(1) 算术二元运算符

在 Prometheus 系统中支持下面的二元算术运算符:

  • + 加法
  • - 减法
  • * 乘法
  • / 除法
  • %
  • ^ 幂等

例如:查看主机内存总大小(Mi)

node_memory_MemTotal_bytes / 1024 /1024

(2) 布尔运算符

目前,Prometheus 支持以下布尔运算符:

  • == (相等)
  • != (不相等)
  • > (大于)
  • < (小于)
  • >= (大于等于)
  • <= (小于等于)

例如:查看主机内存大于3000Mi的

node_memory_MemTotal_bytes / 1024 /1024 < 3000

(3) 集合运算符

使用瞬时向量表达式能够获取到一个包含多个时间序列的集合,我们称为瞬时向量。 通过集合运算,可以在两个瞬时向量与瞬时向量之间进行相应的集合操作。目前,Prometheus 支持以下集合运算符:

  • and (并且)
  • or (或者)
  • unless (排除)

例如:

查看主机内存小于等于2772Mi 或者 主机内存等于3758.59765625Mi的

node_memory_MemTotal_bytes / 1024 /1024 <= 2772  or node_memory_MemTotal_bytes / 1024 /1024 ==     3758.59765625

查看主机内存大于等于2772Mi,排除主机内存等于3758.59765625Mi的

node_memory_MemTotal_bytes / 1024 /1024 >= 2772  unless node_memory_MemTotal_bytes / 1024 /1024 ==     3758.59765625

(4) 聚合操作

Prometheus 还提供了下列内置的聚合操作符,这些操作符作用域瞬时向量。可以将瞬时表达式返回的样本数据进行聚合,形成一个具有较少样本值的新的时间序列。

  • sum (求和)
  • min (最小值)
  • max (最大值)
  • avg (平均值)
  • stddev (标准差)
  • stdvar (标准差异)
  • count (计数)
  • count_values (对 value 进行计数)
  • bottomk (样本值最小的 k 个元素)
  • topk (样本值最大的k个元素)
  • quantile (分布统计)

例如:

取总共的主机内存:

sum(node_memory_MemTotal_bytes) / 1024^2

根据某个字段进行统计:

sum(http_request_total)  by (statuscode, handler)

取内存最小的主机

min(node_memory_MemTotal_bytes)

取所有主机的内存平均值

avg(node_memory_MemTotal_bytes)

所有http请求计数

count(http_request_total)

对value进行统计计数

count_values("count", node_memory_MemTotal_bytes)

取prometheus请求记录前5条记录,以code和handler分组

topk(5, sum(prometheus_http_requests_total) by (code, handler))

取prometheus请求记录后3条记录,以code和handler分组

bottomk(3, sum(prometheus_http_requests_total) by (code, handler))

取当前数据的中位数

quantile(0.5, prometheus_http_requests_total)

1.4.5 PromQL 常用内置函数

完整的内置函数文档参考:https://fuckcloudnative.io/prometheus/3-prometheus/functions.html

Prometheus 提供了其它大量的内置函数,可以对时序数据进行丰富的处理。某些函数有默认的参数,例如:year(v=vector(time()) instant-vector)。其中参数 v 是一个瞬时向量,如果不提供该参数,将使用默认值 vector(time())。instant-vector 表示参数类型。

increase()

increase(v range-vector) 函数获取区间向量中的第一个和最后一个样本并返回其增长量, 它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如: 查询过去1小时内,prometheus HTTP请求的每秒的增长率

increase(prometheus_http_requests_total{code="200",handler="/alerts",instance="0.0.0.0:9090",job="prometheus"}[1h]) / 3600

rate()

rate(v range-vector) 函数可以直接计算区间向量 v 在时间窗口内平均增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。该函数的返回结果不带有度量指标,只有标签列表。

例如:查询过去1小时内,prometheus HTTP请求的每秒的增长率

rate(prometheus_http_requests_total{code="200",handler="/alerts",instance="0.0.0.0:9090",job="prometheus"}[1h])

irate()

irate(v range-vector) 函数用于计算区间向量的增长率,但是其反应出的是瞬时增长率。irate 函数是通过区间向量中最后两个两本数据来计算区间向量的增长速率,它会在单调性发生变化时(如由于采样目标重启引起的计数器复位)自动中断。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度,通过irate函数绘制的图标能够更好的反应样本数据的瞬时变化状态。

不适合做需要分析长期趋势或者告警规则中使用。

predict_linear()

这个函数一般只用在 Gauge 类型的时间序列上。

predict_linear(v range-vector, t scalar) 函数可以预测时间序列 v 在 t 秒后的值。它基于简单线性回归的方式,对时间窗口内的样本数据进行统计,从而可以对时间序列的变化趋势做出预测。该函数的返回结果不带有度量指标,只有标签列表。

例如,基于 1 小时的样本数据,来预测主机可用磁盘空间的是否在 4 个小时候被占满,可以使用如下表达式:

predict_linear(node_filesystem_files_free{mountpoint="/"}[1h], 4*3600)

absent()

如果样本数据不为空则返回no data,如果为空则返回1。一般用于判断数据是否在正常采集。

absent(v instant-vector),如果传递给它的向量参数具有样本数据,则返回空向量;如果传递的向量参数没有样本数据,则返回不带度量指标名称且带有标签的时间序列,且样本值为1。

当监控度量指标时,如果获取到的样本数据是空的, 使用 absent 方法对告警是非常有用的。

ceil()

ceil(v instant-vector) 将 v 中所有元素的样本值向上四舍五入到最接近的整数。例如:2.79 -> 3

floor()

floor(v instant-vector) 函数与 ceil() 函数相反,将 v 中所有元素的样本值向下四舍五入到最接近的整数。例如:2.79 -> 2

delta()

delta(v range-vector) 的参数是一个区间向量,返回一个瞬时向量。它计算一个区间向量 v 的第一个元素和最后一个元素之间的差值。由于这个值被外推到指定的整个时间范围,所以即使样本值都是整数,你仍然可能会得到一个非整数值。

例如:取8小时之前和现在的磁盘可用空间的差值

delta(node_filesystem_files_free[8h])

sort()

sort(v instant-vector) 函数对向量按元素的值进行升序排序,返回结果:key: value = 度量指标:样本值[升序排列]。

sort_desc()

sort(v instant-vector) 函数对向量按元素的值进行降序排序,返回结果:key: value = 度量指标:样本值[降序排列]。

label_join()

将数据中的一个或多个label的值赋值给一个新label,参数依次为:目标变量、新的label的名、分隔符、被合并的第一个label、被合并的第二个label

label_join(v instant-vector, dst_label string, separator string, src_label_1 string, src_label_2 string, ...) 函数可以将时间序列 v 中多个标签 src_label 的值,通过 separator 作为连接符写入到一个新的标签 dst_label 中。可以有多个 src_label 标签

例如:

label_join(node_filesystem_files_free, "new_label", "-", "instance", "mountpoint")

返回如下

node_filesystem_files_free{container="kube-rbac-proxy", device="/dev/sda1", endpoint="https", fstype="xfs", instance="k8s-master01", job="node-exporter", mountpoint="/boot", namespace="monitoring", new_label="k8s-master01-/boot", pod="node-exporter-ztmr9", service="node-exporter"}

label_replace()

根据数据中的某个label值,进行正则匹配,然后赋值给新label并添加到数据中,参数依次为:目标变量、新的label名字、匹配取出字符的位置、正则匹配目标label值

为了能够让客户端的图标更具有可读性,可以通过 label_replace 函数为时间序列添加额外的标签。label_replace 的具体参数如下:

例如:把label名为instance的为目标,去除-开头的左边的字符,添加到host label中

label_replace(node_filesystem_files_free, "host", "$1", "instance", "(.*)-(.*)")

返回如下

node_filesystem_files_free{container="kube-rbac-proxy", device="/dev/sda1", endpoint="https", fstype="xfs", host="k8s", instance="k8s-master01", job="node-exporter", mountpoint="/boot", namespace="monitoring", pod="node-exporter-ztmr9", service="node-exporter"}

1.5 解决二进制安装k8s集群prometheus schedule和controller监控问题

1.5.1 报错详细

二进制安装的k8s集群,在安装完kube-prometheus后,prometheus中的alter会有如下几个Firing告警,注意需要解决KubeControllerManagerDownKubeSchedulerDown

image.png

1.5.2 报错原因

KubeControllerManagerDown的原因:

  • 二进制安装的k8s的kube-contrller-manager监听地址为127.0.0.1,prometheus无法直接访问
  • monitoring命名空间下的名为kube-controller-manager的servicemonitors资源,selector.matchLabels是app.kubernetes.io/name: kube-controller-manager,而kube-system命名空间下没有没有这个label的service

KubeSchedulerDown 的原因和以上相同不再描述,解决方案是相同的。

1.5.3 解决

  • 修改kube-controller-manager和kube-schduler的systemd启动脚本,将--address=127.0.0.1改为--address=0.0.0.0,之后重启
  • 创建指定标签的service,这个service没有selector的,需要注意label和serviceMonitor一致,只需指向kube-controller-manager节点ip和端口的endpoint

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/name: kube-controller-manager
      name: kube-controller-manager
      namespace: kube-system
    spec:
      ports:
        - name: https-metrics
          port: 10257
          protocol: TCP
          targetPort: 10257
      type: ClusterIP
    ---
    apiVersion: v1
    kind: Endpoints
    metadata:
      labels:
        app.kubernetes.io/name: kube-controller-manager
      namespace: kube-system
      name: kube-controller-manager
    subsets:
      - addresses:
          - ip: 192.168.2.4
        ports:
          - name: https-metrics
            port: 10257
            protocol: TCP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app.kubernetes.io/name: kube-scheduler
      name: kube-scheduler
      namespace: kube-system
    spec:
      ports:
        - name: https-metrics
          port: 10259
          protocol: TCP
          targetPort: 10259
      type: ClusterIP
    ---
    apiVersion: v1
    kind: Endpoints
    metadata:
      labels:
        app.kubernetes.io/name: kube-scheduler
      namespace: kube-system
      name: kube-scheduler
    subsets:
      - addresses:
          - ip: 192.168.2.4
        ports:
          - name: https-metrics
            port: 10259
            protocol: TCP

    1.5.4 查看prometheus web页面

image.png

1.6 Prometheus监控etcd集群(云原生应用的监控)

1.6.1 访问etcd metrics接口测试

curl --cacert /etc/etcd/ssl/etcd-ca.pem  --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem https://192.168.2.4:2379/metrics

1.6.2 创建etcd监控service和endpoints

apiVersion: v1
kind: Service 
metadata:
  labels:
    app: etcd-monitor
  name: etcd-monitor
  namespace: kube-system
spec:
  ports:
  - name: etcd-port
    port: 2379
    protocol: TCP
    targetPort: 2379
  type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
  labels:
    app: etcd-monitor
  name: etcd-monitor
  namespace: kube-system
subsets:
- addresses:     # etcd节点对应的主机ip,有几台就写几台
  - ip: 192.168.2.4
  ports:
  - name: etcd-port
    port: 2379   # etcd端口
    protocol: TCP

1.6.3 创建secret

将etcd的证书创建为单个secret资源

本例etcd证书位置分别为:

  • cacert:/etc/etcd/ssl/etcd-ca.pem
  • cert:/etc/etcd/ssl/etcd.pem
  • key:/etc/etcd/ssl/etcd-key
kubectl -n monitoring create secret generic etcd-ssl --from-file=/etc/etcd/ssl/etcd-ca.pem --from-file=/etc/etcd/ssl/etcd.pem --from-file=/etc/etcd/ssl/etcd-key.pem

1.6.4 挂载secret到prometheus容器内

直接编辑名为k8s的prometheus资源

kubectl -n monitoring edit prometheus k8s

加入如下字段,是spec子级

    secrets:
    - etcd-ssl

查看挂载

[root@k8s-master01 ~]# kubectl -n monitoring exec -it prometheus-k8s-0 -c prometheus  -- ls /etc/prometheus/secrets/etcd-ssl
etcd-ca.pem   etcd-key.pem  etcd.pem

1.6.5 创建etcd的ServiceMonitor资源

vim etcd-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: etcd-monitor
  namespace: monitoring
  labels:
    app: etcd-monitor
spec:
  jobLabel: app
  endpoints:
    - interval: 30s
      port: etcd-port  # 这个port对应 Service.spec.ports.name
      scheme: https
      tlsConfig:
        caFile: /etc/prometheus/secrets/etcd-ssl/etcd-ca.pem #证书路径 (在prometheus pod里路径)
        certFile: /etc/prometheus/secrets/etcd-ssl/etcd.pem
        keyFile: /etc/prometheus/secrets/etcd-ssl/etcd-key.pem
        insecureSkipVerify: true  # 关闭证书校验
  selector:
    matchLabels:
      app: etcd-monitor  # 跟svc的lables保持一致
  namespaceSelector:
    matchNames:
    - kube-system    # 跟svc所在namespace保持一致
# 匹配Kube-system这个命名空间下面具有app=etcd-k8s这个label标签的Serve,job label用于检索job任务名称的标签。由于证书serverName和etcd中签发的证书可能不匹配,所以添加了insecureSkipVerify=true将不再对服务端的证书进行校验

1.6.6 在promethus中查看target

image.png

1.6.7 grafana导入模板

中文版ETCD集群插件:https://grafana.com/grafana/dashboards/9733

指定导入id:9733即可

image.png

1.7 kafka集群监控(非云原生应用监控)

非云原生应用的监控需要依赖exporter,采集指定应用的数据然后提供metrics接口,供prometheus采集,以kafka为例,演示监控非原生应用。

kafka_exporter项目地址:https://github.com/danielqsj/kafka_exporter

1.7.1 创建kafka_exporter的deployment和servcice资源

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kafka-exporter
  namespace: monitoring
  labels:
    app: kafka-exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kafka-exporter
  template:
    metadata:
      name: kafka-exporter
      labels:
        app: kafka-exporter
    spec:
      restartPolicy: Always
      containers:
        - name: kafka-exporter
          image: danielqsj/kafka-exporter
          imagePullPolicy: IfNotPresent
          env:
            - name: TZ
              value: Asia/Shanghai
            - name: LANG
              value: C.UTF-8
          args: #这里是args而不是command,避免将kafka_exporter启动命令覆盖
            - --kafka.server=kafka-0.kafka-headless.public-service:9092 #指定kafka的无头服务域名
          ports:
            - containerPort: 9308
              name: monitor-port
              protocol: TCP
          volumeMounts:
            - mountPath: /usr/share/zoneinfo/Asia/Shanghai
              name: tz-config
            - mountPath: /etc/timezone
              name: timezone
      volumes:
        - name: tz-config
          hostPath:
            path: /usr/share/zoneinfo/Asia/Shanghai
        - name: timezone
          hostPath:
            path: /etc/timezone
---
apiVersion: v1
kind: Service
metadata:
  name: kafka-exporter
  namespace: monitoring
  labels:
    app: kafka-exporter
spec:
  ports:
    - port: 9308
      protocol: TCP
      targetPort: 9308
      name: monitor-port #这个name和ServiceMonitor.spec.endpoints.port相对应
  selector:
    app: kafka-exporter
  type: ClusterIP

1.7.2 创建kafka的servicemonitor资源

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: kafka-monitor
  namespace: monitoring
  labels:
    app: kafka-monitor
spec:
  jobLabel: app
  endpoints:
    - interval: 30s
      port: monitor-port  # 这个port对应 Service.spec.ports.name
      scheme: http
  selector:
    matchLabels:
      app: kafka-exporter  # 跟service的lables保持一致
  namespaceSelector:
    matchNames:
      - monitoring

1.7.3 kafka创建测试topic

kubectl -n public-service exec -it kafka-0 -- bash
kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 1  --topic mytopic

1.7.4 Prometheus查看target

image.png

1.7.5 grafana导入模板

导入模板ID为:7589

1.8 黑盒监控

新版本kube-promethus默认已经安装了黑盒监控组件,无需手动安装。

1.8.1 概念

  • 白盒监控:监控一些内部的数据,topic的监控数据,Redis key的大小。内部暴露的指标被称为白盒监控。比较关注的是原因。
  • 黑盒监控:站在用户的角度看到的东西。网站不能打开,网站打开的比较慢。比较关注现象,表示正在发生的问题,正在发生的告警。

    1.8.2 创建演示监控

传统方式(additional-scrape-config):

Prometheus自定义监控项目:https://github.com/prometheus/blackbox_exporter

kube-prometheus添加额外的抓取配置:https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/additional-scrape-config.md

新版本方式(添加Probe资源):

blackbox_exporter及Probe资源添加:https://github.com/prometheus-operator/kube-prometheus/blob/main/docs/blackbox-exporter.md

确保prometheus target中blackbox-exporter存在,然后添加如下Probe资源,即可监控指定的网址

kind: Probe
apiVersion: monitoring.coreos.com/v1
metadata:
  name: baidu-com-website
  namespace: monitoring
spec:
  interval: 60s
  module: http_2xx
  prober:
    url: blackbox-exporter.monitoring.svc.cluster.local:19115
  targets:
    staticConfig:
      static:
      - http://www.baidu.com
      - https://www.qq.com

添加Probe资源完成后,查看Prometheus的Configuration

image.png

1.9 Alertmanager

1.9.1 alertmanager主配置文件

# global块配置下的配置选项在本配置文件内的所有配置项下可见
global:
  # 在Alertmanager内管理的每一条告警均有两种状态: "resolved"或者"firing". 在altermanager首次发送告警通知后, 该告警会一直处于firing状态,设置resolve_timeout可以指定处于firing状态的告警间隔多长时间会被设置为resolved状态, 在设置为resolved状态的告警后,altermanager不会再发送firing的告警通知.
  resolve_timeout: 1h

  # 邮件告警配置
  smtp_smarthost: 'smtp.exmail.qq.com:25'
  smtp_from: 'dukuan@xxx.com'
  smtp_auth_username: 'dukuan@xxx.com'
  smtp_auth_password: 'DKxxx'
  # HipChat告警配置
  # hipchat_auth_token: '123456789'
  # hipchat_auth_url: 'https://hipchat.foobar.org/'
  # wechat
  wechat_api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
  wechat_api_secret: 'JJ'
  wechat_api_corp_id: 'ww'

  # 告警通知模板
templates:
- '/etc/alertmanager/config/*.tmpl'

# route: 根路由,该模块用于该根路由下的节点及子路由routes的定义. 子树节点如果不对相关配置进行配置,则默认会从父路由树继承该配置选项。每一条告警都要进入route,即要求配置选项group_by的值能够匹配到每一条告警的至少一个labelkey(即通过POST请求向altermanager服务接口所发送告警的labels项所携带的<labelname>),告警进入到route后,将会根据子路由routes节点中的配置项match_re或者match来确定能进入该子路由节点的告警(由在match_re或者match下配置的labelkey: labelvalue是否为告警labels的子集决定,是的话则会进入该子路由节点,否则不能接收进入该子路由节点).
route:
  # 例如所有labelkey:labelvalue含cluster=A及altertname=LatencyHigh labelkey的告警都会被归入单一组中
  group_by: ['job', 'altername', 'cluster', 'service','severity']
  # 若一组新的告警产生,则会等group_wait后再发送通知,该功能主要用于当告警在很短时间内接连产生时,在group_wait内合并为单一的告警后再发送
  group_wait: 30s
  # 再次告警时间间隔
  group_interval: 5m
  # 如果一条告警通知已成功发送,且在间隔repeat_interval后,该告警仍然未被设置为resolved,则会再次发送该告警通知
  repeat_interval: 12h
  # 默认告警通知接收者,凡未被匹配进入各子路由节点的告警均被发送到此接收者
  receiver: 'wechat'
  # 上述route的配置会被传递给子路由节点,子路由节点进行重新配置才会被覆盖

  # 子路由树
  routes:
  # 该配置选项使用正则表达式来匹配告警的labels,以确定能否进入该子路由树
  # match_re和match均用于匹配labelkey为service,labelvalue分别为指定值的告警,被匹配到的告警会将通知发送到对应的receiver
  - match_re:
      service: ^(foo1|foo2|baz)$
    receiver: 'wechat'
    # 在带有service标签的告警同时有severity标签时,他可以有自己的子路由,同时具有severity != critical的告警则被发送给接收者team-ops-mails,对severity == critical的告警则被发送到对应的接收者即team-ops-pager
    routes:
    - match:
        severity: critical
      receiver: 'wechat'
  # 比如关于数据库服务的告警,如果子路由没有匹配到相应的owner标签,则都默认由team-DB-pager接收
  - match:
      service: database
    receiver: 'wechat'
  # 我们也可以先根据标签service:database将数据库服务告警过滤出来,然后进一步将所有同时带labelkey为database
  - match:
      severity: critical
    receiver: 'wechat'
# 抑制规则,当出现critical告警时 忽略warning
inhibit_rules:
- source_match:
    severity: 'critical'
  target_match:
    severity: 'warning'
  # Apply inhibition if the alertname is the same.
  #   equal: ['alertname', 'cluster', 'service']
  #
# 收件人配置
receivers:
- name: 'team-ops-mails'
  email_configs:
  - to: 'dukuan@xxx.com'
- name: 'wechat'
  wechat_configs:
  - send_resolved: true
    corp_id: 'ww'
    api_secret: 'JJ'
    to_tag: '1'
    agent_id: '1000002'
    api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
    message: '{{ template "wechat.default.message" . }}'
#- name: 'team-X-pager'
#  email_configs:
#  - to: 'team-X+alerts-critical@example.org'
#  pagerduty_configs:
#  - service_key: <team-X-key>
#
#- name: 'team-Y-mails'
#  email_configs:
#  - to: 'team-Y+alerts@example.org'
#
#- name: 'team-Y-pager'
#  pagerduty_configs:
#  - service_key: <team-Y-key>
#
#- name: 'team-DB-pager'
#  pagerduty_configs:
#  - service_key: <team-DB-key>
#  
#- name: 'team-X-hipchat'
#  hipchat_configs:
#  - auth_token: <auth_token>
#    room_id: 85
#    message_format: html
#    notify: true 

1.9.2 配置邮件告警

kube-prometheus中的alertmanger配置是通过secret挂载到pod中的,修改告警配置信息需要修改指定secret

查看secret

root@k8s-master01:~# kubectl -n monitoring get secrets alertmanager-main
NAME                TYPE     DATA   AGE
alertmanager-main   Opaque   1      13h

修改指定secret

通过直接修改源文件的方式添加邮件告警配置信息,路径为kube-prometheus/manifests/alertmanager-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  labels:
    alertmanager: main
    app.kubernetes.io/component: alert-router
    app.kubernetes.io/name: alertmanager
    app.kubernetes.io/part-of: kube-prometheus
    app.kubernetes.io/version: 0.22.2
  name: alertmanager-main
  namespace: monitoring
stringData:
  alertmanager.yaml: |-
    "global":
      "resolve_timeout": "5m"
      "smtp_from": "1532916189@qq.com"
      "smtp_smarthost": smtp.qq.com:465
      "smtp_hello": "hello from alertmanager"
      "smtp_auth_username": "1532916189@qq.com"
      "smtp_auth_password": "xxxxxxxx"
      "smtp_require_tls": false
    "inhibit_rules":
    - "equal":
      - "namespace"
      - "alertname"
      "source_match":
        "severity": "critical"
      "target_match_re":
        "severity": "warning|info"
    - "equal":
      - "namespace"
      - "alertname"
      "source_match":
        "severity": "warning"
      "target_match_re":
        "severity": "info"
    "receivers":
    - "name": "Default"
      "email_configs":
      - "send_resolved": true
        "to": "2576978433@qq.com"
    - "name": "Watchdog"
      "email_configs":
      - "send_resolved": true
        "to": "2576978433@qq.com"
    - "name": "Critical"
      "email_configs":
      - "send_resolved": true
        "to": "2576978433@qq.com"
    "route":
      "group_by":
      - "namespace"
      "group_interval": "5m"
      "group_wait": "30s"
      "receiver": "Default"
      "repeat_interval": "12h"
      "routes":
      - "match":
          "alertname": "Watchdog"
        "receiver": "Watchdog"
      - "match":
          "severity": "critical"
        "receiver": "Critical"
type: Opaque

在alertmanager pod中生成的配置文件如下

global:
  resolve_timeout: 5m 
邮件告警配置
  smtp_from: 1532916189@qq.com
  smtp_smarthost: smtp.qq.com:465
  smtp_hello: hello from alertmanager
  smtp_auth_username: 1532916189@qq.com
  smtp_auth_password: xxxxxxxxxxxx
  smtp_require_tls: false
# 抑制规则,当出现critical告警时 忽略warning
inhibit_rules:
- equal:
  - namespace
  - alertname
  source_match:
    severity: critical
  target_match_re:
    severity: warning|info
- equal:
  - namespace
  - alertname
  source_match:
    severity: warning
  target_match_re:
    severity: info
# 收件人配置
receivers:
- name: Default
  email_configs:
  - send_resolved: true
    to: 2576978433@qq.com
- name: Watchdog
  email_configs:
  - send_resolved: true
    to: 2576978433@qq.com
- name: Critical
  email_configs:
  - send_resolved: true
    to: 2576978433@qq.com
route:
  group_by:
  - namespace
  - job
  - alertname
  group_interval: 5m
  group_wait: 30s
  receiver: Default
  repeat_interval: 12h
  routes:
  - match:
      alertname: Watchdog
    receiver: Watchdog
  - match:
      severity: critical
    receiver: Critical

替换配置文件

kubectl replace -f kube-prometheus/manifests/alertmanager-secret.yaml

1.9.3 查看邮件报警信息

确保缩进正确,在配置完成后altertmanager容器会自动重新加载配置文件,查看邮箱告警信息

image.png

1.9.4 添加自定义报警规则

以blackbox为例演示自定义报警规则的编写,更多实例可参考这里:https://awesome-prometheus-alerts.grep.to/rules

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    app.kubernetes.io/component: exportor
    app.kubernetes.io/name: blackbox-exportor
    prometheus: k8s
    role: alert-rules
  name: blackbox
  namespace: monitoring
spec:
  groups:
    - name: blackbox-exportor
      rules:
        - alert: BlackboxProbeSlowHttp
          annotations:
            description: |-
              HTTP 请求时间 花费时间超过1秒
                VALUE = {{ $value }}
                LABELS = {{ $labels }}
            summary: '检测到域名访问时间过长 (域名是 {{ $labels.instance }})'
          expr: 'avg_over_time(probe_http_duration_seconds[1m]) > 1'
          for: 1m
          labels:
            severity: warning

1.10 Prometheus自动发现

以自动发现集群内部ingress资源为例

1.10.1 添加additional configuration

编辑或者添加文件prometheus-additional.yaml

- job_name: 'auto_discovery'
  metrics_path: /probe
  params:
    module: [http_2xx]  
  kubernetes_sd_configs:
  - role: ingress
  relabel_configs:
  - source_labels: [__meta_kubernetes_ingress_annotation_prometheus_io_http_probe]
    action: keep
    regex: true
  - source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path]
    regex: (.+);(.+);(.+)
    replacement: ${1}://${2}${3}
    target_label: __param_target
  - source_labels: [__meta_kubernetes_ingress_scheme,__address__,__meta_kubernetes_ingress_path]
    regex: (.+);(.+);(.+)
    replacement: ${1}://${2}${3}
    target_label: target
  - target_label: __address__
    replacement: blackbox-exporter:9115
  - source_labels: [__param_target]
    target_label: instance
  - action: labelmap
    regex: __meta_kubernetes_ingress_label_(.+)
  - source_labels: [__meta_kubernetes_namespace]
    target_label: kubernetes_namespace
  - source_labels: [__meta_kubernetes_ingress_name]
    target_label: kubernetes_name
kubectl create secret generic additional-scrape-configs --from-file=prometheus-additional.yaml --dry-run -oyaml > additional-scrape-configs.yaml
kubectl apply -f additional-scrape-configs.yaml -n monitoring

编辑名为k8sprometheus资源

kubectl -n monitoring edit prometheus k8s 

spec子级添加如下内容

additionalScrapeConfigs:
    name: additional-scrape-configs
    key: prometheus-additional.yaml

1.10.2 添加clusterrole和clusterrolebinding

自动发现需要对ingress资源有权限,建立对ingress有只读资源的custerrole,并创建clusterrolebinding给monitoring:prometheus-k8s SA权限

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress-view
rules:
  - apiGroups:
      - networking.k8s.io
    resources:
      - ingresses
    verbs:
      - get
      - watch
      - list
kubectl -n monitoring create clusterrolebinding prometheus-discovery --clusterrole=ingress-view --serviceaccount=monitoring:prometheus-k8s

1.11 监控业务应用

以springboot应用为例,,监控jvm信息,https://github.com/gongchangwangpi/spring-cloud-demo2

1.11.1 手动配置应用监控

项目加入metrics

项目依赖加入metrics接口

修改依赖信息,spring-cloud-demo2/spring-cloud-eureka/pom.xml

加入如下依赖

<!-- Micrometer Prometheus registry  -->
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
          </dependency>
         <dependency>
                <groupId>io.micrometer</groupId>
                 <artifactId>micrometer-core</artifactId>
         </dependency>
         <dependency>
                <groupId>io.micrometer</groupId>
                <artifactId>micrometer-registry-prometheus</artifactId>
         </dependency>
        <!-- finished -->

项目配置文件加入:spring-cloud-demo2/spring-cloud-eureka/src/main/resources/application.yml

management:
  endpoints:
    web:
      exposure:
        include: '*'
    shutdown:
      enable: false
  metrics:
    tags:
      application: "${spring.application.name}"

编译:

mvn clean package -DskipTests

启动

java -jar target/spring-cloud-eureka-0.0.1-SNAPSHOT.jar

通过additional configuration加入监控target

具体配置不详细说明,参考官方文档:https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/additional-scrape-config.md

- job_name: 'jvm-prometheus'
  scheme: http
  metrics_path: '/actuator/prometheus'
  static_configs:
  - targets: ['192.168.2.10:8761']  #springboot项目的地址,k8s集群内可以写成service地址

查看Prometheus target

image.png

grafana导入dashboard

导入id为12856的dashboard

image.png

1.11.2 console自动发现应用监控

eureka配置eureka-consul-adapter

pom.xml引入eureka-consul-adapter

    <dependency>
      <groupId>at.twinformatics</groupId>
      <artifactId>eureka-consul-adapter</artifactId>
      <version>1.4.0</version>
    </dependency>

eureka-consul-adapter注意和springboot的版本匹配要求,本例的prometheus版本较高,eureka-consul-adapter应该采用1.4.0版本,如果采用较低版本会出现如下报错

level=error ts=2021-08-01T11:16:50.303Z caller=consul.go:513 component="discovery manager scrape" discovery=consul msg="Error refreshing service" service=CLOUD-USER tags= err="Unexpected response code: 404 ({\"timestamp\":\"2021-08-01T11:16:50.301+0000\",\"status\":404,\"error\":\"Not Found\",\"message\":\"No message available\",\"path\":\"/v1/health/service/CLOUD-USER\"})"

重新编译

mvn clean package -DskipTests

修改additional configuration

- job_name: 'jvm-discovery-prometheus'
  scheme: http
  metrics_path: '/actuator/prometheus'
  consul_sd_configs:
    - server: '192.168.2.10:8761' #eureka的地址
      scheme: http
      services: []

配置示例服务注册至eureka

注册配置不再详细解释,参考:https://blog.csdn.net/u014320421/article/details/78272678/

注册完成后访问eureka,可以看到名为CLOUD-USER的应用已经注册过来了

image.png

查看Prometheus target

可以看到配置的jvm-discovery-prometheus的job已经正常获取到了

image.png

查看Dashboard

可以看到prometheus已经通过自动发现获取到了注册到eureka的应用

image.png

版权属于:admin
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
0
查看目录

目录

来自 《k8s 集群监控》
评论

本篇文章评论功能已关闭

博主很懒,啥都没有
26 文章数
1 评论量
11 分类数
27 页面数
已在风雨中度过 5年173天12小时0分