本篇要分享的内容
这里假设你已经完成了kube-prometheus的部署。
假设有个需求:需要将node-exporter的指标暴露到k8s集群外部。如果要搞清楚这个问题,并实现这个需求,需要对通过operator部署的资源、内部链路有一定的了解才可以。所以,本篇要做这方面的一个分享。
关于在manifests下的清单
这里假设你已经对prometheus-operator和kube-prometheus有了一定的了解和使用经验。
在 kube-prometheus 仓库下的 manifests 中,已经有了用于安装和部署 Prometheus Operator、Alertmanager、Node Exporter、kube-state-metrics 和 Grafana 等组件的 Kubernetes 部署清单。这些清单可以用来在 Kubernetes 集群中部署这些组件,以便可以开始监控集群中的各种指标。不仅如此,它还包含了其它资源清单,如 Service、ConfigMap、Role、ClusterRole 等。这些清单文件一起提供了一个完整的 Prometheus 监控解决方案。
它为什么无法在外部拿到指标
- 看看部署方式
nodeExporter-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
...
...
在k8s中, DaemonSet 是一种用于在 K8S 集群中部署守护进程的控制器,它确保每个节点上都运行一个 Pod 的副本,这使得在整个集群中运行守护进程变得非常容易。DaemonSet 的工作原理是,在每个节点上自动创建 Pod,并且这些 Pod 将一直运行,直到 DaemonSet 被删除或更新为止。 如果一个新节点加入集群,DaemonSet 会在该节点上自动创建 Pod。反之,如果节点被删除,它将自动删除对应的 Pod。DaemonSet 常用于运行一些系统级别的服务,例如监控代理、日志收集代理等,这些服务需要在每个节点上运行。所以,node-exporter 以 DaemonSet 控制器部署是非常合适的一个解决方案。
- 查看节点上自动创建的Pod
[root@k8s-a-master manifests-prometheus-operator]# kubectl get pod -n monitoring -o wide | grep node-exporter
node-exporter-2wgf7 2/2 Running 0 3m14s 192.168.11.19 k8s-a-node09 <none> <none>
node-exporter-65fb9 2/2 Running 0 3m14s 192.168.11.20 k8s-a-node10 <none> <none>
node-exporter-6p2ll 2/2 Running 0 3m14s 192.168.11.16 k8s-a-node06 <none> <none>
node-exporter-9jnml 2/2 Running 0 3m14s 192.168.11.12 k8s-a-node02 <none> <none>
node-exporter-cjsr6 2/2 Running 0 3m14s 192.168.11.17 k8s-a-node07 <none> <none>
node-exporter-d9lqf 2/2 Running 0 3m14s 192.168.11.13 k8s-a-node03 <none> <none>
node-exporter-gcrx4 2/2 Running 0 3m14s 192.168.11.10 k8s-a-master <none> <none>
由于这里使用了DaemonSet控制器部署node-exporter,因此每个节点上都会运行一个该容器的实例。这意味着每个节点上都会有一个监听9100端口的node-exporter实例,而这些实例都会向Prometheus提供监控数据,使得Prometheus能够集中管理和分析这些数据。继续往下看,监听端口的部分。
- 我们来看一下端口部分
...
ports:
- containerPort: 9100
hostPort: 9100
name: https
...
“name”指定了一个名为“https”的端口,“containerPort”指定了Pod中容器的端口号,即9100。而“hostPort”指定了宿主机节点上的端口号,也是9100。这意味着在任何宿主机节点上,都可以通过访问9100端口来访问Pod中的容器。
- 在页面上查看targets,node-exporter的job已自动添加
在内部,走的是https协议。
- 外部不给浏览器直接访问
- 我们在集群节点内部用curl试试
[root@k8s-a-node06 ~]# curl https://192.168.11.16:9100/metrics curl: (60) Peer's certificate issuer has been marked as not trusted by the user. More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
[root@k8s-a-node06 ~]# curl http://192.168.11.16/metrics
Client sent an HTTP request to an HTTPS server.
[root@k8s-a-node06 ~]#
[root@k8s-a-node06 ~]# curl http://127.0.0.1/metrics
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 2.2247e-05
go_gc_duration_seconds{quantile="0.25"} 3.0408e-05
go_gc_duration_seconds{quantile="0.5"} 3.2917e-05
...
process_cpu_seconds_total 2.77
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 1.048576e+06
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 10
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
...
发现在集群内部使用http协议访问127.0.0.1是可以拿到指标的,并且没有提示任何关于证书的问题。也就有可能说,只要让其走http就可以在外部拿到指标了?我们继续往下看。
nodeExporter yaml清单
先了解每个yaml的用途
[root@k8s-a-master manifests-prometheus-operator]# ls -l nodeExporter-*
-rw-r--r-- 1 root root 468 Apr 11 10:30 nodeExporter-clusterRoleBinding.yaml
-rw-r--r-- 1 root root 485 Apr 11 10:30 nodeExporter-clusterRole.yaml
-rw-r--r-- 1 root root 3640 Apr 27 21:46 nodeExporter-daemonset.yaml
-rw-r--r-- 1 root root 671 Apr 11 10:30 nodeExporter-networkPolicy.yaml
-rw-r--r-- 1 root root 15214 Apr 11 10:30 nodeExporter-prometheusRule.yaml
-rw-r--r-- 1 root root 306 Apr 11 10:30 nodeExporter-serviceAccount.yaml
-rw-r--r-- 1 root root 850 Apr 27 21:46 nodeExporter-serviceMonitor.yaml
-rw-r--r-- 1 root root 492 Apr 27 21:46 nodeExporter-service.yaml
- nodeExporter-clusterRoleBinding.yaml:这个文件定义了一个 ClusterRoleBinding(集群角色绑定)对象,用于授权一个指定的服务帐户(在 nodeExporter-serviceAccount.yaml 文件中定义)访问与 Node Exporter 相关的资源。
- nodeExporter-clusterRole.yaml:这个文件定义了一个 ClusterRole(集群角色)对象,用于授予一组权限,允许 Prometheus Server 访问 Node Exporter 的指标数据。
- nodeExporter-daemonset.yaml:这个文件定义了一个 DaemonSet(守护进程集)对象,用于在 Kubernetes 集群中每个节点上运行一个 Node Exporter 的副本,以便从每个节点收集指标数据。
- nodeExporter-networkPolicy.yaml:这个文件定义了一个 NetworkPolicy(网络策略)对象,用于限制从 Prometheus Server 到 Node Exporter 的网络流量,以确保只有来自 Prometheus Server 的流量能够到达 Node Exporter。
- nodeExporter-prometheusRule.yaml:这个文件定义了一组 PrometheusRule(Prometheus 规则)对象,用于检查 Node Exporter 的指标数据并生成相应的警报。这些规则定义了要检查的指标及其阈值。
- nodeExporter-serviceAccount.yaml:这个文件定义了一个 ServiceAccount(服务帐户)对象,用于授权 Node Exporter 访问 Kubernetes API。这个服务帐户将被绑定到上面提到的 ClusterRole。
- nodeExporter-serviceMonitor.yaml:这个文件定义了一个 ServiceMonitor(服务监控)对象,用于告诉 Prometheus Server 如何收集来自 Node Exporter 的指标数据。这个对象定义了 Node Exporter 的服务名称和端口号等信息。
- nodeExporter-service.yaml:这个文件定义了一个 Service(服务)对象,用于将 Node Exporter 的网络服务暴露到 Kubernetes 集群中。这个服务将被 nodeExporter-serviceMonitor.yaml 文件中定义的 ServiceMonitor 监控。
同样的,其它grafana、alertmanager、blackboxExporter、kubeStateMetrics等,它们的资源清单也是这样的。
https链路分析
之前已经知道了在内部走的是https协议,并且现在已经搞清楚了清单里的每个yaml的作用后,相信大脑里已经产生了下面的一个逻辑图:
接下来就一层一层的找到关于https的配置。
分析nodeExporter-daemonset
在nodeExporter-daemonset.yaml中下面两个相关的配置:
...
containers:
- args:
- --web.listen-address=127.0.0.1:9100
...
ports:
- containerPort: 9100
hostPort: 9100
name: https
...
- --web.listen-address=127.0.0.1:9100:这是一个参数,它告诉容器在127.0.0.1上监听9100端口的传入请求
- containerPort: 9100:这是容器内的端口号。当容器启动时,它将在该端口上监听传入的流量。
- hostPort: 9100:这是主机上的端口号。当容器启动时,它将绑定到主机的该端口上。这使得主机上的其他进程可以通过该端口访问容器中运行的应用程序。
- name: https:这是端口的名称。它是一个可选的字段,但在许多情况下都是很有用的,因为它允许您在其他地方引用端口而不是硬编码端口号。
经测试:
- 端口的名称只是端口名称而已,可以改成任意字符串,比如我改成字符串“http”
name: http
- 将127.0.0.1改为0.0.0.0,修改后在k8s外部,通过浏览器走http协议能拿到指标:
--web.listen-address=0.0.0.0:9100
尴尬的事情发生了,页面中可以看到拿不到指标了:
原因是serviceMonitor还是用https去连接的,奇怪了,在上一步只是改了监听,改为0.0.0.0而已,难道https已经不生效啦?继续往下看。
分析nodeExporter-serviceMonitor和nodeExporter-service
先看nodeExporter-serviceMonitor.yaml,找到相关的字段
...
spec:
endpoints:
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
interval: 15s
port: https # 看这个
relabelings:
- action: replace
regex: (.*)
replacement: $1
sourceLabels:
- __meta_kubernetes_pod_node_name
targetLabel: instance
scheme: https # 还有这个
tlsConfig:
insecureSkipVerify: true
jobLabel: app.kubernetes.io/name
selector:
matchLabels:
...
上面的字段port和字段scheme,可以查看官方的API文档,就可以知道是什么意义
https://prometheus-operator.dev/docs/operator/api/#monitoring.coreos.com/v1.Endpoint
所以现在答案很明显了,scheme字段是真正决定它是https还是使用http。经过分析之前的逻辑图,这里的port是指向nodeExporter-service.yaml中的ports.name。
从https修改为http:
scheme: http
为了更有意义,把名称相关的也修改:
port: http
然后,修改nodeExporter-service.yaml中的ports里的name和targetPort
spec:
clusterIP: None
ports:
- name: http
port: 9100
targetPort: http
下面我梳理了一个关系图:
看看最终效果:
已经成功让它走http了,并且外部也能直接拿到指标了。
最后
你会发现,当整条链路分析下来,会对Prometheus Operator这个东西理解的更加深刻。对于其它资源、或者是自己定义监控业务的资源,在套路上是万变不离其宗。:https://mp.weixin.qq.com/s/dKVt29oO9pXQW7SEe5Hkow