Posted on

在K8S內ksoftirqd耗費大量CPU

問題描述

我們在K8S內架設串流伺服器,在做loadtest時發現,當流量變高之後,K8S用來管理線程的cadvisor所調用的ksoftirqd會占掉非常大的CPU使用率,並導致整個worker node變得緩慢。

相關的問題說明請見: Debugging network stalls on Kubernetes

形成原因

這是因為當使用 Kubernetes 的 NodePort 來公開一個服務時,它將在每個工作節點上開放一個端口,以便外部可以連接到該端口,並將流量轉發到服務的後端 Pod 上。當流量高峰期間,可能會導致節點的 CPU 負載增加,並導致大量的 IRQ 請求,這是因為每個數據包都會觸發一次 IRQ 請求。

IRQ 是中斷請求的簡寫,是一種處理設備 I/O 操作的機制。當設備有 I/O 操作時,它會觸發一個中斷請求,通知操作系統或應用程序需要處理這個 I/O 操作。在網絡通信中,每個數據包都會觸發一次 IRQ 請求,因此當流量高峰期間,大量的 IRQ 請求可能會導致節點的 CPU 負載增加,從而影響應用程序的性能。

為了減輕這個問題,您可以考慮使用負載均衡器來替代 NodePort,將流量分發到多個節點上,從而分散 CPU 負載。您還可以考慮對節點進行調優,以提高節點的性能和吞吐量。例如,可以調整節點的 CPU 和內存資源配額,優化網絡配置,減少網絡延遲等。此外,也可以嘗試使用更高效的網絡協議,如 UDP 協議,以減少 CPU 負載。

IRQ是甚麼

IRQ(Interrupt Request)是計算機系統中的中斷請求,它是用來通知 CPU 執行特定的操作的信號。中斷請求通常由外部設備發出,例如鍵盤、鼠標、網卡、磁盤控制器等,這些設備需要與 CPU 進行通信,以便進行數據傳輸、讀寫、處理等操作。

IRQ 的實現通常涉及到硬件和軟件兩個方面。在硬件方面,通常需要在主板上預留一些專門的中斷請求線(IRQ lines),用於連接各種外設和 CPU,以便它們之間進行數據傳輸和通信。一般來說,一個計算機系統會有多個 IRQ lines,每個 IRQ line 對應一個外設或者一組相關的外設。

在軟件方面,操作系統需要通過中斷控制器來管理各個 IRQ lines,以便在接收到外設發出的中斷請求時,及時地響應並處理。一般來說,中斷控制器會將中斷請求轉發給 CPU,CPU 再執行相應的中斷處理程序來處理中斷請求。

IRQ是計算機硬件的設計決定。當網絡適配器(NIC)接收到數據包時,它會發送一個中斷請求(IRQ)給處理器,通知處理器需要處理這個數據包。處理器收到 IRQ 後,會停止當前的任務,並開始處理中斷請求。處理完中斷請求後,處理器會返回到之前的任務繼續執行。.

網絡適配器是什麼

網絡適配器,也稱為網絡接口卡(Network Interface Card,NIC),是計算機中用於實現網絡通信的硬件設備之一。它通常安裝在計算機主板上,負責接收和發送網絡數據包。網絡適配器可以連接到不同類型的網絡,例如以太網、Wi-Fi、藍牙等,以實現不同的網絡通信方式。

網絡適配器在計算機中的作用是將數據轉換為網絡能夠識別和傳輸的格式,例如將數據包封裝成以太網幀,以便在以太網上進行傳輸。同時,網絡適配器也負責監控網絡上的數據流量,並在需要時觸發 IRQ 請求,通知處理器需要處理數據包。

網絡適配器的性能對網絡通信的效率和吞吐量有很大影響。在高性能計算環境中,通常會選擇高速的網絡適配器,例如 10GbE、40GbE、100GbE 等,以滿足大規模數據傳輸的需求。

