写点什么

【云原生•监控】基于 Prometheus 的云原生集群监控 (理论 + 实践)-01

作者:Reactor2020
  • 2023-12-12
    俄罗斯
  • 本文字数:14894 字

    阅读完需:约 49 分钟

【云原生•监控】基于 Prometheus 的云原生集群监控(理论+实践)-01

前言

「笔者已经在公有云上搭建了一套临时环境,可以先登录体验下:」

http://124.222.45.207:17000/login账号:root/root.2020
复制代码

云原生监控挑战

Prometheus 是用 Go 语言编写,从一开始就是开源的,到 2016 年 Prometheus 成为继 Kubernetes 之后,成为 CNCF 的第二个成员。近几年 Prometheus 的火热,和云原生日趋流行是密不可分的,并且现在已成为云原生生态中监控的事实标准。

传统的监控霸主 Zabbix 在面对云原生监控时,主要面临如下几个挑战:

  1. 监控对象数量增大:传统监控以单体应用为粒度,结合计算、存储、网络等基础设施监控进行运维保障。但在容器化微服务架构下,监控粒度细致到容器 POD 或微服务 API 级别,使得监控对象的数量相比单体应用呈指数级增长。

  2. 监控指标海量:资源对象类型多,如:Container、Pod、Service、Deployment、ReplicaSet、Endpoint、Ingress、PV、PVC 等等;一个云原生集群可能有几万甚至几十万 Pod;一个云原生集群可能有几千上万级别的 Service、Endpoint、Deployment、Ingress 等;海量的监控指标对数据写入、查询性能要求较高,以及存储空间占用优化等,才能承载海量的监控资源

  3. 对象动态变更较为频繁,资源对象的扩缩容、资源对象生命周期大大缩短,甚至有些对象朝生夕死等等,这就会带来两个问题:采集目标不能使用传统的静态配置方式,而是要基于服务发现机制能及时的感知到变化,并进行快速调整;资源对象扩缩容等导致的资源对象生命周期大大缩短是很容易导致指标数量的快速膨胀,久而久之会影响整个监控系统性能;

Zabbix 出现得比较早,当时容器还没有诞生,自然对容器的支持比较差,而 Prometheus 的 TSDB 时序数据存储机制、丰富的服务发现机制等,基本就是为云原生量身定做的,Prometheus 开始成为容器监控方面的标配,并且在未来可见的时间内会被广泛应用。

云原生监控方案

kubernetes云原生集群非常复杂,概况总结下我们主要关注的无外乎下面五大块指标:

  1. 容器基础资源指标:组件运行的外部环境相关性能指标,传统场景下组件运行的外部环境是主机,而云原生环境下组件的外部环境是容器,主机我们需要关注 CPU、内存、存储、磁盘 IO、网络 IO 等相关指标,同理容器基础资源指标也存在类似相关指标,如:Container 的 CPU 使用率、内存使用率、存储空间、磁盘读写 IO 和网络 IO 等。

  2. k8s 资源对象指标:容器是最底层的运行时组件,k8s 作为强大的调度协调这些容器的平台,抽象定义出了很多资源对象,如 Pod、Service、Deployment、ReplicaSet、DaemonSet、Ingress、StatefulSet、ConfigMap、ServiceAccount 等等,资源对象指标就是对这些 k8s 定义的元数据信息进行监控。

  3. k8s 服务组件指标:k8s 作为一个复杂的集群,自身存在很多组件,如 master 节点上运行着:api-server 组件、etcd 组件、kube-scheduler 组件、kube-controller-manager 组件、coredns 组件等,node 节点上有 kubelet 组件、kube-proxy 组件等,作为云原生集群的运维人员,肯定要关注这些核心组件的运行状况,避免某些组件性能瓶颈、异常奔溃导致整个云原生集群性能低下甚至不可用。

  4. k8s 集群 Node 指标:云原生集群的各种组件、业务容器等最终都是运行在 Node 节点上,因此,Node 节点的性能、异常情况等对整个云原生集群的影响也是非常大的,所以,我们也需要特别关注 Node 节点性能指标。

  5. 云原生上层业务指标:上面说的主要是云原生集群底层相关基础指标,云原生作为平台上面自然部署很多业务组件,比如 PaaS 中间件、业务应用服务等,这些组件运行在云原生上层本身也存在相关指标监控。

