查看原文
其他

集群外独立部署Prometheus+Grafana监控K8S全面解析

木讷大叔爱运维 木讷大叔爱运维 2022-07-13


点击上方蓝色字体,关注我们





读完需 15 分钟

速读需 7 分钟 




Prometheus+Grafana作为监控K8S的解决方案,大都是在K8S集群内部部署,但是增加了集群的资源开销。因此在资源有限的情况下,我更倾向于K8S集群外独立部署Prometheus+Grafana。


无论哪种部署方式,都需要通过exporter收集各种维度的监控指标,其维度如下:

维度工具监控url(__metrics_path__)备注
Node性能node-exporter/api/v1/nodes/node名:9100/proxy/metrics节点状态
Pod性能kubelet
cadvisor
/api/v1/nodes/node名:10250/proxy/metrics
/api/v1/nodes/node名:10250/proxy/metrics/cadvisor
容器状态
K8S资源kube-state-metrics
Deploy/ds等


大家可能在此有疑问,为什么kube-state-metrics没有监控url?
其实从上表可以看出,监控url并不完整,因为prometheus的动态发现会基于标签进行自动补全,补全格式为:__scheme__://__address____metrics_path__。其中标签的值都可以通过Prometheus的relabel_config拼接成最终的监控url。


正是基于以上原因,集群外部署Prometheus和集群内部署Prometheus是不一样的,因为集群内的Prometheus有的监控使用的是集群私有ip,而集群外Prometheus使用默认自动拼接的监控url是无法访问的,此时需要自行构造apiserver proxy URLs。通过proxy url集群外Prometheus就可以访问监控url来拉取监控指标了。


上表中Pod性能和Node性能的监控url其实都是自行构造的proxy url,而K8S资源使用默认的监控url,就会发现其endpoint都是K8S集群内部的私有ip,因此所有的状态都是down的。

但如果通过自行改造的proxy url访问,则所有的状态则是up的。


构造apiserver proxy url

通过Accessing services running on the cluster(https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-services-running-on-the-cluster)了解到在k8s集群中nodes、pods、services都有自己的私有IP,但是无法从集群外访问;但K8S提供以下几种方式来访问:

  • 通过public IPs访问service

  • 通过proxy 访问node、pod、service

  • 通过集群内的node或pod间接访问

而通过kubectl cluster-info可以查看kube-system命令空间的proxy url:

# 访问nodehttps://${other_apiserver_address}/api/v1/nodes/node_name:[port_name]/proxy/metrics# 访问servicehttps://${other_apiserver_address}/api/v1/namespaces/service_namespace/services/http:service_name[:port_name]/proxy/metrics# 访问podhttps://${other_apiserver_address}/api/v1/namespaces/pod_namespace/pods/http:pod_name[:port_name]/proxy/metrics

在了解如何构造proxy url后,我们就可以通过集群外Prometheus的relabel_config自行构造proxy url了。


apiserver授权

要访问K8S apiserver需要先进行授权,而集群内部Prometheus可以使用集群内默认配置进行访问,而集群外访问需要使用token+客户端cert进行认证,因此需要先进行RBAC授权。

由于我们需要访问不同的namespace,因此我们最好分配cluster-admin,以免权限不足。具体步骤如下:

# 1.创建serviceaccountskubectl create sa prometheus # 2.创建prometheus角色并对其绑定cluster-adminkubectl create clusterrolebinding prometheus --clusterrole cluster-admin --serviceaccount=default:prometheus

虽创建了serviceaccount,但访问apiserver并不是直接使用serviceaccount,而是通过token。因此我们需要获取serviceaccount:prometheus对应的token,而此token是经过base64加密过的,必须解密后才能使用。

# 1.查看sa,在默认namespace# kubectl get sa NAME SECRETS AGEdefault 1 113mprometheus 1 19m
# 2.查看secret# kubectl get sa prometheus -o yamlapiVersion: v1kind: ServiceAccountmetadata: creationTimestamp: "2020-07-28T08:27:55Z" name: prometheus namespace: default resourceVersion: "14403390" selfLink: /api/v1/namespaces/default/serviceaccounts/prometheus uid: 43a98176-faa1-43f7-ad91-0352ca2dce2csecrets:- name: prometheus-token-44jkm
# 3.获取token,从yaml中得到token# kubectl get secret prometheus-token-44jkm -o yaml...省略...token: ZXlKaGJHY2lPaUpTV......省略...
# 4.token解密# 由于此token是经过base64加密的,我们需要通过base64解密获取token值# echo "xxxxxxxx" |base64 -d

通过一系列操作获得的token,可以作为bearer_token访问apiserver。