為什麼在K8S的IQR會比一般Linux主機更明顯

當一般主機傳輸大量流時,也會產生網絡適配器的 IRQ 請求。但是,這種情況下的 IRQ 請求通常可以被系統有效地處理,並不會對 CPU 的負載產生太大的影響。這是因為一般主機的網絡適配器通常採用了更為先進的中斷卸載技術,如 RSS(Receive Side Scaling)、RPS(Receive Packet Steering)等,可以將 IRQ 請求在多個 CPU 核心上進行分配,從而有效地提高系統的網絡吞吐量。

在 Kubernetes 中,由於每個節點上的 Pod 分佈不確定,因此無法像一般主機那樣進行有效的中斷卸載。此外,由於網絡流量是從 NodePort 直接傳輸到 Pod,中間可能還需要經過多個網絡層,從而增加了系統的網絡負載。因此,在高負載情況下,使用 NodePort 公開服務可能會導致大量 IRQ 請求,從而增加 CPU 的負載。為了解決這個問題,可以考慮使用負載均衡器等技術,將流量轉發到多個節點上,以降低單個節點的負載。

解決方法

由於我們所架設的伺服器為串流伺服器,原本在一般的Linux主機裡面,我們會使用NGINX去做反向代理,讓主機知道現在的連接目標為串流,如下面這個nginx.conf的範例

http {
    include       mime.types;
    default_type  application/octet-stream; #設定所傳輸的格式為串流
    sendfile        on;
}

這樣子當有人透過http去拉取串流時,NIC就會採取長連接的方式去處理這條串流,但是,因為現在我們將串流伺服器移到K8S裡面去,連線請求處理的地方會在worker node所在的NIC上去處理,而不是在串流服務的POD去處理的。因此,即便我們在POD裡面設定連線方式為串流,在worker node上面也是不知道這件事情的。

所以我們會必須要在K8S的ingress裡面去做進一步的設定,第一步要先了解自己的K8S的ingress是用甚麼實作的,例如像我們的K8S是用kubernetes/ingress-nginx實作的

設定介紹: NGINX Configuration

這邊會有三個方式去實作

  1. ConfigMap:使用 Configmap 在 NGINX 中設置全局配置。
  2. Annotations:如果您想要特定 Ingress 規則的特定配置,請使用它。
  3. 自定義模板:當需要更具體的設置時,如open_file_cache,調整監聽選項,rcvbuf或者當無法通過 ConfigMap 更改配置時。

以下是一個使用 types 設置 MIME 類型的示例:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/server-snippet: |
      types {
        text/html                             html htm shtml;
        text/css                              css;
        text/xml                              xml;
        image/gif                             gif;
        image/jpeg                            jpeg jpg;
        application/javascript               js;
        application/atom+xml                  atom;
        application/rss+xml                   rss;
        text/mathml                           mml;
        text/plain                            txt;
        text/vnd.sun.j2me.app-descriptor      jad;
        text/vnd.wap.wml                      wml;
        text/x-component                      htc;
        image/png                             png;
        image/tiff                            tif tiff;
        image/vnd.wap.wbmp                    wbmp;
        image/x-icon                          ico;
        image/x-jng                           jng;
        image/x-ms-bmp                        bmp;
        image/svg+xml                         svg svgz;
        image/webp                            webp;
        application/font-woff                 woff;
        application/font-woff2                woff2;
        application/vnd.ms-fontobject         eot;
        application/x-font-ttf                ttc ttf;
        application/x-httpd-php               php;
        application/x-shockwave-flash         swf;
        application/json                      json;
        application/octet-stream              flv; #這邊可以設定MINE TYPE
      }
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  name: http

這樣子就可以正確的於ingress處理串流的連接了!

相關官方說明: Annotations – Ingress-Nginx ControllerCustom Headers – Ingress-Nginx Controller

Posted on

使用Helm來部署K8S

Helm介紹

