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

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

220300

【云原生•监控】基于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.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitoring
data:
  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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: monitoring
  labels:
    app: prometheus
spec:
  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.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: prometheus-local
  labels:
    app: prometheus
spec:
  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: v1
kind: PersistentVolumeClaim
metadata:
  name: prometheus-data
  namespace: monitoring
spec:
  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 monitoring
NAME              STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
prometheus-data   Pending                                      local-storage   4m9s

RBAC权限

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

# rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: monitoring
---
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
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
  - kind: ServiceAccount
    name: prometheus
    namespace: monitoring

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

[root@k8s-01 prometheus]# kubectl apply -f rbac.yaml 
serviceaccount/prometheus created
clusterrole.rbac.authorization.k8s.io/prometheus created
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
[root@k8s-01 prometheus]# kubectl get sa -n monitoring
NAME         SECRETS   AGE
default      1         30m
prometheus   1         21s

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

[root@k8s-01 prometheus]# kubectl apply -f prometheus-deploy.yaml
deployment.apps/prometheus created
[root@k8s-01 prometheus]# kubectl get pod -n monitoring                                
NAME                         READY   STATUS             RESTARTS   AGE
prometheus-5cdf864d9-z9bg4   0/1     CrashLoopBackOff   2          2m56s
[root@k8s-01 prometheus]# kubectl logs -f prometheus-5cdf864d9-z9bg4 -n monitoring
ts=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 +0x3d7
main.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
总用量 0
drwxr-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 monitoring
NAME                          READY   STATUS    RESTARTS   AGE
prometheus-675dd5dc5b-ks9k4   1/1     Running   0          9s
[root@k8s-01 prometheus]# kubectl logs -f prometheus-675dd5dc5b-ks9k4 -n monitoring
ts=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:9090
ts=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.yml
ts=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µs
ts=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.yaml
apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: monitoring
  labels:
    app: prometheus
spec:
  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   SELECTOR
prometheus   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.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: monitoring
spec:
  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: v1
kind: Service
metadata:
  name: grafana
  namespace: monitoring
spec:
  type: NodePort
  ports:
    - port: 3000
  selector:
    app: grafana
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: grafana-local
  labels:
    app: grafana
spec:
  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: v1
kind: PersistentVolumeClaim
metadata:
  name: grafana-data
  namespace: monitoring
spec:
  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 monitoring
NAME                          READY   STATUS    RESTARTS   AGE
grafana-7cfd74ccf5-crcnz      1/1     Running   0          3m57s
prometheus-675dd5dc5b-ks9k4   1/1     Running   0          11d
[root@k8s-01 prometheus]# kubectl get svc -n monitoring
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
grafana      NodePort   10.96.57.144    <none>        3000:32052/TCP   13m
prometheus   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_tran**it_bytes_total[1m]))  # 网卡IO(出)

节点监控部署

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

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

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: kube-system
  labels:
    app: node-exporter
spec:
  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 -owide
NAME                  READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
node-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/metrics
curl http://192.168.31.161:9100/metrics
curl http://192.168.31.162:9100/metrics

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

[root@k8s-01 ~]# netstat -antp|grep 9100
tcp        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云原生集群节点性能监控指标就展示到模板上,如下图:

 

[更多云原生监控运维,请关注微信公众号:云原生生态实验室]

 

点赞收藏
云原生生态实验室

关注公众号@reactor_2020

请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

实现定时任务的六种策略

实现定时任务的六种策略

0
0