集群外独立部署Prometheus+Grafana监控K8S全面解析
点击上方蓝色字体,关注我们
读完需 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:
# 访问node
https://${other_apiserver_address}/api/v1/nodes/node_name:[port_name]/proxy/metrics
# 访问service
https://${other_apiserver_address}/api/v1/namespaces/service_namespace/services/http:service_name[:port_name]/proxy/metrics
# 访问pod
https://${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.创建serviceaccounts
kubectl create sa prometheus
# 2.创建prometheus角色并对其绑定cluster-admin
kubectl 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 AGE
default 1 113m
prometheus 1 19m
# 2.查看secret
# kubectl get sa prometheus -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2020-07-28T08:27:55Z"
name: prometheus
namespace: default
resourceVersion: "14403390"
selfLink: /api/v1/namespaces/default/serviceaccounts/prometheus
uid: 43a98176-faa1-43f7-ad91-0352ca2dce2c
secrets:
- 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。
好了,了解以上几点后,接下来我们按以下顺序来介绍:
使用exporter收集各种K8S监控指标;
Prometheus如何构造exporter的监控url;
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.yaml
kind: DaemonSet
apiVersion: apps/v1
metadata:
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: Service
apiVersion: v1
metadata:
annotations:
prometheus.io/scrape: 'true'
labels:
app: node-exporter
name: node-exporter
spec:
type: ClusterIP
clusterIP: None
ports:
- name: node-exporter
port: 9100
protocol: TCP
selector:
app: node-exporter
# 2.部署
kubectl apply -f node-exporter.yaml
注意:
node-exporter以DaemonSet部署并且设置为hostNetwork,可通过宿主机ip+9100直接访问,因此我认为Service可以不创建,经测试是可以的;
node-exporter需要收集集群内所有节点,而master节点默认有NoSchedule污点,即不参与任何调度;因此我们需要单独设置toleration来使master节点也可以部署node-exporter;
添加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.yaml
kubectl apply -f cluster-role.yaml
kubectl apply -f cluster-role-binding.yaml
kubectl apply -f deployment.yaml
kubectl 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.yaml
version: '3'
services:
prometheus:
image: prom/prometheus
container_name: prometheus
restart: always
ports:
- "9090:9090"
volumes:
- /App/prometheus/etc/prometheus.yml:/etc/prometheus/prometheus.yml
- /App/prometheus:/prometheus
command:
- '--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__ | https | https |
__address__ | 192.168.3.217:10250 | 192.168.3.217:6443 |
__metrics_path__ | /metrics | /api/v1/nodes/uvmsvr-3-217:9100/proxy/metrics |
完整url | https://192.168.3.217:10250//metrics | https://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__ | https | https |
__address__ | 192.168.3.217:10250 | 192.168.3.217:6443 |
__metrics_path__ | /metrics | /api/v1/nodes/uvmsvr-3-217:10250/proxy/metrics |
完整url | https://192.168.3.217:10250/metrics | https://192.168.3.217:6443/api/v1/nodes/uvmsvr-3-217:10250/proxy/metrics |
advisor
标签 | 默认 | 构造后 |
---|---|---|
__scheme__ | https | https |
__address__ | 192.168.3.217:10250 | 192.168.3.217:6443 |
__metrics_path__ | /metrics | /api/v1/nodes/uvmsvr-3-219:10250/proxy/metrics/cadvisor |
完整url | https://192.168.3.217:10250/metrics | https://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__ | https | https |
__address__ | 10.244.2.10:8081 | 192.168.3.217:6443 |
__metrics_path__ | /metrics | /api/v1/namespaces/kube-system/pods/http:kube-state-metrics-6b6b4476bd-4qh7g:8081/proxy/metrics |
完整url | https://10.244.2.10:8081//metrics | https://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.重启grafana
systemctl 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中心化,还是每个集群内部单独部署。