Helm 是一個 Kubernetes 包管理器,它可以幫助您在 Kubernetes 上部署和管理應用程序。Helm 允許您定義、安裝和升級 Kubernetes 應用程序,並且可以管理它們的依賴關係。

Helm 由兩部分組成:Helm CLI 和 Helm Charts。Helm CLI 是一個命令行界面,用於管理 Helm Charts。Helm Charts 是一個包含 Kubernetes 资源描述文件的打包文件,例如 Deployment、Service、Ingress、ConfigMap 等等。這些文件被打包到壹個壓縮文件中,通常是 tar.gz 或 zip 格式。

使用 Helm,您可以通過創建自己的 Charts 或者使用社區提供的 Charts 快速部署應用程序。您可以使用 Helm Charts 定義 Kubernetes 资源,然後通過 Helm CLI 安裝 Charts 來創建和管理 Kubernetes 资源。

Helm 還允許您管理 Charts 的版本控制,從而使您可以輕鬆地升級或回滾到先前的版本。此外,Helm 還支持模板化和參數化 Charts,從而使您可以通過使用不同的參數集在不同的環境中部署同一個 Chart。

Helm的安裝

  1. 下載 Helm: 下載頁面有各個作業系統的下載檔案,這邊是官方的安裝指南(Installing Helm)
  2. 解壓 Helm
  3. 將 Helm 的執行文件複製到可執行路徑中,若為linux可能為/usr/local/bin/,若為Window則為C:\Users\my_name
  4. 驗證 Helm 是否正確安裝。運行以下命令應該會顯示 Helm 的版本信息: helm version

Helm的使用指令

這邊是使用的指令碼的介紹: https://helm.sh/docs/intro/using_helm/

創建新的專案可用下面指令

helm install happy-panda bitnami/wordpress

會有類似這樣的資料夾結構

其中Chart.yaml會在創建時設定好,values.yaml可以設定在templates要使用的變數,而templates則是要放我們要部署的YAML設定檔。

接著用下面的指令就可以部署到K8S了!

helm upgrade --install -n stu-srs --set APP_ENV=QAT srs-core1 . --values ./values-core1.yaml --version v1.0.0 
Posted on

Prometheus Exporter: json-exporter

甚麼是JSON Exporter

JSON Exporter是一個Prometheus的exporter(指標收集器),它能夠從提供JSON格式的API中收集指標數據,並將這些數據轉換為Prometheus所支持的格式,以便Prometheus進行分析和視覺化。

JSON Exporter的運行方式是通過設置JSON配置文件,其中包括API端點和相關的指標數據,然後使用Prometheus的配置文件將JSON Exporter添加到Prometheus的targets列表中。

JSON Exporter可以收集各種不同類型的指標數據,例如計數器(counters)、量規(gauges)和直方圖(histograms)等,並可以根據需要對數據進行轉換和聚合。

如何設置Exporter

在官方的Writing exporters文件中,有下面這一段

Each exporter should monitor exactly one instance application, preferably sitting right beside it on the same machine. That means for every HAProxy you run, you run a haproxy_exporter process. For every machine with a Mesos worker, you run the Mesos exporter on it, and another one for the master, if a machine has both.

The theory behind this is that for direct instrumentation this is what you’d be doing, and we’re trying to get as close to that as we can in other layouts. This means that all service discovery is done in Prometheus, not in exporters. This also has the benefit that Prometheus has the target information it needs to allow users probe your service with the blackbox exporter.

這段的意思是說,Exporter盡量和主要的Container放在同一個POD裡面,如下圖:

這樣做主要的原因是可以避免單點失敗,且更符合微服務架構的理念。

實作概要

下面是輸出的JSON檔案的範例

