Promethues 之服务发现(node-exporter)
在 Kubernetes 下,Promethues 通过与 Kubernetes API 集成,主要支持5中服务发现模式,分别是:Node
、Service
、Pod
、Endpoints
、Ingress
。
我们通过 kubectl 命令可以很方便的获取到当前集群中的所有节点信息:
[root@master1 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
master1 Ready master 40d v1.19.3
node1 Ready <none> 40d v1.19.3
node2 Ready <none> 40d v1.19.3
但是要让 Prometheus 也能够获取到当前集群中的所有节点信息的话,我们就需要利用 Node 的服务发现模式,同样的,在 prometheus.yml
文件中配置如下的 job 任务即可:
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
# 然后apply这个cm
其实现在到页面上查看会报错,查看Promethues 日志:
orbidden: User \"system:serviceaccount:kube-mon:default\" cannot list resource \"nodes\" in API group \"\" at the cluster scope"
level=error ts=2021-02-12T14:15:17.104Z caller=klog.go:94 component=k8s_client_runtime func=ErrorDepth msg="/app/discovery/kubernetes/kubernetes.go:335: Failed to list *v1.Node: nodes is forbidden: User \"system:serviceaccount:kube-mon:default\" cannot list resource \"nodes\" in API group \"\" at the cluster scope"
level=error ts=2021-02-12T14:15:18.108Z caller=klog.go:94 component=k8s_client_runtime func=ErrorDepth msg="/app/discovery/kubernetes/kubernetes.go:335: Failed to list *v1.Node: nodes is forbidden: User \"system:serviceaccount:kube-mon:default\" cannot list resource \"nodes\" in API group \"\" at the cluster scope"
level=error ts=2021-02-12T14:15:19.112Z caller=klog.go:94 component=k8s_client_runtime func=ErrorDepth msg="/app/discovery/kubernetes/kubernetes.go:335: Failed to list *v1.Node: nodes is forbidden: User \"system:serviceaccount:kube-mon:default\" cannot list resource \"nodes\" in API group \"\" at the cluster scope"
实际上就是没权限,所以我们得给他加权限
# 默认的sa是没有权限的
[root@master1 prometheus]# kubectl get sa default -n kube-mon
NAME SECRETS AGE
default 1 6h37m
步骤一
在创建Prometheus的deployment中加上
# 位置:Deployment.spec.template.spec下面
serviceAccountName: prometheus # 指定自己创建的sa
"""
template:
metadata:
labels:
app: prometheus # 这个labels要跟selector的一致,才能匹配上
spec:
serviceAccountName: prometheus # 指定自己创建的sa
volumes: # 真正挂载,这里需要用到底下声明挂载的name
- name: config # 这里需要跟底下声明挂载的name(config)保持一致
configMap:
name: prometheus-config # configmap name
"""
步骤二
创建SA,创建文件prometheus-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus # 名字要跟deployment中的那个serviceAccountName保持一直
namespace: kube-mon
步骤三
创建集群角色,且做好绑定。文件prometheus-rbac.yaml
# 先创建一个集群角色,给定以下一堆权限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups:
- ""
resources:
- nodes
- services
- endpoints
- pods
- nodes/proxy
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
- nodes/metrics
verbs:
- get
- nonResourceURLs:
- /metrics
verbs:
- get
---
# 然后做集群角色绑定,把集群角色跟SA绑定在一起即可
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io # 使用这个API
kind: ClusterRole # 指定绑定的ClusterRole名字是prometheus
name: prometheus
subjects: # 指定绑定的kind为ServiceAccount,name is prometheus,namespace is kube-mon
- kind: ServiceAccount
name: prometheus
namespace: kube-mon
# 所以现在这个namespace下的Pod就有以上权限了
步骤四
然后重新apply这几个文件
[root@master1 prometheus]# ll
total 24
-rw-r--r-- 1 root root 1926 Feb 12 21:54 prome-node-exporter.yaml
-rw-r--r-- 1 root root 968 Feb 12 20:37 prome-redis.yaml
-rw-r--r-- 1 root root 574 Feb 12 22:11 prometheus-cm.yaml
-rw-r--r-- 1 root root 2247 Feb 12 22:52 prometheus-deploy.yaml
-rw-r--r-- 1 root root 861 Feb 12 17:30 prometheus-rbac.yaml
-rw-r--r-- 1 root root 451 Feb 12 16:28 prometheus-svc.yaml
[root@master1 prometheus]# kubectl apply -f .
步骤五、
现在页面查看还是有问题的
我们可以看到上面的 kubernetes-nodes
这个 job 任务已经自动发现了我们5个 node 节点,但是在获取数据的时候失败了,出现了类似于下面的错误信息:
server returned HTTP status 400 Bad Request
这个是因为 prometheus 去发现 Node 模式的服务的时候,访问的端口默认是10250,而默认是需要认证的 https 协议才有权访问的,但实际上我们并不是希望让去访问10250端口的 /metrics
接口,而是 node-exporter
绑定到节点的 9100 端口,所以我们应该将这里的 10250
替换成 9100
,但是应该怎样替换呢?
这里我们就需要使用到 Prometheus 提供的 relabel_configs
中的 replace
能力了,relabel
可以在 Prometheus 采集数据之前,通过 Target 实例的 Metadata
信息,动态重新写入 Label 的值。除此之外,我们还能根据 Target 实例的 Metadata
信息选择是否采集或者忽略该 Target 实例。比如我们这里就可以去匹配 __address__
这个 Label 标签,然后替换掉其中的端口,如果你不知道有哪些 Label 标签可以操作的话,可以将鼠标🎒移动到 Targets 的标签区域,其中显示的 Before relabeling
区域都是我们可以操作的标签:
现在我们来替换掉端口,修改 ConfigMap:(此处忽略,用下面的最终版本)
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: '(.*):10250'
replacement: '${1}:9100'
target_label: __address__
action: replace
这里就是一个正则表达式,去匹配 __address__
这个标签,然后将 host 部分保留下来,port 替换成了 9100,现在我们重新更新配置文件,执行 reload 操作,然后再去看 Prometheus 的 Dashboard 的 Targets 路径下面 kubernetes-nodes 这个 job 任务是否正常了:
我们可以看到现在已经正常了,但是还有一个问题就是我们采集的指标数据 Label 标签就只有一个节点的 hostname,这对于我们在进行监控分组分类查询的时候带来了很多不方便的地方,要是我们能够将集群中 Node 节点的 Label 标签也能获取到就很好了。这里我们可以通过 labelmap
这个属性来将 Kubernetes 的 Label 标签添加为 Prometheus 的指标数据的标签:
- job_name: 'kubernetes-nodes'
kubernetes_sd_configs:
- role: node
relabel_configs:
- source_labels: [__address__]
regex: '(.*):10250'
replacement: '${1}:9100'
target_label: __address__
action: replace
- action: labelmap # 这个
regex: __meta_kubernetes_node_label_(.+)
# 热更新,ip是prometheusPod的Ip
[root@master1 ~]# curl -X POST "http://10.244.1.139:9090/-/reload"
另外由于 kubelet 也自带了一些监控指标数据,就上面我们提到的 10250 端口,所以我们这里也把 kubelet 的监控任务也一并配置上:
- job_name: 'kubernetes-kubelet'
kubernetes_sd_configs:
- role: node
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
但是这里需要特别注意的是这里必须使用 https
协议访问,这样就必然需要提供证书,我们这里是通过配置 insecure_skip_verify: true
来跳过了证书校验,但是除此之外,要访问集群的资源,还必须要有对应的权限才可以,也就是对应的 ServiceAccount 棒的 权限允许才可以,我们这里部署的 prometheus 关联的 ServiceAccount 对象前面我们已经提到过了,这里我们只需要将 Pod 中自动注入的 /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
和 /var/run/secrets/kubernetes.io/serviceaccount/token
文件配置上,就可以获取到对应的权限了。
现在我们再去更新下配置文件,执行 reload 操作,让配置生效,然后访问 Prometheus 的 Dashboard 查看 Targets 路径:
到这里我们就把 Kubernetes 集群节点使用 Prometheus 监控起来了,接下来我们再来和大家学习下怎样监控 Pod 或者 Service 之类的资源对象。
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/port: "9153" # metrics 接口的端口
prometheus.io/scrape: "true" # 这个注解可以让prometheus自动发现