好了,了解以上几点后,接下来我们按以下顺序来介绍:

  1. 使用exporter收集各种K8S监控指标;

  2. Prometheus如何构造exporter的监控url;

  3. Grafana的图形化展示;


监控指标收集

1.node性能

通过node-exporter采集集群node节点的服务器层面的数据,如cpu、内存、磁盘、网络流量等,其监控url为"http://node_ip:9100/metrics"。


node-exporter可以独立部署在node节点服务器上,但Prometheus需要通过static_config静态配置手动添加监控,在集群扩展情况下,还需要再手动安装node-exporter。因此将node-exporter以DaemonSet形式部署,配合Prometheus动态发现更加方便。

# 1.vim node-exporter.yamlkind: DaemonSetapiVersion: apps/v1metadata: name: node-exporter annotations: prometheus.io/scrape: 'true'spec: selector: matchLabels: app: node-exporter template: metadata: labels: app: node-exporter name: node-exporter spec: containers: - image: quay.io/prometheus/node-exporter:latest name: node-exporter ports: - containerPort: 9100 hostPort: 9100 name: node-exporter hostNetwork: true hostPID: true tolerations: - key: "node-role.kubernetes.io/master" operator: "Exists" effect: "NoSchedule"
---kind: ServiceapiVersion: v1metadata: annotations: prometheus.io/scrape: 'true' labels: app: node-exporter name: node-exporterspec: type: ClusterIP clusterIP: None ports: - name: node-exporter port: 9100 protocol: TCP selector: app: node-exporter
# 2.部署kubectl apply -f node-exporter.yaml


注意:

  1. node-exporter以DaemonSet部署并且设置为hostNetwork,可通过宿主机ip+9100直接访问,因此我认为Service可以不创建,经测试是可以的

  2. node-exporter需要收集集群内所有节点,而master节点默认有NoSchedule污点,即不参与任何调度;因此我们需要单独设置toleration来使master节点也可以部署node-exporter;

  3. 添加prometheus.io/scrape: 'true’用于自动发现;


2.pod性能

cAdvisor 是一个开源的分析容器资源使用率和性能特性的代理工具,集成到 Kubelet中,当Kubelet启动时会同时启动cAdvisor,且一个cAdvisor只监控一个Node节点的信息。cAdvisor 自动查找所有在其所在节点上的容器,自动采集 CPU、内存、文件系统和网络使用的统计信息。cAdvisor 通过它所在节点机的 Root 容器,采集并分析该节点机的全面使用情况。


当然kubelet也会输出一些监控指标数据,因此pod的监控数据有kubelet和cadvisor,监控url分别为
https://NodeIP:10250/metrics

https://NodeIP:10250/metrics/cadvisor


由于kubelet天然存在,因此直接远程访问即可,无需做其他配置。


3.K8S资源对象

kube-state-metrics是一个简单的服务,它监听Kubernetes API服务器并生成关联对象的指标。它不关注单个Kubernetes组件的运行状况,而是关注内部各种对象(如deployment、node、pod等)的运行状况。

# 1.下载部署文件https://github.com/kubernetes/kube-state-metrics/tree/master/examples/standard
# 2.部署kubectl apply -f service-account.yamlkubectl apply -f cluster-role.yamlkubectl apply -f cluster-role-binding.yamlkubectl apply -f deployment.yamlkubectl apply -f service.yaml


4.小结

监控数据的指标采集比较简单,按需部署即可。重点的是Prometheus如何配置k8s自动发现、通过构造apiserver proxy url拉取metrics,因为K8S中的资源都是动态的。


Prometheus

1.部署

Prometheus使用docker部署在K8S集群外。

# 1.创建持久化数据目录并授权mkdir -p /App/prometheus/etc# 默认启动的容器用户信息为:uid=65534(nobody) gid=65534(nogroup),如果不改成777 ,容器启动失败chmod -R 777 /APP/prometheus
# 2.docker启动 docker run -d -p 9090:9090 -v /App/prometheus/etc/prometheus.yml:/etc/prometheus/prometheus.yml -v /App/prometheus:/prometheus prom/prometheus

在后期我们可能要删除一些metric,此时需要调用API,默认是关闭的,可在容器启动时开启,因此我们使用docker-compose部署更合适:

# 1.编辑docker-compose.yamlversion: '3'services:prometheus:image: prom/prometheuscontainer_name: prometheusrestart: alwaysports:- "9090:9090"volumes:- /App/prometheus/etc/prometheus.yml:/etc/prometheus/prometheus.yml- /App/prometheus:/prometheuscommand:- '--config.file=/etc/prometheus/prometheus.yml'- '--storage.tsdb.path=/prometheus'- '--web.enable-admin-api' # 控制对admin HTTP API的访问,其中包括删除时间序列等功能- '--web.enable-lifecycle' # 支持热更新,直接执行localhost:9090/-/reload立即生效
# 2.启动docker-compose up -d
# 3.删除metric# curl -X POST -g 'http://localhost:9090/api/v1/admin/tsdb/delete_series?match[]={job="kubernetes-kube-state"}'{"status":"error","errorType":"unavailable","error":"admin APIs disabled"}