{
  "code": 0,
  "server": "vid-69t27o3",
  "streams": [
    {
      "id": "vid-0diw412",
      "name": "livestream",
      "vhost": "vid-y000397",
      "app": "live",
      "tcUrl": "rtmp://172.16.46.86:1935/live",
      "url": "/live/livestream",
      "live_ms": 1681903514993,
      "clients": 4,
      "frames": 0,
      "send_bytes": 45370,
      "recv_bytes": 34930,
      "kbps": {
        "recv_30s": 0,
        "send_30s": 0
      },
      "publish": {
        "active": false
      },
      "video": null,
      "audio": null
    }
  ]
}

下面是json-exporter的config.yml

modules:
  default:
    metrics:
    - name: server
      path: "{ .server}"

    - name: stream_clients
      type: object
      help: Example of sub-level value scrapes from a json
      path: '{.streams[?(@.name!="")]}'
      labels:
        name: '{.name}' 
      values:
        clients: '{.clients}' 
        send_bytes: '{.send_bytes}'
        recv_bytes: '{.recv_bytes}'
        frames: '{.frames}'
        publish: '{.publish.active}'

    headers:
      X-Dummy: my-test-header

設定要監控的POD的YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/instance: srs-core1
  name: srs-core1
  namespace: stu-srs
spec:
  template:
    metadata:
	  creationTimestamp: null
      labels:
        app.kubernetes.io/instance: srs-core1
	containers:
      ....Other container here
      - image: dev-registry.xycloud.org/ldr/streaming/json-exporter
        imagePullPolicy: IfNotPresent
        name: json-exporter
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
		args: ["--config.file", "/config.yml"]
        volumeMounts:
        - mountPath: /config.yml
          name: json-exporter
          subPath: config.yml
	volumes:  
      - configMap:
          defaultMode: 420
          name: json-exporter
        name: json-exporter

進入該POD的SHELL裡面查看Json-exporter所吐的資料

curl "http://localhost:7979/probe?target=http://127.0.0.1:1985/api/v1/streams/"

可以把資料串到Prometheus了

請參考以下文章

  1. 查看普羅米修斯某的pod內所有的值
  2. 查看普羅米修斯監控目標的exporter資訊
Posted on

HorizontalPodAutoscalers by customize metric

設定擴充的行為,sacle down及up的時候所做的行為,這邊的設定是假如維持300秒都穩定相同狀況,則做HPA縮放,最少維持這種狀態60秒,一次增加1個Pod​

這邊則設定要參考的數值,若是要使用自訂義資料,則describedObject這邊要設定的與我們在Rules裡面設定的一致,target部分則設定每一個pods的目標值為多少​

下面scaleTargetRef的部分則是設定要做HPA的目標是甚麼,有可能是Services,這邊做HPA的目標則為Pod​

apiVersion: autoscaling/v2beta2​
kind: HorizontalPodAutoscaler​
metadata:​
  name: srs-edge​
  namespace: srs3​
spec:​
  behavior:​
    scaleDown:​
      policies:​
      - periodSeconds: 60​
        type: Pods​
        value: 1​
      selectPolicy: Max​
      stabilizationWindowSeconds: 300​
    scaleUp:​
      policies:​
      - periodSeconds: 60​
        type: Pods​
        value: 1​
      selectPolicy: Max​
      stabilizationWindowSeconds: 300​
  maxReplicas: 2​
  metrics:​
  - object:​
      describedObject:​
        apiVersion: v1​
        kind: Service​
        name: eventqueue​
      metric:​
        name: stream_total_clients_by_pod​
      target:​
        type: Value​
        value: 1k​
    type: Object​
  minReplicas: 1​
  scaleTargetRef:​
    apiVersion: apps/v1​
    kind: Deployment​
    name: srs-edge​

stream_total_clients_by_pod是我們的客製化變數,這個變數是來自於普羅米修斯,要把普羅米修斯的變數給k8s使用,請參見
http://claire-chang.com/2022/12/16/prometheus-rule-for-alert/
這邊很重要的是可以看到label裡面有name: eventqueue,在Prometheus Rule裡一定也要加上labels: service: eventqueue
這樣這個值才會可以被輸出給普羅米修斯使用

