iT邦幫忙

2021 iThome 鐵人賽

DAY 11
1
DevOps

喬叔帶你上手 Elastic Stack - 探索與實踐 Observability系列 第 11

11 - Metrics - 觀察系統的健康指標 (5/6) - 使用 Metricbeat 掌握 Infrastructure 的健康狀態 Kubernetes 篇

Metrics - 觀察系統的健康指標 系列文章


本篇學習重點

  • Metricbeat 能夠收集 Kubernetes 哪些 Metrics
  • 如何使用 Metricbeat 來收集 Kubernetes 的 Metrics
  • 在 Kibana 上有提供哪些方式,能查看 Metricbeats 所收集的 Metrics

前一篇文章介紹了如何使用 Metricbeat 來掌握 Docker 環境 Infrastructure 的健康狀態,這一篇將來說明 Kubernetes 的環境,我們要如何使用 Metricbeat 來掌握各種健康狀態的 Metrics。

Metricbeat 在 Kubernetes 環境中,能收集哪些 Metrics

這邊我們分成以下三個部份來說明:

  • System Metrics: 我們在 Kubernetes 環境中的每個 Node,我們都應該要收集這些 Nodes 的系統 Metrics,所以這邊就會要使用 Metricbeat 的 system module 來收集。
  • Kubernetes Metrics: 在 Kubernetes 的環境之中,Kubernetes 本身有許多運作的功能與機制,這部份 Metricbeat 有特別針對 Kubernetes 開發 kubernetes module 裡面有收集非常豐富的 Metrics,下面會針對這個 module 獨立介紹。
  • 其他運作在 Kubernetes 上的服務的 Metrics: 這部份就會使用 Metricbeat 所支援的各種服務的 modules,細節可以參考 官方文件 Metricbeat Modules [1]。

Metricbeat Kubernetes Module

這邊我們來說明 Metricbeat 針對 Kubernetes 所開發的 Module 有哪些功能。

Kubernetes module 有收集以下 Kubernetes 元件的 Metrics:

由於這些元件之中, kubeletproxy 是運作在 Cluster 當中的每個 Node 身上,所以會是 Node 層級,而其他的元件是運作在 Cluster 層級,因此不同層級也會有不同的佈署與收集方式,以下我整理一個表格,將 Kubernetes module 所支援的 metricset 進行分類說明。

Metricset 名稱 收集的方式 層級 適用的佈署方式
container, node, pod, system, volume kubelet endpoint (Default HTTP port: 10250) Node DaemonSet
state_node, state_daemonset, state_deployment, state_replicaset, state_statefulset, state_pod, state_container, state_cronjob, state_resourcequota, state_service, state_persistentvolume, state_persistentvolumeclaim, state_storageclass, event kibe-state-metrics 需另外安裝的 Service (Standard Example HTTP port: 8080) Cluster DaemonSet 之中的 Leader Pod
apiserver Kubernetes /metrics API Cluster DaemonSet 之中的 Leader Pod
proxy proxy endpoint (Default HTTP port: 10249) Node DaemonSet
scheduler scheduler endpoint 需另外 create kube-scheduler service (Default HTTP port: 10259) Cluster DaemonSet 之中的 Leader Pod
controller-manager controller-manager endpoint 需另外 create kube-controller-manager service (Default HTTP port: 10257) Cluster DaemonSet 之中的 Leader Pod

使用 Metricbeat 監控 Kubernetes 的 Metrics

接下來,我們要來實際說明佈署的方式,在進行實作之前,先介紹在 Kubernetes 上部署 Metricbeat 的方法。

在 Kubernetes 上部署 Metricbeat 的方法

首先,要在 Kubernetes 裡佈署 Metricbeat 的方式有兩種,這邊先簡介這兩種的概念,接下來的實例,將帶大家了解如何實作。

DaemonSet

由於 Kubernetes DaemonSet 的設計,讓我們能夠輕易的確保 Metricbeat 能運作且常駐在 Kubernetes Cluster 中的每一個 Node 身上,並且可以在這個 Node 上只啟動一個 Instance (一個 Pod),讓這個 Metricbeat 負責收集這個 Node 的 System Metrics 以及運作在這個 Node 身上其他 Pods 的各種服務的 Metrics。

因此在使用 Metricbeat 來監控 Kubernetes Cluster 的基本配置方式,就是將 Metricbeat 佈署成 DaemonSet。

另外 Metricbeat 有實作 Leader Election [2],在 Cluster DaemonSet 中只有一個 Metricbeat Pod,會被選為 leader,我們就可以使用這個 leader pod 來負責收集 Cluster 層級的 Metrics,避免 Cluster 中若是有多個 Metricbeat 都在收集 Cluster 層集的 Metrics,會收集到重覆的資料。