2.自动发现

kubernetes_sd_config从Kubernetes的REST API查找并拉取指标,并始终与集群状态保持同步。
可自动发现的几种role

  • node
    自动发现每个集群节点发现一个target,其地址默认为Kubelet的HTTP端口,如"https://192.168.3.217:10250/metrics"

  • service
    自动发现每个服务的每个服务端口的target。

  • pod
    自动发现所有容器及端口

  • endpoints
    自动发现service中的endpoint,如图

  • ingrsss
    自动发现ingress中path


本次我们主要用到了node和endpoint,但是默认情况自动生成的url有时是不可用的,这就需要我们通过以下内容学习relabel_configs如何使用了。


3.拉取node监控指标

标签默认构造后
__scheme__httpshttps
__address__192.168.3.217:10250192.168.3.217:6443
__metrics_path__/metrics/api/v1/nodes/uvmsvr-3-217:9100/proxy/metrics
完整urlhttps://192.168.3.217:10250//metricshttps://192.168.3.217:6443/api/v1/nodes/uvmsvr-3-217:9100/proxy/metrics


通过relabel_configs构造如下:

scrape_configs:- job_name: "kube-state-metrics" scheme: https tls_config: insecure_skip_verify: true #使用apiserver授权部分解密的token值,以文件形式存储 bearer_token_file: /prometheus/k8s_token # k8s自动发现具体配置 kubernetes_sd_configs: # 使用endpoint级别自动发现 - role: endpoints api_server: "https://192.168.3.217:6443" tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token relabel_configs: - source_labels: [__meta_kubernetes_service_name] # 只保留指定匹配正则的标签,不匹配则删除 action: keep regex: '^(kube-state-metrics)$' - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] # 只保留指定匹配正则的标签,不匹配则删除 action: keep regex: true - source_labels: [__address__] action: replace target_label: instance - target_label: __address__ # 使用replacement值替换__address__默认值 replacement: 192.168.3.217:6443 - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_pod_name, __meta_kubernetes_pod_container_port_number] # 正则匹配 regex: ([^;]+);([^;]+);([^;]+) # 使用replacement值替换__metrics_path__默认值 target_label: __metrics_path__ # 自行构建的apiserver proxy url replacement: /api/v1/namespaces/${1}/pods/http:${2}:${3}/proxy/metrics - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace # 将标签__meta_kubernetes_namespace修改为kubernetes_namespace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace # 将标签__meta_kubernetes_service_name修改为service_name    target_label: service_name


注意:tls_config和bearer_token_file 必须在job内和kubernetes_sd_configs都存在,否则会导致认证失败。


最终的效果如下:


4.拉取pod监控指标

kubelet

标签默认构造后
__scheme__httpshttps
__address__192.168.3.217:10250192.168.3.217:6443
__metrics_path__/metrics/api/v1/nodes/uvmsvr-3-217:10250/proxy/metrics
完整urlhttps://192.168.3.217:10250/metricshttps://192.168.3.217:6443/api/v1/nodes/uvmsvr-3-217:10250/proxy/metrics

advisor

标签默认构造后
__scheme__httpshttps
__address__192.168.3.217:10250192.168.3.217:6443
__metrics_path__/metrics/api/v1/nodes/uvmsvr-3-219:10250/proxy/metrics/cadvisor
完整urlhttps://192.168.3.217:10250/metricshttps://192.168.3.217:6443/api/v1/nodes/uvmsvr-3-219:10250/proxy/metrics/cadvisor

通过relabel_configs构造如下:

# kubelet- job_name: "kube-node-kubelet" scheme: https tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token kubernetes_sd_configs: - role: node api_server: "https://192.168.3.217:6443" tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token relabel_configs: - target_label: __address__ # 使用replacement值替换__address__默认值 replacement: 192.168.3.217:6443 - source_labels: [__meta_kubernetes_node_name] regex: (.+) # 使用replacement值替换__metrics_path__默认值 target_label: __metrics_path__ replacement: /api/v1/nodes/${1}:10250/proxy/metrics - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace target_label: service_name
# advisor - job_name: "kube-node-cadvisor" scheme: https tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token kubernetes_sd_configs: - role: node api_server: "https://192.168.3.217:6443" tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token relabel_configs: - target_label: __address__ # 使用replacement值替换__address__默认值 replacement: 192.168.3.217:6443 - source_labels: [__meta_kubernetes_node_name] regex: (.+) # 使用replacement值替换__metrics_path__默认值 target_label: __metrics_path__ replacement: /api/v1/nodes/${1}:10250/proxy/metrics/cadvisor - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace    target_label: service_name