如下圖:

其他更多的設定值請見: https://docs.openshift.com/container-platform/4.9/nodes/pods/nodes-pods-autoscaling.html​

Posted on

查看普羅米修斯某的POD內所有的值

Prometheus 指令

使用的指令如下:

sum by(__name__)({namespace="default",pod="pod_name", __name__=~".*"})

解釋如下:

  • sum by(__name__) 是一個 Prometheus 查詢語句,用於計算符合指定條件的指標值之和,並根據指標名稱進行分組。
  • {namespace="default",pod_name="my-pod"} 是一個標籤選擇器 (label selector),用來選擇符合條件的 POD。其中,namespace 表示命名空間 (namespace),pod_name 表示 POD 名稱。
  • __name__=~"MEERIC.*" 是一個正則表達式選擇器 (regular expression selector),用於選擇符合特定模式的指標名稱。在本例中,我們使用 ~ 運算符將正則表達式 "MEERIC.*" 用於指標名稱,以找到符合條件的指標。這個正則表達式的意思是:以 MEERIC 開頭的所有指標名稱。
  • __name__ 是一個特殊的標籤 (label),代表指標名稱。使用 sum by 子句時,我們將其作為分組條件之一,以根據指標名稱對指標值進行分組。

設定ServiceMonitor

在可以看到所有的值之後,就可以確認你的ServiceMonitor是否正確,可以來設定ServiceMonitor讓普羅米修斯監控正確的對象

以下為一個簡單的範例

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app.kubernetes.io/instance: srs-json-exporter
  name: json-exporter
  namespace: stu-dashboard
spec:
  endpoints:
  - interval: 30s
    params:
      module:
      - default
      target:
      - http://127.0.0.1:1985/api/v1/streams/
    path: probe
    port: json-exporter
  jobLabel: jobLabel
  namespaceSelector:
    matchNames:
    - stu-srs
  selector:
    matchLabels:
      app: json-exporter

更多關於ServiceMonitor可用的設定值請見:
https://docs.openshift.com/container-platform/4.9/rest_api/monitoring_apis/servicemonitor-monitoring-coreos-com-v1.html

Posted on

使用kubectl進入某個pod裡的某個container的指令

使用kubectl進入container

若要使用 kubectl 進入某個 pod 裡的某個 container,您可以使用 kubectl exec 命令。以下是一個範例指令:
kubectl exec -it -n –container — /bin/sh
在這裡,請將 <pod_name> 替換為您想要進入的 pod 的名稱,將 <container_name> 替換為您想要進入的 container 的名稱。這個指令會使用 /bin/bash shell 進入 container,如果該 container 沒有 /bin/bash,您可以嘗試使用 /bin/sh 作為替代:

kubectl exec -it -n <namespace> <pod_name> -c <container_name> -- /bin/sh

請注意,這些指令假設您已經成功地安裝並設置了 kubectl,並能夠與 Kubernetes 集群通信。

設定kubectl的方法

要配置 kubectl,您需要一個包含集群連接信息的 kubeconfig 文件。通常,當您使用雲服務提供商(如 GKE、EKS 或 AKS)或 Kubernetes 配置工具(如 kopskubeadm)建立集群時,它們會自動為您生成一個 kubeconfig 文件。

kubeconfig 文件通常位於 ~/.kube/config。您可以使用環境變量 KUBECONFIG 來指定 kubeconfig 文件的位置,例如:
export KUBECONFIG=~/.kube/my-kubeconfig.yaml
Kubeconfig file將內容複製到 ~/.kube/config 位置即可​裡面

下載kubectl 或者Lens

即可於本機​ 對K8S下指令

Posted on

查看普羅米修斯監控目標的exporter資訊

Prometheus Target

普羅米修斯 (Prometheus) 是一套開源的監控系統,其中一個重要的功能就是監控 Service (服務) 的運作狀態,這個功能被稱為 Service Monitoring。