环境准备

为了监控上述云原生指标,首先,我们需要准备PrometheusGrafana环境。

Prometheus 部署

1、为了方便管理,我们将监控相关的所有资源对象都安装在 monitoring 这个 namespace 下面,没有的话可以提前创建:

[root@k8s-01 prometheus]# kubectl create ns monitoring namespace/monitoring created
复制代码

2、为了能够方便的管理配置文件,我们这里将 prometheus.yml 配置文件用 ConfigMap 的形式进行管理:

# prometheus-config.yamlapiVersion: v1kind: ConfigMapmetadata:  name: prometheus-config  namespace: monitoringdata:  prometheus.yml: |    global:      scrape_interval: 15s      scrape_timeout: 15s    scrape_configs:    - job_name: 'prometheus'      static_configs:      - targets: ['localhost:9090']
复制代码

我们这里暂时只配置了对 prometheus 本身的监控,直接创建该资源对象:

[root@k8s-01 prometheus]# kubectl apply -f prometheus-config.yaml configmap/prometheus-config created
复制代码

配置文件创建完成了,以后如果我们有新的资源需要被监控,我们只需要将上面的 ConfigMap 对象更新即可。

3、现在我们来创建 prometheusPod 资源:

# prometheus-deploy.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: prometheus  namespace: monitoring  labels:    app: prometheusspec:  selector:    matchLabels:      app: prometheus  template:    metadata:      labels:        app: prometheus    spec:      serviceAccountName: prometheus      containers:        - image: prom/prometheus:v2.31.1          name: prometheus          args:            - "--config.file=/etc/prometheus/prometheus.yml"            - "--storage.tsdb.path=/prometheus" # 指定tsdb数据路径            - "--storage.tsdb.retention.time=24h"            - "--web.enable-admin-api" # 控制对admin HTTP API的访问,其中包括删除时间序列等功能            - "--web.enable-lifecycle" # 支持热更新,直接执行localhost:9090/-/reload立即生效          ports:            - containerPort: 9090              name: http          volumeMounts:            - mountPath: "/etc/prometheus"              name: config-volume            - mountPath: "/prometheus"              name: data          resources:            requests:              cpu: 200m              memory: 1024Mi            limits:              cpu: 200m              memory: 1024Mi        - image: jimmidyson/configmap-reload:v0.4.0  #prometheus配置动态加载          name: prometheus-reload          securityContext:            runAsUser: 0          args:            - "--volume-dir=/etc/config"            - "--webhook-url=http://localhost:9090/-/reload"          volumeMounts:            - mountPath: "/etc/config"              name: config-volume          resources:            requests:              cpu: 100m              memory: 50Mi            limits:              cpu: 100m              memory: 50Mi         volumes:        - name: data          persistentVolumeClaim:            claimName: prometheus-data        - configMap:            name: prometheus-config          name: config-volume
复制代码

持久化

另外为了 prometheus 的性能和数据持久化我们这里是直接将通过一个 LocalPV 来进行数据持久化的,**注意一定不能使用 nfs 来持久化数据(TSDB 时序库不支持 nfs 存储,会存在丢失数据风险)**,通过 --storage.tsdb.path=/prometheus 指定数据目录,创建如下所示的一个 PVC 资源对象,注意是一个 LocalPV,和 k8s-02 节点具有亲和性:

#prometheus-storage.yamlapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:  name: local-storageprovisioner: kubernetes.io/no-provisionervolumeBindingMode: WaitForFirstConsumer---apiVersion: v1kind: PersistentVolumemetadata:  name: prometheus-local  labels:    app: prometheusspec:  accessModes:    - ReadWriteOnce  capacity:    storage: 20Gi  storageClassName: local-storage  local:    path: /data/k8s/prometheus  #确保主机节点上存在该目录  persistentVolumeReclaimPolicy: Retain  nodeAffinity:    required:      nodeSelectorTerms:        - matchExpressions:            - key: kubernetes.io/hostname              operator: In              values:                - k8s-02---apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: prometheus-data  namespace: monitoringspec:  selector:    matchLabels:      app: prometheus  accessModes:    - ReadWriteOnce  resources:    requests:      storage: 20Gi  storageClassName: local-storage
复制代码

