Grafana 外掛程式的開發:大人物的歷史

大家好! 幾個月前,我們將新的開源專案投入生產——用於監控 kubernetes 的 Grafana 插件,我們稱之為 DevOpsProdigy KubeGraf。 插件原始碼位於 GitHub 上的公共儲存庫。 在這篇文章中,我們想與大家分享我們如何創建這個外掛程式、使用了哪些工具以及在開發過程中遇到了哪些陷阱。 我們走吧!

第 0 部分 - 介紹:我們是如何做到這一點的?

為 Grafan 編寫自己的插件的想法是很偶然的。 我們公司十多年來一直監控各種複雜程度的網路專案。 在這段時間裡,我們累積了大量的專業知識、有趣的案例以及使用各種監控系統的經驗。 在某些時候,我們問自己:「是否有一個神奇的工具來監控 Kubernetes,以便像他們所說的那樣,「設定好然後忘記它」?」..當然,監控 k10s 的行業標準長期以來一直是Prometheus + Grafana 組合。 作為此堆疊的現成解決方案,有大量各種工具:prometheus-operator、一組 kubernetes-mixin 儀表板、grafana-kubernetes-app。

grafana-kubernetes-app 插件似乎是我們最有趣的選擇,但它已經一年多沒有得到支持,而且無法與新版本的 node-exporter 和 kube-state-metrics 一起使用。 在某個時刻,我們決定:“我們不應該自己做決定嗎?”

我們決定在插件中實現哪些想法:

  • 「應用程式地圖」的視覺化:方便地呈現叢集中的應用程序,按名稱空間、部署進行分組…;
  • 連接的可視化,例如“部署 - 服務(+連接埠)”。
  • 叢集應用程式跨叢集節點的分佈的可視化。
  • 從多個來源收集指標和資訊:Prometheus 和 k8s api 伺服器。
  • 監控基礎設施部分(CPU 時間、記憶體、磁碟子系統、網路的使用)和應用程式邏輯 - 健康狀態 Pod、可用副本數量、有關通過活性/就緒性測試的資訊。

第 1 部分:什麼是「Grafana 插件」?

從技術角度來看,Grafana的插件是一個角度控制器,它儲存在Grafana資料目錄中(/var/grafana/插件/ /dist/module.js)並且可以作為 SystemJS 模組載入。 另外,在此目錄中應該有一個plugin.json 文件,其中包含有關插件的所有元資訊:名稱、版本、插件類型、儲存庫/網站/許可證的連結、依賴項等。

Grafana 外掛程式的開發:大人物的歷史
模組.ts

Grafana 外掛程式的開發:大人物的歷史
插件.json

正如您在螢幕截圖中看到的,我們指定了plugin.type = app。 因為 Grafana 的插件可以分為三種:

面板:最常見的插件類型 - 它是一個用於視覺化任何指標的面板,用於建立各種儀表板。
數據源:連接到某些資料來源的插件連接器(例如,Prometheus-datasource、ClickHouse-datasource、ElasticSearch-datasource)。
應用:一個插件,允許您在 Grafana 中建立自己的前端應用程序,創建自己的 html 頁面並手動存取資料來源以可視化各種資料。 此外,其他類型的插件(資料來源、面板)和各種儀表板也可以用作依賴項。

Grafana 外掛程式的開發:大人物的歷史
type=app 的範例插件依賴項.

您可以使用 JavaScript 和 TypeScript 作為程式語言(我們選擇了它)。 準備任何類型的 hello-world 插件 找到連結:這個儲存庫包含大量帶有預先安裝和配置建構器的入門包(甚至有一個 React 插件的實驗範例)。

第2部分:準備本地環境

要使用該插件,我們自然需要一個帶有所有預先安裝工具的 kubernetes 叢集:prometheus、node-exporter、kube-state-metrics、grafana。 環境應該快速、輕鬆、自然地設置,為了確保熱重載,Grafana 資料目錄應該直接從開發人員的機器上掛載。