Service Monitoring 可以藉由 exporter,透過定義 HTTP endpoints 的方式,監控這些服務的運作狀態。普羅米修斯會定期呼叫這些 endpoints ,並且收集回應的 metrics 以了解服務是否正常運作、服務的吞吐量、延遲、錯誤率等相關資訊。

Service Monitoring 可以提供以下的監控能力:

  • 監控服務的可用性,例如偵測服務是否還在運作、是否正常回應等等。
  • 監控服務的效能,例如服務的吞吐量、延遲等等。
  • 記錄服務的執行狀態,例如錯誤率、請求數量、處理時間等等。
  • 透過 Service Monitoring,可以提升系統的可用性、效能及穩定性,讓系統管理者能夠更快速地偵測到問題、快速修復問題,降低系統的 downtime,提高系統的可靠度。

如何瀏覽exporter的內容

先到普羅米修斯的網頁的Target的地方,會可以看到現在的監控目標,如果設定的目標沒有正確出現,則可以去Service Discovery的頁籤去確認原因。

內容長這樣

無法存取rancher-monitoring-kubelet的exporter吐出的內容


serviceMonitor/kube-system/rancher-monitoring-kubelet/1 (7/7 up)
普羅米修斯在取得Pod的相關狀態是利用rancher-monitoring-kubelet這個POD來取得相關資訊,但是我們會沒有辦法直接去讀取https://127.0.0.1:10250/metrics/cadvisor這個網址,這是因為要讀取需要先透過K8S的認證
# 取得該namespace的所有密鑰​
kubectl get secret -n cattle-monitoring-system​

# 取得密鑰的內容​
kubectl -n cattle-monitoring-system get secret rancher-monitoring-prometheus-token-hvlqt -o jsonpath={.data.token} | base64 –d​

# 將pod-exporter的網址後面加上-H並帶入密鑰​
curl https://127.0.0.1:10250/metrics/cadvisor -k -H “Authorization: Bearer token_content_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”​

Service Monitor抓不到監控目標的可能原因

以下為一個簡單範例

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  generation: 4
  labels:
    app.kubernetes.io/instance: srs-json-exporter
    manager: agent
    operation: Update
  name: json-exporter
  namespace: stu-srs
spec:
  endpoints:
  - interval: 30s
    params:
      module:
      - default
      target:
      - http://127.0.0.1:1985/api/v1/streams/
    port: json-exporter
  jobLabel: jobLabel
  namespaceSelector:
    matchNames:
    - stu-srs
  selector:
    matchLabels:
      app.kubernetes.io/instance: srs-json-exporter

在selector 字段指定要監控的 Service 的標籤選擇器,而不是 Pod 的標籤選擇器。

在這個 YAML 配置文件中,ServiceMonitor 的 selector 字段設置為 matchLabels: app: json-exporter,這代表 ServiceMonitor 將監控符合 app: json-exporter 標籤的 Service。
如果這個 Service 沒有符合 app: json-exporter 標籤,那麼 ServiceMonitor 就無法監控這個 Service。

如果您確認了 Service 的標籤設置是正確的,那麼可能是因為 ServiceMonitor 與 Service 所在的命名空間不匹配,導致 ServiceMonitor 無法監控 Service。
您可以檢查 ServiceMonitor 的 namespaceSelector 設置是否正確。namespaceSelector 字段指定要監控的命名空間。如果這個 Service 所在的命名空間不在 matchNames 列表中,那麼 ServiceMonitor 就無法監控這個 Service。

Posted on

在K8S內node js紀錄log的解決方案

千萬不要使用PM2

PM2是一個在linux裡面管理nodejs程序的好工具,它可以讓nodejs在死掉時自動控制重啟,並可於重啟次數超過時停止重啟
但是由於在K8S之中,這種管理的機制已經交由K8S去管理了,因此,若再於裡面包一層PM2,很容易出問題