Deployment

除了使用 DaemonSet 的方式來佈署,我們當然也可以使用 Deployment 的方式來佈署 Metricbeat,但是什麼時候會用到這種方法呢?

主要是當 Cluster 規模愈大時,上面所提到 leader pod 很可能會因為資源不足,無法處理這樣大量級的資料,這時就應該考慮使用獨立的 Instance 來佈署 Metricbeat,以專門收集 Cluster 層級的 Metrics。

實際的佈署

我們這邊使用官方提供的一個 Metricbeat-Kubernetes 範例 [3] 來進行拆解說明。

ConfigMap metricbeat-deamonset-config

在這個 ConfigMap 當中,定義了主要運作成為 DaemonSet 的 Metricbeat 的主要設定,也就是 metricbeat.yml 的配置。

apiVersion: v1
kind: ConfigMap
metadata:
  name: metricbeat-daemonset-config
  namespace: kube-system
  labels:
    k8s-app: metricbeat
data:
  metricbeat.yml: |-
    metricbeat.config.modules:
      # Mounted `metricbeat-daemonset-modules` configmap:
      path: ${path.config}/modules.d/*.yml
      # Reload module configs as they change:
      reload.enabled: false

    metricbeat.autodiscover:
      providers:
        - type: kubernetes
          scope: cluster
          node: ${NODE_NAME}
          unique: true
          templates:
            - config:
                - module: kubernetes
                  hosts: ["kube-state-metrics:8080"]
                  period: 10s
                  add_metadata: true
                  metricsets:
                    - state_node
                    - state_deployment
                    - state_daemonset
                    - state_replicaset
                    - state_pod
                    - state_container
                    - state_cronjob
                    - state_resourcequota
                    - state_statefulset
                    - state_service
                - module: kubernetes
                  metricsets:
                    - apiserver
                  hosts: ["https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"]
                  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
                  ssl.certificate_authorities:
                    - /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
                  period: 30s
                # Uncomment this to get k8s events:
                #- module: kubernetes
                #  metricsets:
                #    - event
        # To enable hints based autodiscover uncomment this:
        #- type: kubernetes
        #  node: ${NODE_NAME}
        #  hints.enabled: true

    processors:
      - add_cloud_metadata:

    cloud.id: ${ELASTIC_CLOUD_ID}
    cloud.auth: ${ELASTIC_CLOUD_AUTH}

    output.elasticsearch:
      hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
      username: ${ELASTICSEARCH_USERNAME}
      password: ${ELASTICSEARCH_PASSWORD}

這裡面的配置我們分成以下來說明:

  • 有定義下面另一組 ConfigMap metricbeat-daemonset-modules 要載入到 modules.d 目錄底的設定。
  • 定義 autodiscover 的設定,這裡指定到 scope: cluster 以及 unique: true,代表這是在整個 DaemonSet 當中,只有 leader 這個唯一的 Pod 會運行,也因此裡面所描述的 Metricset 會是 Cluster 等級的,像是 state_* 以及 event 這樣的 Metricsets。

ConfigMap metricbeat-daemonset-modules

在這個 ConfigMap 裡,定義了主要的 DaemonSet 要執行的 Metricbeat 的模組有哪些

apiVersion: v1
kind: ConfigMap
metadata:
  name: metricbeat-daemonset-modules
  namespace: kube-system
  labels:
    k8s-app: metricbeat
data:
  system.yml: |-
    - module: system
      period: 10s
      metricsets:
        - cpu
        - load
        - memory
        - network
        - process
        - process_summary
        #- core
        #- diskio
        #- socket
      processes: ['.*']
      process.include_top_n:
        by_cpu: 5      # include top 5 processes by CPU
        by_memory: 5   # include top 5 processes by memory

    - module: system
      period: 1m
      metricsets:
        - filesystem
        - fsstat
      processors:
      - drop_event.when.regexp:
          system.filesystem.mount_point: '^/(sys|cgroup|proc|dev|etc|host|lib|snap)($|/)'
  kubernetes.yml: |-
    - module: kubernetes
      metricsets:
        - node
        - system
        - pod
        - container
        - volume
      period: 10s
      host: ${NODE_NAME}
      hosts: ["https://${NODE_NAME}:10250"]
      bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
      ssl.verification_mode: "none"
      # If there is a CA bundle that contains the issuer of the certificate used in the Kubelet API,
      # remove ssl.verification_mode entry and use the CA, for instance:
      #ssl.certificate_authorities:
        #- /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt
    # Currently `proxy` metricset is not supported on Openshift, comment out section
    - module: kubernetes
      metricsets:
        - proxy
      period: 10s
      host: ${NODE_NAME}
      hosts: ["localhost:10249"]

這裡面的配置我們分成以下來說明:

  • 由於這會是每個 Node 都會運行一組的 DaemonSet,所以會要收集系統的 Metrics,這邊有定義了 system.yml 的 System module。
  • 同樣的每個 Node 也都要收集 Node 層級的 Kubernetes Metrics,所以這邊有定義 kuebernetes.yml 使用 Kubernetes module,並且宣告 nodesystempodcontainervolumeproxy 這些 Metricsets。
  • 另外針對不同的 metricset 的來源,會從 kubelet 的 port 10250proxy 的 port 10249 取得 Metrics。

DaemoneSet metricbeat

接下來就是主要的 DaemonSet - metricbeat

# Deploy a Metricbeat instance per node for node metrics retrieval
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: metricbeat
  namespace: kube-system
  labels:
    k8s-app: metricbeat
spec:
  selector:
    matchLabels:
      k8s-app: metricbeat
  template:
    metadata:
      labels:
        k8s-app: metricbeat
    spec:
      serviceAccountName: metricbeat
      terminationGracePeriodSeconds: 30
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: metricbeat
        image: docker.elastic.co/beats/metricbeat:7.14.2
        args: [
          "-c", "/etc/metricbeat.yml",
          "-e",
          "-system.hostfs=/hostfs",
        ]
        env:
        - name: ELASTICSEARCH_HOST
          value: elasticsearch
        - name: ELASTICSEARCH_PORT
          value: "9200"
        - name: ELASTICSEARCH_USERNAME
          value: elastic
        - name: ELASTICSEARCH_PASSWORD
          value: changeme
        - name: ELASTIC_CLOUD_ID
          value:
        - name: ELASTIC_CLOUD_AUTH
          value:
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        securityContext:
          runAsUser: 0
          # If using Red Hat OpenShift uncomment this:
          #privileged: true
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - name: config
          mountPath: /etc/metricbeat.yml
          readOnly: true
          subPath: metricbeat.yml
        - name: data
          mountPath: /usr/share/metricbeat/data
        - name: modules
          mountPath: /usr/share/metricbeat/modules.d
          readOnly: true
        - name: proc
          mountPath: /hostfs/proc
          readOnly: true
        - name: cgroup
          mountPath: /hostfs/sys/fs/cgroup
          readOnly: true
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: cgroup
        hostPath:
          path: /sys/fs/cgroup
      - name: config
        configMap:
          defaultMode: 0640
          name: metricbeat-daemonset-config
      - name: modules
        configMap:
          defaultMode: 0640
          name: metricbeat-daemonset-modules
      - name: data
        hostPath:
          # When metricbeat runs as non-root user, this directory needs to be writable by group (g+w)
          path: /var/lib/metricbeat-data
          type: DirectoryOrCreate

這裡面的配置我們分成以下來說明:

  • 這邊有使用到 DaemonSet 的 selectortemplate ,並指定 Label k8s-app: metricbeat
  • 使用 serviceAccountName: metricbeat
  • /proc/sys/fs/cgroup 給 mount 到 /hostfs 底下,並且在啟動時,指定給 metricbeat: -system.hostfs=/hostfs
  • 將 Elasticsearch 相關的環境變數指定預設定。
  • mount 前面指定好的 ConfigMap metricbeat-daemonset-configmetricbeat-daemonset-modules

ServiceAccount 與相關的權限設定

這部份就不多解釋,請大家自己從設定來參考。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: metricbeat
subjects:
- kind: ServiceAccount
  name: metricbeat
  namespace: kube-system
roleRef:
  kind: ClusterRole
  name: metricbeat
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: metricbeat
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: metricbeat
    namespace: kube-system
roleRef:
  kind: Role
  name: metricbeat
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: metricbeat-kubeadm-config
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: metricbeat
    namespace: kube-system
roleRef:
  kind: Role
  name: metricbeat-kubeadm-config
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: metricbeat
  labels:
    k8s-app: metricbeat
rules:
- apiGroups: [""]
  resources:
  - nodes
  - namespaces
  - events
  - pods
  - services
  verbs: ["get", "list", "watch"]
# Enable this rule only if planing to use Kubernetes keystore
#- apiGroups: [""]
#  resources:
#  - secrets
#  verbs: ["get"]
- apiGroups: ["extensions"]
  resources:
  - replicasets
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources:
  - statefulsets
  - deployments
  - replicasets
  verbs: ["get", "list", "watch"]
- apiGroups:
  - ""
  resources:
  - nodes/stats
  verbs:
  - get
- nonResourceURLs:
  - "/metrics"
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: metricbeat
  # should be the namespace where metricbeat is running
  namespace: kube-system
  labels:
    k8s-app: metricbeat
rules:
  - apiGroups:
      - coordination.k8s.io
    resources:
      - leases
    verbs: ["get", "create", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: metricbeat-kubeadm-config
  namespace: kube-system
  labels:
    k8s-app: metricbeat
rules:
  - apiGroups: [""]
    resources:
      - configmaps
    resourceNames:
      - kubeadm-config
    verbs: ["get"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: metricbeat
  namespace: kube-system
  labels:
    k8s-app: metricbeat

安裝 Kube-state-metrics 以提供 Metricbeat 所需要的 Metrics

由於前面所提到的 kube-state-metrics 並非是 Kubernetes Cluster 預設啟用的功能,這部份會需要透過另外安裝才能啟用這個服務。

以下使用最基本的簡易安裝方式,細節請參考 GitHub kube-state-metrics [4]。

先抓下 GitHub 上專案中建立好的 examples 配置:

git clone https://github.com/kubernetes/kube-state-metrics.git

使用 examples 中的 standard 配置來建立服務:

cd kube-state-metrics
kubectl apply -f examples/standard

成功建立之後,就可以在 kube-system 的 namespace 中看到 kube-state-metricspod 以及對外開啟 8080 port 的 service

11-k9s-kube-state-metrics

這邊使用的工具是 k9s,蠻好用的 Kubernetes 管理工具。

在圖中我們可以看到,由於 kube-state-metrics 是指定給 leader 才會執行,所以我們在 leader 這台 pod 的 logs 才會看到這資訊。

使用 Autodiscovery 透過 Annotation 自動找尋需監控的 Pods

其他運作在 Kubernetes 上的 Service,若是要使用 Metricbeat 的其他 modules 來取得 Metrics,建議可以使用 Autodiscovery 針對 Kubernetes Annotation 所支援的自動監控的功能。

metricbeat.autodiscover:
  providers:
    - type: kubernetes
      templates:
        - condition:
            contains:
              kubernetes.labels.app: "redis"
          config:
            - module: redis
              metricsets: ["info", "keyspace"]
              hosts: "${data.host}:6379"
              password: "${REDIS_PASSWORD}"

例如我們可以針對 kubernetes.labels.appredis 的 pod,設定使用 redis module 來取得 Redis 的 Metrics , 並且套用上面所定義的 config 配置。

在 Kibana 檢視 Kubernetes 的 Metrics

在以上設定安裝完成之後,我們可以透過 Kibana 來查看 Metricbeat 所針對 Kubernetes 收集到的 Metrics。

Kibana Observability Metrics

在 Kibana > Observability > Metrics 裡的 Inventory 中,我們可以針對 Show 指定為 Kubernetes Pods ,並且可以透過 Group by 的方式進行分類,結果如下圖。

11-kibana-observability-metrics-k8s

其他 Inventory 的使用方式,可以參考先前的文章 09 - Metrics - 觀察系統的健康指標 (3) - 使用 Metricbeat 掌握 Infrastructure 的健康狀態 Host 篇 的介紹。

Metricbeat 內建的 Dashboard

由於 Inventory 的檢視方式較為是 Infrastructure 整體的健康度,而 Metricbeat 也有為 Kubernetes 建立了四種 Dashboard,可以讓我們直接使用。

(由於我的測試環境有些資訊沒有呈現出來,所以有幾張圖我直接以官方網站的圖來呈現)

Cluster Overview

11-kibana-dashboard-k8s-overview

Controller Manager

11-metricbeat-kubernetes-controllermanager

Scheduler

11-metricbeat_kubernetes_scheduler

Proxy

11-metricbeat-kubernetes-proxy


Metricbeat 針對 Kubernetes 所收集的資訊相當詳細,相信可以對於我們監控管理 Kubernetes Cluster 有很大的幫助,特別是這些資料進入 Elasticsearch 之後,還能和其他 Obersevability 的資訊進行整合使用,應用的空間還很大呢!

參考資訊

  1. 官方文件 - Metricbeat Modules
  2. Kubernetes client-go - Leader Election
  3. Metricbeat-Kubernetes 範例
  4. GitHub kube-state-metrics

上一篇
10 - Metrics - 觀察系統的健康指標 (4/6) - 使用 Metricbeat 掌握 Infrastructure 的健康狀態 Docker 篇
下一篇
12 - Metrics - 觀察系統的健康指標 (6/6) - 使用 Metricbeat 掌握 Infrastructure 的健康狀態 AWS 篇
系列文
喬叔帶你上手 Elastic Stack - 探索與實踐 Observability31

尚未有邦友留言

立即登入留言