一、环境描述

K8S中一般使用Prometheus进行指标数据的监控,而对于custom metrics自定义指标,需要满足Prometheus可以识别的格式发送。这时候一般需要写exporter来搞定自定义数据,然后上报。本篇结合nginx示例来配置下自定义指标监控。

为了省于前期复制的k8s配置和Prometheus的集成,这里选用了华为的云容器引擎CCE,创建完CCE,把metrics-server和prometheus两个插件勾选上就可以了,会自动安装上grafana和prometheus-adapter(将自定义指标通过API上报Prometheus)。

这里出于测试目的,使用的nginx(stub_status开启内部访问)和nginx_exporter(将stub_status数据转换),如果需要采集更多指标,可以使用nginx_vts替代nginx_exporter。

二、编译nginx镜像

编辑nginx.conf配置文件,开启stub_status功能,配置文件内容如下:

 1user  nginx;
 2worker_processes  auto;
 3
 4error_log  /var/log/nginx/error.log warn;
 5pid        /var/run/nginx.pid;
 6
 7events {
 8    worker_connections  1024;
 9}
10
11http {
12    include       /etc/nginx/mime.types;
13    default_type  application/octet-stream;
14    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
15                      '$status $body_bytes_sent "$http_referer" '
16                      '"$http_user_agent" "$http_x_forwarded_for"';
17
18    access_log  /var/log/nginx/access.log  main;
19    sendfile        on;
20    #tcp_nopush     on;
21    keepalive_timeout  65;
22    #gzip  on;
23    include /etc/nginx/conf.d/*.conf;
24
25    server {
26      listen 8080;
27      server_name  localhost;
28      location /stub_status {
29         stub_status on;
30         access_log off;
31      }
32    }
33}

编辑Dockerfile文件,将该文件复制到对应的镜像内容(重新生成docker image这部也可以不做,因为大部分的nginx images是支持nginx.conf指定本地目录下的nginx.conf文件进去的):

1FROM nginx:1.21.5-alpine
2ADD nginx.conf /etc/nginx/nginx.conf
3EXPOSE 80
4CMD ["nginx", "-g", "daemon off;"]

将build新生成的镜像文件上传华为SWR镜像仓库。

三、Deployment发布应用

编辑一个deployment文件,内容如下:

 1kind: Deployment
 2apiVersion: apps/v1
 3metadata:
 4  name: nginx-exporter
 5  namespace: default
 6spec:
 7  replicas: 1
 8  selector:
 9    matchLabels:
10      app: nginx-exporter
11  template:
12    metadata:
13      labels:
14        app: nginx-exporter
15      annotations:
16        # metrics.alpha.kubernetes.io/custom-endpoints: '[{"api":"prometheus","path":"/metrics","port":"9113","names":""}]'  //这个是上报华为AOM服务使用的,可以删除该行
17        prometheus.io/path: /metrics
18        prometheus.io/port: "9113"
19        prometheus.io/scrape: "true"
20    spec:
21      containers:
22        - name: container-nginx
23          image: 'swr.la-north-2.myhuaweicloud.com/testca/nginx:exporter'
24          resources:
25            limits:
26              cpu: 250m
27              memory: 512Mi
28            requests:
29              cpu: 250m
30              memory: 512Mi
31        - name: container-exporter
32          image: 'nginx/nginx-prometheus-exporter:0.9.0'
33          command:
34            - nginx-prometheus-exporter
35          args:
36            - '-nginx.scrape-uri=http://127.0.0.1:8080/stub_status'
37      imagePullSecrets:
38        - name: default-secret

Prometheus可以动态监测,一般来说给Pod打上Prometheus的annotations,Prometheus会自动采集该Pod的监控信息,这里注意下annotations这里面的几个关键内容,具体的解释如下:

1prometheus.io/scrape: true的话该pod会作为监控目标
2prometheus.io/path: 采集的url,默认为/metrics
3prometheus.io/port: 采集endpoint的端口号
4prometheus.io/scheme: 默认http,如果为了安全设置了https,此处需要改为https

通常打上prometheus.io/scrape这个annotations就可以了,这样Prometheus就会从“/metrics”采集Pod的的监控信息。执行kubectl create/apply应用该yaml文件。

四、监控配置

由于CCE上默认prometheus和grafana默认都是ClusterIP内部访问的,这里我新增加了一个nodeport的service服务,对外暴漏prometheus,同样grafan需要暴漏的时候,操作也是一样的。

k8s-cce-prometheus
k8s-cce-prometheus

通过kubectl get pods -o wide获取到Pod的内部IP,通过prometheus的target部分,可以看到kubernetes-pods endpoint里已经有了这部分数据:
nginx-prometheus
nginx-prometheus

 1[root@testcce-47617-dk54v ~]# kubectl get deployments -n monitoring
 2NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
 3cceaddon-prometheus-kube-state-metrics   1/1     1            1           2d5h
 4cceaddon-prometheus-operator             1/1     1            1           2d5h
 5custom-metrics-apiserver                 1/1     1            1           2d5h
 6grafana                                  1/1     1            1           2d5h
 7[root@testcce-47617-dk54v ~]# kubectl get svc -n monitoring
 8NAME                                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
 9cceaddon-prometheus-kube-state-metrics   ClusterIP   None             <none>        80/TCP           2d5h
10custom-metrics-apiserver                 ClusterIP   10.247.2.162     <none>        443/TCP          2d5h
11grafana                                  ClusterIP   10.247.208.180   <none>        3000/TCP         2d5h
12prometheus                               ClusterIP   10.247.177.188   <none>        80/TCP           2d5h
13prometheus-nodeport                      NodePort    10.247.255.97    <none>        9090:32384/TCP   44h
14[root@testcce-47617-dk54v ~]# kubectl expose deployment grafana --type=NodePort --name=grafana-nodeport -n monitoring
15service/grafana-nodeport exposed
16[root@testcce-47617-dk54v ~]# kubectl get svc -n monitoring
17NAME                                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
18cceaddon-prometheus-kube-state-metrics   ClusterIP   None             <none>        80/TCP           2d5h
19custom-metrics-apiserver                 ClusterIP   10.247.2.162     <none>        443/TCP          2d5h
20grafana                                  ClusterIP   10.247.208.180   <none>        3000/TCP         2d5h
21grafana-nodeport                         NodePort    10.247.195.200   <none>        3000:30269/TCP   3s
22prometheus                               ClusterIP   10.247.177.188   <none>        80/TCP           2d5h
23prometheus-nodeport                      NodePort    10.247.255.97    <none>        9090:32384/TCP   44h
24</none></none></none></none></none></none></none></none></none></none></none>

这里在grafana上增加了下每秒请求数量的图,具体代码为sum(rate(nginx_http_requests_total[1m])) by (kubernetes_pod_name),通过循环请求对应的图如下:

nginx-grafana
nginx-grafana

这里请求是对单pod进行的while true;do curl 172.16.0.12;done,多pod服务的情况下,也可以通过内部域名,在一台测试容器中进行,或者通过NodePort暴漏后,访问对应的地址进行集群测试。

后记

这里nginx和nginx-exporter使用的是sidecar模式,如果要放在一个容器里也可以实现,具体步骤如下:
1. 创建dockerfile,内容如下:

 1# 编译阶段 命名为 exporter
 2FROM nginx/nginx-prometheus-exporter:latest as exporter
 3# 运行阶段
 4FROM nginx:alpine
 5COPY ./nginx/status.conf /etc/nginx/conf.d/status.conf
 6COPY --from=exporter /usr/bin/exporter /usr/bin/exporter
 7ADD run.sh /run.sh
 8RUN chmod 777 /run.sh
 9EXPOSE 80 9113
10CMD ["/bin/sh", "/run.sh"]
  1. 编写run.sh:
1#!/bin/bash
2nginx -c /etc/nginx/nginx.conf
3nginx -s reload
4/usr/bin/exporter -nginx.scrape-uri http://127.0.0.1/stub_status
5tail -f /dev/null #实现本shell永不运行完成,容器不退出。

同样,通过docker命令执行生成image的指令如下:

1docker build . -t nginx-exporter:v2