可能發生的問題

  • pm2 一開始起來時會依你的參數去試著把 resource 給最大化,所以會一下子把 resource 吃滿,這會讓 k8s 覺得 是不是這個 pod 又很忙了,就馬上又起一個 pod 要來試著接手
  • pm2 會自己重啟 node process : 這會讓 k8s 不知道其實 pod 已經死了,就不會再建新的 pod 來接手

PM2其他功能的替代方案

因為PM2的部分功能與K8S重疊,不推薦使用,那關於PM2另外的文字檔log功能,則有幾種方案可解決

  • container 是吐到 stdout,k8s 的 cri 會寫到 host 上
  • 自己實作log系統

而我們公司由於管K8S的系統的運營部門不處理我們的log的儲存以及打至ELK裡的問題,所以就只能採用第二種方案,以下為我們nodeJS的解決方案log4js

使用nodeJS所推出的log管理系統

https://www.npmjs.com/package/log4js
官方的說明非常簡單好懂,下面為一個基礎使用範例,可每日分檔案,儲存三天

const log4js = require("log4js");
log4js.configure({
    appenders: {
        log: { type: "dateFile", filename: "logs/log.log", pattern: "yyyy-MM-dd", layout: { type: "pattern", pattern: "[%d] %m", }, keepFileExt: true, fileNameSep: "-", numBackups: 3 },
        error: { type: "dateFile", filename: "logs/error.log", pattern: "yyyy-MM-dd", layout: { type: "pattern", pattern: "[%d] %m", }, keepFileExt: true, fileNameSep: "-", numBackups: 3 },
    },
    categories: { default: { appenders: ["log"], level: "debug" }, error: { appenders: ["error"], level: "error" } }
});
var logger = log4js.getLogger();
var logger_error = log4js.getLogger("error");
logger.level = "debug";

exports.log = (...msg) => {
    logger.debug(...msg);
}

exports.error = (...msg) => {
    logger_error.error(...msg);
}
Posted on

把普羅米修斯的資料打到ELK

下載Metricbeat的docker版本​

官網介紹: https://www.elastic.co/beats/metricbeat
其中給普羅米修斯使用的模組為: https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-module-prometheus.html
官方映像檔: https://hub.docker.com/r/elastic/metricbeat
下載映像檔

docker pull docker.elastic.co/beats/metricbeat:8.5.3

新建一個Metricbeat的Pod​

設定metrucbeat的deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: metricbeat
  namespace: default
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      workload.user.cattle.io/workloadselector: apps.deployment-srs3-metricbeat
  template:
    spec:
      affinity: {}
      containers:
      - image: dev-registry.xycloud.org/ldr/streaming/metricbeat
        imagePullPolicy: Always
        name: metricbeat
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /usr/share/metricbeat/metricbeat.yml
          name: vol0
          subPath: metricbeat.yml
        - mountPath: /usr/share/metricbeat/prometheus.yml
          name: vol0
          subPath: prometheus.yml
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: regsecret
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - configMap:
          defaultMode: 420
          name: filebeat-config
        name: vol0

設定兩個config​

metricbeat.yml​