我們認為,在本地使用 kubernetes 的最方便的方法是 迷你立方體。 下一步是使用 prometheus-operator 安裝 Prometheus + Grafana 組合。 在 本文 詳細介紹了minikube上安裝prometheus-operator的過程。 若要啟用持久性,必須設定參數 持久性:真實 在charts/grafana/values.yaml檔案中,新增自己的PV和PVC,並在persistence.existingClaim參數中指定它們

我們最終的 minikube 啟動腳本如下所示:

minikube start --kubernetes-version=v1.13.4 --memory=4096 --bootstrapper=kubeadm --extra-config=scheduler.address=0.0.0.0 --extra-config=controller-manager.address=0.0.0.0
minikube mount 
/home/sergeisporyshev/Projects/Grafana:/var/grafana --gid=472 --uid=472 --9p-version=9p2000.L

第三部分:實際開發

物件模型

為了準備實作這個插件,我們決定以 TypeScript 類別的形式描述我們將使用的所有基本 Kubernetes 實體:pod、deployment、daemonset、statefulset、job、cronjob、service、node、namespace。 這些類別中的每一個都繼承自公共 BaseModel 類,該類別描述了建構函數、析構函數、更新和切換可見性的方法。 每個類別都描述與其他實體的巢狀關係,例如部署類型實體的 Pod 清單。

import {Pod} from "./pod";
import {Service} from "./service";
import {BaseModel} from './traits/baseModel';

export class Deployment extends BaseModel{
   pods: Array<Pod>;
   services: Array<Service>;

   constructor(data: any){
       super(data);
       this.pods = [];
       this.services = [];
   }
}

在 getter 和 setter 的幫助下,我們可以以方便且可讀的形式顯示或設定我們需要的實體指標。 例如,可分配 cpu 節點的格式化輸出:

get cpuAllocatableFormatted(){
   let cpu = this.data.status.allocatable.cpu;
   if(cpu.indexOf('m') > -1){
       cpu = parseInt(cpu)/1000;
   }
   return cpu;
}

網頁

我們所有插件頁面的列表最初在依賴項部分的 pluing.json 中描述:

Grafana 外掛程式的開發:大人物的歷史

在每個頁面的區塊中,我們必須指示頁面名稱(然後它將轉換為可存取該頁面的slug); 負責本頁面操作的元件名稱(元件清單匯出到module.ts); 指示可使用此頁面的使用者角色以及側邊欄的導覽設定。