这里的volumeBindingMode: WaitForFirstConsumer意思就是延迟绑定,当有符合 PVC 要求的 PV 不立即绑定。因为 POD 关联 PVC,而绑定之后,POD 被调度到其他节点,显然其他节点很有可能没有那个 PV 所以 POD 就挂起了,另外就算该节点有合适的 PV,而 POD 被设置成不能运行在该节点,这时候就没法了,延迟绑定的好处是,POD 的调度要参考卷的分布。当开始调度 POD 的时候看看它要求的 LPV 在哪里,然后就调度到该节点,然后进行 PVC 的绑定,最后在挂载到 POD 中,这样就保证了 POD 所在的节点就一定是 LPV 所在的节点。所以让 PVC 延迟绑定,就是等到使用这个 PVC 的 POD 出现在调度器上之后(真正被调度之前),然后根据综合评估再来绑定这个 PVC。

[root@k8s-01 prometheus]# kubectl get pvc -n monitoringNAME              STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGEprometheus-data   Pending                                      local-storage   4m9s
复制代码

RBAC 权限

由于 prometheus 可以访问 Kubernetes 的一些资源对象,所以需要配置 rbac 相关认证,这里我们使用了一个名为 prometheus 的 serviceAccount 对象:

# rbac.yamlapiVersion: v1kind: ServiceAccountmetadata:  name: prometheus  namespace: monitoring---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata:  name: prometheusrules:  - 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---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:  name: prometheusroleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: prometheussubjects:  - kind: ServiceAccount    name: prometheus    namespace: monitoring
复制代码

由于我们要获取的资源信息,在每一个 namespace 下面都有可能存在,所以我们这里使用的是 ClusterRole 的资源对象,值得一提的是我们这里的权限规则声明中有一个 nonResourceURLs 的属性,是用来对非资源型 metrics 进行操作的权限声明,这个在以前我们很少遇到过,然后直接创建上面的资源对象即可:

[root@k8s-01 prometheus]# kubectl apply -f rbac.yaml serviceaccount/prometheus createdclusterrole.rbac.authorization.k8s.io/prometheus createdclusterrolebinding.rbac.authorization.k8s.io/prometheus created[root@k8s-01 prometheus]# kubectl get sa -n monitoringNAME         SECRETS   AGEdefault      1         30mprometheus   1         21s
复制代码

现在我们就可以添加 promethues 的资源对象了:

[root@k8s-01 prometheus]# kubectl apply -f prometheus-deploy.yamldeployment.apps/prometheus created[root@k8s-01 prometheus]# kubectl get pod -n monitoring                                NAME                         READY   STATUS             RESTARTS   AGEprometheus-5cdf864d9-z9bg4   0/1     CrashLoopBackOff   2          2m56s[root@k8s-01 prometheus]# kubectl logs -f prometheus-5cdf864d9-z9bg4 -n monitoringts=2023-06-06T15:27:55.111Z caller=main.go:444 level=info msg="Starting Prometheus" version="(version=2.31.1, branch=HEAD, revision=411021ada9ab41095923b8d2df9365b632fd40c3)"ts=2023-06-06T15:27:55.111Z caller=main.go:449 level=info build_context="(go=go1.17.3, user=root@9419c9c2d4e0, date=20211105-20:35:02)"ts=2023-06-06T15:27:55.111Z caller=main.go:450 level=info host_details="(Linux 3.10.0-1127.10.1.el7.x86_64 #1 SMP Wed Jun 3 14:28:03 UTC 2020 x86_64 prometheus-5cdf864d9-z9bg4 (none))"ts=2023-06-06T15:27:55.111Z caller=main.go:451 level=info fd_limits="(soft=1048576, hard=1048576)"ts=2023-06-06T15:27:55.111Z caller=main.go:452 level=info vm_limits="(soft=unlimited, hard=unlimited)"ts=2023-06-06T15:27:55.112Z caller=query_logger.go:87 level=error component=activeQueryTracker msg="Error opening query log file" file=/prometheus/queries.active err="open /prometheus/queries.active: permission denied"panic: Unable to create mmap-ed active query log
goroutine 1 [running]:github.com/prometheus/prometheus/promql.NewActiveQueryTracker({0x7ffc2fc58e01, 0xb}, 0x14, {0x34442c0, 0xc0001371d0})        /app/promql/query_logger.go:117 +0x3d7main.main()        /app/cmd/prometheus/main.go:491 +0x6bbf[root@k8s-01 prometheus]# 
复制代码