最终效果如下:


5.拉取K8S资源监控指标

标签默认构造后
__scheme__httpshttps
__address__10.244.2.10:8081192.168.3.217:6443
__metrics_path__/metrics/api/v1/namespaces/kube-system/pods/http:kube-state-metrics-6b6b4476bd-4qh7g:8081/proxy/metrics
完整urlhttps://10.244.2.10:8081//metricshttps://192.168.3.217:6443/api/v1/namespaces/kube-system/pods/http:kube-state-metrics-6b6b4476bd-4qh7g:8081/proxy/metrics

通过relabel_configs构造如下:

scrape_configs:- job_name: "kube-state-metrics" scheme: https tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token kubernetes_sd_configs: - role: endpoints api_server: "https://192.168.3.217:6443" tls_config: insecure_skip_verify: true bearer_token_file: /prometheus/k8s_token relabel_configs: - source_labels: [__meta_kubernetes_service_name] action: keep regex: '^(kube-state-metrics)$' - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__address__] action: replace target_label: instance - target_label: __address__ # 使用replacement值替换__address__默认值 replacement: 192.168.3.217:6443 - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_pod_name, __meta_kubernetes_pod_container_port_number] regex: ([^;]+);([^;]+);([^;]+) # 使用replacement值替换__metrics_path__默认值 target_label: __metrics_path__ replacement: /api/v1/namespaces/${1}/pods/http:${2}:${3}/proxy/metrics - action: labelmap regex: __meta_kubernetes_service_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_service_name] action: replace    target_label: service_name

最终效果如下:

Grafana

Grafana从prometheus数据源读取监控指标并进行图形化展示,可通过以下几种方式进行展示:


1

grafana dashboard模板


Grafana Dashboard提供了很多模板供我们下载使用,针对以上不同维度的监控指标,我们可以自行选择喜欢的模板直接导入Dashboard id使用。


1.node性能
Dashboard id:8919


Dashboard id:9276


2.pod性能

Dashboard id:8588


3.K8S资源
Dashboard id:3119


Dashboard id:6417


注意: 如果Dashboard没有数据,需要具体查看相关指标或标签是否存在,因为有的模板是几年前上传的,没有更新。


2l

grafana plugin


通过Dashboard 模板我们需要自行选择并组合,灵活有余但规范不足。而grafana自带专门针对Kubernetes集群监控的插件grafana-kubernetes-app,它包括4个仪表板,集群,节点,Pod /容器和部署。但是这个插件已经3年+没有更新了,有很多的metrics和label没有更新。

在此特推荐KubeGraf,是grafana-kubernetes-app升级版本,该插件可以用来可视化和分析 Kubernetes 集群的性能,通过各种图形直观的展示了 Kubernetes 集群的主要服务的指标和特征,还可以用于检查应用程序的生命周期和错误日志。


1.安装

# 1.安装grafana-cli plugins install devopsprodigy-kubegraf-app# 2.重启grafanasystemctl restart grafana-server

2.配置
“Add New Cluster” 后,我们进行如下配置:

  • URL:填写K8S apiserver地址

  • TLS Client Auth:使用tls认证

  • Skip TLS Verify:不会检查服务器凭证的有效性,这会导致HTTPS链接不安全

  • With CA Cert:不开启,将不使用CA Cert

  • CA Cert:和With CA Cert同时使用
    填入解密的内容

# 从/root/.kube/config 获取certificate-authority-data 值并解密echo "xxxx" |base64 -d
  • Client Cert
    填入解密的内容

# 从/root/.kube/config 获取client-certificate-data 值并解密echo "xxxx" |base64 -d
  • Client Key
    填入解密的内容

# 从/root/.kube/config 获取client-key-data 值并解密echo "xxxx" |base64 -d


3.展示效果


集群状态


node状态


Deployment状态


DaemonSet 状态


pod状态



总结

监控K8S一定要提前规划好Prometheus的位置,熟悉RBAC授权及apiserver proxy url,这样我们在部署过程中能够快速定位问题。

至于Prometheus部署在集群外还是集群内,大家见仁见智,根据自己的实际需求进行部署。建议多个小集群可通过集群外Prometheus统一监控;大集群则避免Prometheus中心化,还是每个集群内部单独部署。




filebeat收集K8S日志,写入自动创建的索引

PMM:最佳的开源数据库监视解决方案

Jenkins扩展共享库进阶

离了蓝鲸也能交付虚拟机

腾讯蓝鲸实现vsphere虚拟机交付




关注我们




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存