metricbeat.config.modules:​
  path: ${path.config}/modules.d/*.yml​
  reload.enabled: false​
metricbeat.max_start_delay: 10s​
output.logstash:​
  enabled: true​
  hosts: ["logstash-logstash.tool-elk.svc.cluster.local:5043"]​
  index: 'metricbeat'​
  logging.level: info​
logging.metrics.enabled: false​
logging.metrics.period: 30s​

prometheus.yml​

- module: prometheus​
  metricsets: ["query"]​
  hosts: ["http://rancher-monitoring-prometheus.cattle-monitoring-system.svc.cluster.local:9090"]​
  period: 10s​
  queries:​
  - name: "stream_total_clients_by_pod"​
    path: "/api/v1/query"​
    params:​
      query: "stream_total_clients_by_pod"​

把這兩個config mount進pod的在/usr/share/metricbeat​

Posted on 1 Comment

Prometheus Rule for Alert​

Prometheus Rule功能介紹

Prometheus Rule 是用於在 Prometheus 中定義規則的 YAML 配置文件。它可以根據指定的表達式或條件對 metrics 進行匹配和計算,並在達到一定條件時生成警報或創建新的 metrics。

Prometheus Rule 的主要功能如下:

  • Metrics 計算:通過表達式對符合條件的 metrics 進行匹配和計算,生成新的 metrics。
  • 警報:當符合指定條件的 metrics 達到一定閾值時,生成警報。
  • 規則繫結:可以為指定的 metrics 繫結指定的規則,進行自動化的警報觸發。
  • 標註註釋:在生成警報時可以加上自定義的標註和註釋,方便後續的統計和分析。

通常在配合 Grafana 等圖形化界面使用時,Prometheus Rule 可以讓用戶方便的自定義需要監控的 metrics,並在 Grafana 上實現對這些 metrics 的實時監控和報警,以實現系統的實時監控和異常處理。

設定Prometheus Rule

這是一個 PrometheusRule YAML 配置文件,用於定義 Prometheus 規則,以檢測和警報指定的 metrics。

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    name: srs-online-member
  name: srs-online-member
  namespace: stu-srs
spec:
  groups:
  - name: srs-online-member
    rules:
    - expr: sum(stream_clients_clients{container="json-exporter", name=~".+",namespace=~"stu-srs",pod=~"srs-edge.+"})
        by (pod)
      labels:
        name: online-member-high
        namespace: stu-srs
        service: eventqueue
      record: stream_total_clients_by_pod
  - name: quay-alert.rules
    rules:
    - alert: online-member-full
      annotations:
        message: online-member-full {{ $labels.pod }} at {{ $value }}%
      expr: sum(stream_clients_clients{container="json-exporter", name=~".+",namespace=~"stu-srs",pod=~"srs-edge.+"})
        by (pod) > 1000
      for: 5m
      labels:
        severity: warning

該文件定義了兩個規則組,每個規則組包含一個或多個規則。

第一個規則組名為 srs-online-member,包含一個規則。該規則通過表達式 sum(stream_clients_clients{container="json-exporter", name=~".+",namespace=~"stu-srs",pod=~"srs-edge.+"}) by (pod) 求和符合條件的 metrics,這些 metrics 包含在 stream_clients_clients 中,該 metrics 必須滿足以下條件:在命名空間 stu-srs 中,容器名稱為 json-exporter,Pod 名稱符合正則表達式 srs-edge.+。

如果條件滿足,Prometheus 將會創建一個名為 stream_total_clients_by_pod 的時間序列,其中 pod 是標籤,值是符合條件的 Pod 名稱,這樣可以讓你在 Grafana 等圖形化界面上顯示時間序列並進行分析。

第二個規則組名為 quay-alert.rules,包含一個警報規則。該規則通過表達式 sum(stream_clients_clients{container="json-exporter", name=~".+",namespace=~"stu-srs",pod=~"srs-edge.+"}) by (pod) > 1000 檢查符合條件的 metrics 是否大於 1000。如果條件滿足 5 分鐘以上,Prometheus 將會發出名為 online-member-full 的警報,並設置一些額外的標籤和注釋以便進一步分析。

設定alert規則

我們也可以在Rule裡面設定Alert的規則,當有labels的Severity為warning時,就代表這個rule為一個告警,下面是代表當pod的人數大於1000多過五分鐘時,會觸發告警

  - name: quay-alert.rules
    rules:
    - alert: online-member-full
      annotations:
        message: online-member-full {{ $labels.pod }} at {{ $value }}%
      expr: sum(stream_clients_clients{container="json-exporter", name=~".+",namespace=~"default",pod=~"my-pod.+"})
        by (pod) > 1000
      for: 5m
      labels:
        severity: warning

可以在Prometheus Web UI的Alert頁籤裡找到這個設定值​