在負責頁面操作的元件中,我們必須設定 templateUrl,將帶有標記的 html 檔案的路徑傳遞到那裡。 在控制器內部,透過依賴注入,我們可以存取最多 2 個重要的 Angular 服務:

  • backendSrv - 提供與 Grafana API 伺服器互動的服務;
  • datasourceSrv - 提供與 Grafana 中安裝的所有資料來源的本地互動的服務(例如 .getAll() 方法 - 傳回所有已安裝資料來源的清單;.get( ) - 傳回特定資料來源的實例物件。

Grafana 外掛程式的開發:大人物的歷史

Grafana 外掛程式的開發:大人物的歷史

Grafana 外掛程式的開發:大人物的歷史

第四部分:資料來源

從 Grafana 的角度來看,資料來源與其他外掛程式完全相同:它有自己的入口點 module.js,有一個包含元資訊的檔案 plugin.json。 當使用type = app 開發插件時,我們可以與現有的資料來源(例如prometheus-datasource)和我們自己的資料來源進行交互,我們可以將其直接儲存在插件目錄(dist/datasource/*)中或作為依賴項安裝。 在我們的例子中,資料來源附帶插件程式碼。 還需要有一個 config.html 模板和一個 ConfigCtrl 控制器,它將用於資料來源實例配置頁面和資料來源控制器,它實現資料來源的邏輯。

在KubeGraf插件中,從使用者介面的角度來看,資料來源是一個kubernetes叢集的實例,它實現了以下功能(原始碼可取得) 鏈接):

  • 從 k8s api 伺服器收集資料(取得命名空間、部署的清單...)
  • 代理程式對 prometheus-datasource 的請求(在每個特定叢集的插件設定中選擇)並格式化回應以在靜態頁面和儀表板中使用資料。
  • 更新靜態外掛程式頁面上的資料(具有設定的更新率)。
  • 處理查詢以在 grafana-dashboards 中產生範本表(metriFindQuery() 方法)

Grafana 外掛程式的開發:大人物的歷史

Grafana 外掛程式的開發:大人物的歷史

Grafana 外掛程式的開發:大人物的歷史

  • 與最終 k8s 集群的連接測試。
testDatasource(){
   let url = '/api/v1/namespaces';
   let _url = this.url;
   if(this.accessViaToken)
       _url += '/__proxy';
   _url += url;
   return this.backendSrv.datasourceRequest({
       url: _url,
       method: "GET",
       headers: {"Content-Type": 'application/json'}
   })
       .then(response => {
           if (response.status === 200) {
               return {status: "success", message: "Data source is OK", title: "Success"};
           }else{
               return {status: "error", message: "Data source is not OK", title: "Error"};
           }
       }, error => {
           return {status: "error", message: "Data source is not OK", title: "Error"};
       })
}

我們認為,一個單獨的有趣點是資料來源的身份驗證和授權機制的實作。 通常,我們可以直接使用內建的 Grafana 元件 datasourceHttpSettings 來配置對最終資料來源的存取。 使用此元件,我們可以透過指定 url 和基本驗證/授權設定(登入密碼或用戶端憑證/用戶端金鑰)來設定對 http 資料來源的存取。 為了實現使用不記名令牌(k8s 的事實上的標準)配置存取的能力,我們必須做一些調整。

為了解決這個問題,您可以使用 Grafana 內建的「Plugin Routes」機制(更多詳細資訊請參見 官方文件頁面)。 在資料來源的設定中,我們可以聲明一組將由grafana代理伺服器處理的路由規則。 例如,對於每個單獨的端點,可以設定帶有範本可能性的標頭或 url,其資料可以從 jsonData 和 secureJsonData 欄位中取得(用於以加密形式儲存密碼或令牌)。 在我們的範例中,查詢如下 /__proxy/api/v1/命名空間 將被代理到表單的 url
/api/v8/namespaces 帶有 Authorization: Bearer 標頭。

Grafana 外掛程式的開發:大人物的歷史

Grafana 外掛程式的開發:大人物的歷史

當然,要使用 k8s api 伺服器,我們需要一個具有唯讀存取權限的用戶,您也可以在中找到用於建立的清單 插件原始碼.

第 5 部分:發布

Grafana 外掛程式的開發:大人物的歷史

一旦您編寫了自己的 Grafana 插件,您自然會希望將其公開。 在 Grafana 中,這是一個可用的插件庫 grafana.com/grafana/plugins

為了讓您的插件在官方商店上可用,您需要在 這個儲存庫將這樣的內容加入 repo.json 檔案:

Grafana 外掛程式的開發:大人物的歷史

其中 version 是插件的版本,url 是存儲庫的鏈接,commit 是可用的特定版本插件的提交的哈希值。

在輸出中你會看到一張精彩的圖片,如下圖:

Grafana 外掛程式的開發:大人物的歷史

它的資料將自動從您的 Readme.md、Changelog.md 和帶有插件描述的plugin.json 檔案中取得。

第六部分:代替結論

發布後我們並沒有停止開發插件。 現在,我們正在努力正確監控叢集節點資源的使用情況,引入新功能來改善使用者體驗,並收集我們的客戶和 GitHub 上的人員在安裝插件後收到的大量回饋(如果您離開)您的問題或拉取請求,我會很高興:)

我們希望這篇文章能幫助您了解 Grafana 如此出色的工具,或許還能幫助您撰寫自己的外掛程式。

謝謝!)

來源: www.habr.com

添加評論