大家好!幾個月前,我們將新的開源專案投入生產——一個用於監控 kubernetes 的 Grafana 插件,我們稱之為 。該插件的源代碼可以在 。在本文中,我們想與您分享我們如何創建插件、我們使用了哪些工具以及在開發過程中遇到了哪些陷阱的故事。我們走吧!
第 0 部分 - 簡介:我們是如何到達這裡的?
我們完全是偶然想到為 Grafana 編寫自己的插件的。我們公司已經監控不同複雜程度的網路專案超過 10 年。在此期間,我們累積了大量的專業知識、有趣的案例以及使用各種監控系統的經驗。在某個時候,我們問自己:「是否存在一種用於監控 Kubernetes 的神奇工具,就像他們所說的那樣,你可以『設定它然後忘記它』?」。監控 K8S 的業界標準自然是 Prometheus + Grafana 套件。並且作為這個堆疊的現成解決方案,有大量各種類型的工具:prometheus-operator,一組儀表板kubernetes-mixin,grafana-kubernetes-app。
對我們來說最有趣的選擇似乎是 grafana-kubernetes-app 插件,但它已經一年多沒有得到支援了,此外,它不能與新版本的 node-exporter 和 kube-state-metrics 一起使用。在某個時候,我們決定:“為什麼我們不自己找到解決方案?”
我們決定在插件中實現哪些想法:
- 「應用程式地圖」的視覺化:方便地表示叢集中的應用程序,按命名空間、部署等分組;
- 「部署 - 服務(+連接埠)」類型的連線的視覺化。
- 跨叢集節點的叢集應用程式分佈的可視化。
- 從多個來源收集指標和資訊:Prometheus 和 k8s api 伺服器。
- 監控基礎設施部分(處理器時間、記憶體、磁碟子系統、網路的使用)和應用程式邏輯-pod 的健康狀態、可用副本的數量、有關活躍度/就緒性測試通過的資訊。
第 1 部分:什麼是「Grafana 插件」?
從技術上講,Grafana 插件是一個角度控制器,儲存在 Grafana 的資料目錄中 (/var/grafana/插件/ /dist/module.js) 並且可以作為 SystemJS 模組載入。此目錄中還應該有一個檔案 plugin.json,其中包含有關插件的所有元資訊:名稱、版本、插件類型、儲存庫/網站/許可證的連結、依賴項等。

模組.ts

插件.json
正如您在螢幕截圖中看到的,我們指定了 plugin.type = app。因為Grafana有三種類型的插件:
面板:最常見的插件類型 - 是一個用於視覺化某些指標的面板,用於建立各種儀表板。
資料來源:連接到某些資料來源的插件連接器(例如,Prometheus-datasource、ClickHouse-datasource、ElasticSearch-datasource)。
應用:一個插件,允許您在 Grafana 內部建立自己的前端應用程序,創建自己的 html 頁面並手動存取資料來源以可視化不同的資料。此外,其他類型的插件(資料來源、面板)和各種儀表板也可以作為依賴項。

類型 = app 的插件依賴項範例.
您可以使用 JavaScript 或 TypeScript 作為程式語言(我們選擇了 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第 3 部分:直接開發
物件模型
在準備插件實作時,我們決定將我們將使用的所有基本 Kubernetes 實體描述為 TypeScript 類別: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 中描述:

在每個頁面的區塊中,我們必須指明頁面名稱(然後它將轉換成可存取該頁面的 slug);負責此頁面運行的元件名稱(元件清單匯出到module.ts);指定可以使用此頁面的使用者角色和側邊欄的導覽設定。
在負責頁面操作的元件中,我們必須設定templateUrl,並將帶有標記的html檔案的路徑傳遞給它。在控制器內部,透過依賴注入,我們可以存取最多 2 個重要的 Angular 服務:
- backendSrv是提供與grafana api伺服器互動的服務;
- datasourceSrv — 提供與 Grafana 中安裝的所有資料來源進行本機互動的服務(例如,.getAll() 方法傳回所有已安裝資料來源的清單;.get( ) - 傳回特定資料來源的實例物件。



第 4 部分:資料來源
從 Grafana 的角度來看,datasource 與所有其他插件完全相同:它有自己的入口點 module.js,有一個包含元資訊的檔案 plugin.json。當開發 type = app 的插件時,我們可以與現有資料來源(例如,prometheus-datasource)和我們自己的資料來源進行交互,我們可以將其直接儲存在插件目錄(dist/datasource/*)中或作為依賴項安裝。在我們的例子中,資料來源由插件程式碼提供。還需要有一個 config.html 模板和一個 ConfigCtrl 控制器,它將用於資料來源實例配置頁面和 Datasource 控制器,它實現資料來源的邏輯。
在 KubeGraf 外掛程式中,從使用者介面的角度來看,資料來源是實現以下功能的 Kubernetes 叢集實例(原始碼可用 ):
- 從 k8s api 伺服器取得資料(取得命名空間、部署清單…)
- 將請求代理程式到 prometheus-datasource(在每個特定叢集的插件設定中選擇)並格式化回應以便在靜態頁面和儀表板中使用資料。
- 更新插件靜態頁面的資料(以設定的刷新率時間)。
- 處理查詢以在 grafana-dashboards 中產生範本表(方法 .metriFindQuery())



- 測試與最終的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 機制「插件路由」(更多詳情請參閱 )。在我們的資料來源設定中,我們可以宣告一組將由 grafana 代理伺服器處理的路由規則。例如,對於每個單獨的端點,都有能力設定具有範本功能的標頭或 URL,其資料可以從 jsonData 和 secureJsonData 欄位中取得(用於以加密形式儲存密碼或令牌)。在我們的範例中,以下形式的查詢 /__proxy/api/v1/命名空間 將會被代理到以下形式的 URL
/api/v8/namespaces 並設定 Authorization: Bearer 標頭。


當然,為了使用 k8s api 伺服器,我們需要一個具有唯讀存取權限的用戶,您也可以在 .
第五部分:發布

一旦您編寫了自己的 Grafana 插件,您自然會希望將其開源。在 Grafana 中,這是一個插件庫,可在此連結獲取
為了讓您的外掛能夠在官方商店中銷售,您需要在 ,在 repo.json 文件中加入以下內容:

其中 version 是您的插件的版本,url 是存儲庫的鏈接,commit 是提交的哈希值,可使插件的特定版本可用。
在出口處你會看到這樣美妙的畫面:

它的資料將自動從您的 Readme.md、Changelog.md 和 plugin.json 檔案中獲取,其中包含插件描述。
第六部分:不要下結論
發布後我們並沒有停止開發我們的插件。現在我們正在努力正確監控叢集節點資源的使用情況,實現新功能以改善用戶體驗,並整理安裝插件後從客戶和 GitHub 上的請求收到的大量反饋(如果您留下您的問題或拉取請求,我會很高興 🙂 )。
我們希望本文能幫助您了解 Grafana 這樣出色的工具,甚至幫助您編寫自己的外掛程式。
謝謝你! )
來源: www.habr.com
