Kubernetes 教學 第五篇(Cluster Monitoring 篇)

毫無疑問,在這邊我們主要會使用 Prometheus 來監控 Cluster,但是在這之前,我們要先介紹 k8s 的 DaemonSet

DaemonSet

DaemonSet 能確保 Cluster 中的每個滿足條件的 Node 上面都能運行一個特定的 Node,因此通常用於部署系統級別的服務,例如監控、Log 收集、CNI 插件等,這些服務理所應當的需要在每個 Node 上執行。

$ kubectl get daemonsets  -A
NAMESPACE        NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-system    calico-node       1         1         1       1            1           kubernetes.io/os=linux   5d22h
calico-system    csi-node-driver   1         1         1       1            1           kubernetes.io/os=linux   5d22h
metallb-system   speaker           1         1         1       1            1           kubernetes.io/os=linux   13d

創建我們自己的 Node Exporter DaemonSet:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    app: node-exporter
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      containers:
      - name: node-exporter
        image: quay.io/prometheus/node-exporter:v1.8.2
        args:
          - --path.procfs=/host/proc
          - --path.sysfs=/host/sys
        ports:
        - name: metrics
          containerPort: 9100
        volumeMounts:
        - name: proc
          mountPath: /host/proc
          readOnly: true
        - name: sys
          mountPath: /host/sys
          readOnly: true
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: sys
        hostPath:
          path: /sys

以及 Service:

apiVersion: v1
kind: Service
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    app: node-exporter
spec:
  selector:
    app: node-exporter
  ports:
  - name: metrics
    port: 9100
    targetPort: 9100
    protocol: TCP
  type: ClusterIP

我們就可以看到新建成功的樣子了:

$  kubectl get daemonset,deployment,pod,svc -n monitoring
NAME                           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/node-exporter   1         1         1       1            1           <none>          41m

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/grafana             1/1     1            1           6d19h
deployment.apps/prometheus-server   1/1     1            1           6d19h

NAME                                     READY   STATUS    RESTARTS   AGE
pod/grafana-6964b5687d-nts7c             1/1     Running   0          5d22h
pod/node-exporter-jq54f                  1/1     Running   0          5m17s
pod/prometheus-server-65648cd94f-w7bzv   1/1     Running   0          26m

NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/grafana             ClusterIP   10.152.183.109   <none>        3000/TCP   6d19h
service/node-exporter       ClusterIP   10.152.183.62    <none>        9100/TCP   40m
service/prometheus-server   ClusterIP   10.152.183.125   <none>        9090/TCP   6d19h
為 DaemonSet 配置 DNS

我們可以創建一個 Service,例如透過 selector 來匹配該 DaemonSet 的 Pod,然後將 Cluster-IP 設爲 None(即 Headless Service),這樣我們就可以透過 <pod-name>.<service-name>.<namespace>.svc.cluster.local 來訪問每一個 Pod 了。

但這也會遇到問題,如果整個 DaemonSet 被重啓,那麽 Pod 的名稱也會改變,DNS 也會隨之改變,因此這方面的設定會很麻煩。

因此,遇到這種情況,直接使用 NodePort 或是 HostPort 將更方便,而且也更直觀:對應到某個 Node 的那個 Pod,就是在搜集那個 Node 的資訊。

其他監控 Kubernetes 的方式

剛才我們提及了使用 DaemonSet 開 Node Exporter 來監控 Cluster,但這個其實只是監控每個 Node 的主機狀況(因爲 Node Exporter 本身就是監控 Linux 主機的 Prometheus Exporter,不是針對 K8S 的),沒辦法帶我們很好的理解每個 Pod 的情況和網路運作狀況。

所以如果真的有監控每個 Pod 的需求,可以考慮使用 kube-state-metrics

而監控網路的部分,很多 CNI 插件都已經提供了内建的 Prometheus Exporter,只需要開啓即可,例如 Monitor Calico component metrics

而還有 Log 收集、分析的部分,就可以參考 Deploy ECK in your Kubernetes cluster,這篇文章是針對 Elastic Cloud on Kubernetes 而撰寫的,基本上就是 ELK stack,而其中的 Elasticsearch 恰好很適合我們下面介紹的 StatefulSet(分散式、長期資料儲存)。


淺談 K8S 中常用的 Controllers

除了我們之前一直在使用的 Deployment 和剛剛介紹的 DaemonSet,k8s 還提供了其他的 Controller。

比較常使用的還有例如 StatefulSet、CronJob 等。

有必要在此特別介紹 StatefulSet,顧名思義,他適合那些需要保持狀態的應用程式。這些應用程式通常需要穩定、一致的命名、網路配置(IP、DNS)和持久化 Storage。

不變的命名和網路配置很好理解,我們以往創建的那些 Pod 名字中基本上都帶有個隨機後綴。而 StatefulSet 創建的 Pod 則是規律的,按照流水號排下去。

而説到持久化 Storage,你可能會想到之前介紹過的 Persistent Volume Claim,也是為 Pod 創建一個穩定的 Storage,但兩者還是有本質上的區別。

StatefulSet 會為每一個 Pod 創建獨立的 PVC,即使 Pod 被刪除、調度,也會重新掛載最初分配的 PV,確保資料一致性;而一般 Deployment 通常是數個 Pods 共用同一個 PVC,又或是沒有嚴格的對應關係,導致每次 Pod 重啓,都可能會掛載到不同的 PV。

因此 StatefulSet 特別適合來開分散式資料庫服務,如 MySQL 或是 Redis 等。他們每個節點都需要自己維護一份獨立的資料庫來保證資料的一致性,他們也需要穩定的網路身份和命名來進行正確的通信以及確保主從關係。

不過因爲我這邊目前是沒有要部署這種應用程式的需求,所以只能在這邊粗淺的介紹一下。