文件权限

创建 Pod 后,我们可以看到并没有成功运行,出现了 open /prometheus/queries.active: permission denied 这样的错误信息,这是因为我们的 prometheus 的镜像中是使用的 nobody 这个用户,然后现在我们通过 LocalPV 挂载到宿主机上面的目录的 ownership 却是 root

[root@k8s-02 k8s]# ls -alh总用量 0drwxr-xr-x  4 root root  39 6月  18 22:14 .drwxr-xr-x. 5 root root  50 6月   6 23:23 ..drwxr-xr-x  6 root root 138 6月  19 01:00 prometheus
复制代码

所以当然会出现操作权限问题了,这个时候我们就可以通过 securityContext 来为 Pod 设置下 volumes 的权限,通过设置 runAsUser=0 指定运行的用户为 root:

containers:  - image: prom/prometheus:v2.31.1    name: prometheus    securityContext:      runAsUser: 0
复制代码

也可以通过设置一个 initContainer 来修改数据目录权限:

......initContainers:- name: fix-permissions  image: busybox  command: [chown, -R, "nobody:nobody", /prometheus]  volumeMounts:  - name: data    mountPath: /prometheus
复制代码

这个时候我们重新更新下 prometheus:

[root@k8s-01 prometheus]# kubectl apply -f prometheus-deploy.yaml deployment.apps/prometheus created[root@k8s-01 prometheus]# kubectl get pod -n monitoringNAME                          READY   STATUS    RESTARTS   AGEprometheus-675dd5dc5b-ks9k4   1/1     Running   0          9s[root@k8s-01 prometheus]# kubectl logs -f prometheus-675dd5dc5b-ks9k4 -n monitoringts=2023-06-06T15:33:41.415Z caller=main.go:444 level=info msg="Starting Prometheus" version="(version=2.31.1, branch=HEAD, revision=411021ada9ab41095923b8d2df9365b632fd40c3)"ts=2023-06-06T15:33:41.415Z caller=main.go:449 level=info build_context="(go=go1.17.3, user=root@9419c9c2d4e0, date=20211105-20:35:02)"ts=2023-06-06T15:33:41.418Z caller=web.go:542 level=info component=web msg="Start listening for connections" address=0.0.0.0:9090ts=2023-06-06T15:33:41.500Z caller=main.go:839 level=info msg="Starting TSDB ..."ts=2023-06-06T15:33:41.505Z caller=main.go:869 level=info msg="TSDB started"ts=2023-06-06T15:33:41.505Z caller=main.go:996 level=info msg="Loading configuration file" filename=/etc/prometheus/prometheus.ymlts=2023-06-06T15:33:41.506Z caller=main.go:1033 level=info msg="Completed loading of configuration file" filename=/etc/prometheus/prometheus.yml totalDuration=592.24µs db_storage=1.487µs remote_storage=6.209µs web_handler=900ns query_engine=1.736µs scrape=288.029µs scrape_sd=26.451µs notify=1.151µs notify_sd=1.487µs rules=3.679µsts=2023-06-06T15:33:41.506Z caller=main.go:811 level=info msg="Server is ready to receive web requests."
复制代码

Pod 创建成功后,为了能够在外部访问到 prometheus 的 Web UI 服务,我们还需要创建一个 Service 对象:

# prometheus-svc.yamlapiVersion: v1kind: Servicemetadata:  name: prometheus  namespace: monitoring  labels:    app: prometheusspec:  selector:    app: prometheus  type: NodePort  ports:    - name: web      port: 9090      targetPort: http
复制代码

为了方便测试,我们这里创建一个 NodePort 类型的服务,当然我们可以创建一个 Ingress对象,通过域名来进行访问:

[root@k8s-01 prometheus]# kubectl apply -f prometheus-svc.yaml service/prometheus created[root@k8s-01 prometheus]# kubectl get svc -n monitoring  -owide NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE   SELECTORprometheus   NodePort   10.96.219.107   <none>        9090:32478/TCP   20s   app=prometheus
复制代码

现在我们就可以通过 http://任意节点IP:32478 访问 prometheus 的 webui 服务了:

这个抓取 job 是用于抓取 prometheus 本身的一些监控数据了,比如我们这里就选择 process_resident_memory_bytes 这个指标,然后点击 Execute,就可以看到类似于下面的图表数据了:

Grafana 部署

Prometheus 采集了 Kubernetes 集群中的一些监控数据指标,我们也尝试使用 promQL 语句查询出了一些数据,并且在 Prometheus 的 Dashboard 中进行了展示,但是明显可以感觉到 Prometheus 的图表功能相对较弱,所以一般情况下我们还是会使用 Grafana 来进行展示,所以我们可以将 Grafana 安装到集群中来。

1、创建编排文件:

# grafana-deploy.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: grafana  namespace: monitoringspec:  selector:    matchLabels:      app: grafana  template:    metadata:      labels:        app: grafana    spec:      volumes:        - name: storage          persistentVolumeClaim:            claimName: grafana-data      containers:        - name: grafana          image: grafana/grafana:8.3.3          imagePullPolicy: IfNotPresent          securityContext:            runAsUser: 0          ports:            - containerPort: 3000              name: grafana          env:            - name: GF_SECURITY_ADMIN_USER              value: admin            - name: GF_SECURITY_ADMIN_PASSWORD              value: admin          readinessProbe:            failureThreshold: 10            httpGet:              path: /api/health              port: 3000              scheme: HTTP            initialDelaySeconds: 60            periodSeconds: 10            successThreshold: 1            timeoutSeconds: 30          livenessProbe:            failureThreshold: 3            httpGet:              path: /api/health              port: 3000              scheme: HTTP            periodSeconds: 10            successThreshold: 1            timeoutSeconds: 1          resources:            limits:              cpu: 400m              memory: 1024Mi            requests:              cpu: 200m              memory: 512Mi          volumeMounts:            - mountPath: /var/lib/grafana              name: storage---apiVersion: v1kind: Servicemetadata:  name: grafana  namespace: monitoringspec:  type: NodePort  ports:    - port: 3000  selector:    app: grafana---apiVersion: v1kind: PersistentVolumemetadata:  name: grafana-local  labels:    app: grafanaspec:  accessModes:    - ReadWriteOnce  capacity:    storage: 1Gi  storageClassName: local-storage  local:    path: /data/k8s/grafana #保证节点上创建好该目录  persistentVolumeReclaimPolicy: Retain  nodeAffinity:    required:      nodeSelectorTerms:        - matchExpressions:            - key: kubernetes.io/hostname              operator: In              values:                - k8s-02---apiVersion: v1kind: PersistentVolumeClaimmetadata:  name: grafana-data  namespace: monitoringspec:  selector:    matchLabels:      app: grafana  accessModes:    - ReadWriteOnce  resources:    requests:      storage: 1Gi  storageClassName: local-storage
复制代码

两个比较重要的环境变量GF_SECURITY_ADMIN_USERGF_SECURITY_ADMIN_PASSWORD,用来配置 grafana 的管理员用户和密码的,由于 grafana 将 dashboard、插件这些数据保存在 /var/lib/grafana 这个目录下面的,所以我们这里如果需要做数据持久化的话,就需要针对这个目录进行 volume 挂载声明。

2、创建并验证 Pod 启动正常:

[root@k8s-01 prometheus]# kubectl apply -f grafana-deploy.yaml[root@k8s-01 prometheus]# kubectl get pod -n monitoringNAME                          READY   STATUS    RESTARTS   AGEgrafana-7cfd74ccf5-crcnz      1/1     Running   0          3m57sprometheus-675dd5dc5b-ks9k4   1/1     Running   0          11d[root@k8s-01 prometheus]# kubectl get svc -n monitoringNAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGEgrafana      NodePort   10.96.57.144    <none>        3000:32052/TCP   13mprometheus   NodePort   10.96.219.107   <none>        9090:32478/TCP   11d
复制代码

3、访问 grafana:http://192.168.31.160:32052

4、添加 Prometheus 数据源:

容器基础资源指标

说到容器监控我们自然会想到 cAdvisor,之前分享过如何部署cAdvisor组件监控Docker容器,cAdvisor(Container Advisor)Google 开源的一个容器监控工具,可用于对容器资源的使用情况和性能进行监控。它以守护进程方式运行,用于收集、聚合、处理和导出正在运行容器的有关信息。具体来说,该组件对每个容器都会记录其资源隔离参数、历史资源使用情况、完整历史资源使用情况的直方图和网络统计信息。

cAdvisor 是用于监控容器引擎的,由于其监控的实用性,Kubernetes 已经默认将其内置到 kubelet 组件中,所以我们无需再单独部署 cAdvisor 组件,直接使用 kubelet 组件提供的指标采集地址即可。

cAdvisor 的数据路径为 /api/v1/nodes/<node>/proxy/metrics,但是我们不推荐使用这种方式,因为这种方式是通过 api-server 去代理访问的,对于大规模的集群会对 api-server造成很大的压力,所以我们可以直接通过访问 kubelet/metrics/cadvisor 这个端点来获取 cAdvisor 的数据。

cAdvisor 接入

我们这里使用 node 的服务发现模式,因为每一个节点下面都有 kubelet,自然都有 cAdvisor 采集到的数据指标,配置如下:

- job_name: "cadvisor"  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_(.+)      replacement: $1    - replacement: /metrics/cadvisor # <nodeip>/metrics -> <nodeip>/metrics/cadvisor      target_label: __metrics_path__  # 下面的方式不推荐使用  # - target_label: __address__  #   replacement: kubernetes.default.svc:443  # - target_label: __metrics_path__  #   replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
复制代码

cadvisor 监控接入成功如下图:

k8s 节点 node 指标

节点性能关键指标

1、主机基本信息

node_uname_info:主机基本信息,包括架构、主机名、操作系统类型等
复制代码

2、CPU 使用率:

(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[$interval])) by (instance)) * 100
复制代码

3、CPU 负载:

node_load1:1分钟负载node_load5:5分钟负载node_load15:15分钟负载
复制代码

4、内存使用率:

100 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100
复制代码

5、磁盘指标:

node_filesystem_size_bytes:磁盘总量node_filesystem_avail_bytes:磁盘可用量
复制代码

6、磁盘 IO:

sum(rate(node_disk_read_bytes_total[1m]))     # 磁盘每秒读取量sum(rate(node_disk_written_bytes_total[1m]))  # 磁盘每秒写入量
复制代码

7、网络 IO:

sum(rate(node_network_receive_bytes_total[1m]))     # 网卡IO(进)sum(rate(node_network_transmit_bytes_total[1m]))  # 网卡IO(出)
复制代码

节点监控部署

物理节点性能监控一般是通过node_exporter来获取,要监控云原生集群节点同样我们这里使用 node_exporter,由于每个节点都需要获取到监控指标数据,所以我们可以通过 DaemonSet 控制器来部署该服务,这样每一个节点都会自动运行一个 node-exporter 的 Pod,如果我们从集群中删除或者添加节点后,也会进行自动扩展。

1、创建 DaemonSet 控制器的编排文件node-exporter-daemonset.yaml:

apiVersion: apps/v1kind: DaemonSetmetadata:  name: node-exporter  namespace: kube-system  labels:    app: node-exporterspec:  selector:    matchLabels:      app: node-exporter  template:    metadata:      labels:        app: node-exporter    spec:      hostPID: true      hostIPC: true      hostNetwork: true      nodeSelector:        kubernetes.io/os: linux      containers:        - name: node-exporter          image: prom/node-exporter:v1.3.1          args:            - --web.listen-address=$(HOSTIP):9100            - --path.procfs=/host/proc            - --path.sysfs=/host/sys            - --path.rootfs=/host/root            - --no-collector.hwmon # 禁用不需要的一些采集器            - --no-collector.nfs            - --no-collector.nfsd            - --no-collector.nvme            - --no-collector.dmi            - --no-collector.arp            - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/containerd/.+|/var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/)            - --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$          ports:            - containerPort: 9100          env:            - name: HOSTIP              valueFrom:                fieldRef:                  fieldPath: status.hostIP          resources:            requests:              cpu: 150m              memory: 200Mi            limits:              cpu: 300m              memory: 400Mi          securityContext:            runAsNonRoot: true            runAsUser: 65534          volumeMounts:            - name: proc              mountPath: /host/proc            - name: sys              mountPath: /host/sys            - name: root              mountPath: /host/root              mountPropagation: HostToContainer              readOnly: true      tolerations: # 添加容忍        - operator: "Exists"      volumes:        - name: proc          hostPath:            path: /proc        - name: dev          hostPath:            path: /dev        - name: sys          hostPath:            path: /sys        - name: root          hostPath:            path: /
复制代码

由于我们要获取到的数据是主机的监控指标数据,而我们的 node-exporter 是运行在容器中的,所以我们在 Pod 中需要配置一些 Pod 的安全策略,这里我们就添加了 hostPID: truehostIPC: truehostNetwork: true 3 个策略,用来使用主机的 PID namespaceIPC namespace 以及Network namespace,这些 namespace 就是用于容器隔离的关键技术。

另外使用hostPath存储卷技术将主机的 /dev/proc/sys这些目录挂载到容器中,这些因为我们采集的很多节点数据都是通过这些文件夹下面的文件来获取到的,比如我们在使用 top 命令可以查看当前 cpu 使用情况,数据就来源于文件 /proc/stat,使用 free 命令可以查看当前内存使用情况,其数据来源是来自 /proc/meminfo 文件。

2、通过DaemonSet控制器创建Pod:

kubectl apply -f  node-exporter-daemonset.yaml
复制代码

3、查看 Pod 是否运行正常:

[root@k8s-01 prometheus]# kubectl get pod -n kube-system -l app=node-exporter -owideNAME                  READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATESnode-exporter-5brqt   1/1     Running   0          3m35s   192.168.31.162   k8s-03   <none>           <none>node-exporter-hqzbp   1/1     Running   0          3m35s   192.168.31.161   k8s-02   <none>           <none>node-exporter-tlc7r   1/1     Running   0          3m35s   192.168.31.160   k8s-01   <none>           <none>
复制代码

部署完成后,我们可以看到在 3 个节点上都运行了一个 node-exporter 的 Pod,且状态Running,可以通过PodIP:9100方式访问获取节点指标:

curl http://192.168.31.160:9100/metricscurl http://192.168.31.161:9100/metricscurl http://192.168.31.162:9100/metrics
复制代码

由于我们指定了 hostNetwork=true,所以PodIP实际上就是节点IP,指定的container port: 9100也会在每个节点上就会绑定一个端口 9100:

[root@k8s-01 ~]# netstat -antp|grep 9100tcp 0 0 192.168.31.160:9100 0.0.0.0:* LISTEN 39239/node_exporter

4、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_(.+)
复制代码

成功接入后,在 prometheus target 页面可以看到采集正常:

5、导入8919 dashboardKubernetes云原生集群节点性能监控指标就展示到模板上,如下图:


发布于: 刚刚阅读数: 3
用户头像

Reactor2020

关注

云原生监控运维 2018-09-17 加入

更多资料,请关注@reactor_2020

评论

发布
暂无评论
【云原生•监控】基于Prometheus的云原生集群监控(理论+实践)-01_监控_Reactor2020_InfoQ写作社区