Ўсім прывітанне! Некалькі месяцаў таму мы запусцілі ў прадакшн наш новы open-source праект — Grafana-плагін для маніторынгу kubernetes, які назвалі
Частка 0 - уступная: як мы да гэтага дакаціліся?
Ідэя напісаць свой уласны плягін для Grafan'ы ў нас нарадзілася зусім выпадкова. Наша кампанія ўжо больш за 10 гадоў займаецца маніторынгам web-праектаў рознага ўзроўню складанасці. За гэты час мы напрацавалі вялікі багаж экспертызы, цікавых кейсаў, досведу выкарыстання розных сістэм маніторынгу. І ў нейкі момант мы задаліся пытаннем: «А ці існуе чароўная прылада для маніторынгу Kubernetes, каб, як той казаў, “паставіў і забыўся”»?.. Прамстандартам для маніторынгу k8s, натуральна, даўно з'яўляецца звязак Prometheus + Grafana. І ў якасці гатовых рашэнняў для дадзенага стэка існуе вялікі набор рознага роду прылад: prometheus-operator, набор дашбордаў kubernetes-mixin, grafana-kubernetes-app.
Найбольш цікавым варыянтам для нас здаўся плягін grafana-kubernetes-app, але ён не падтрымліваецца ўжо больш за год і, да таго ж, не ўмее працаваць з новымі версіямі node-exporter'а і kube-state-metrics'а. І ў нейкі момант мы вырашылі: "А ці не зрабіць нам сваё ўласнае рашэнне?"
Якія ідэі мы вырашылі рэалізаваць у сваёй убудове:
- візуалізацыя «карты дадатку»: зручнае прадстаўленне дадаткаў у кластары, згрупаваных па namespace'ах, deployment'ах…;
- візуалізацыя сувязяў выгляду "deployment - service (+ports)".
- візуалізацыя размеркавання прыкладанняў кластара па nod'ах кластара.
- збор метрык і інфармацыі з некалькіх крыніц: Prometheus і k8s api server.
- маніторынг як інфраструктурнай часткі (выкарыстанне працэсарнага часу, памяці, дыскавай падсістэмы, сеткі), так і логікі прыкладанняў - health-status pod'ов, колькасць даступных рэплік, інфармацыя аб праходжанні liveness / readyness-проб.
Частка 1: Што такое «плягін для Grafana»?
З тэхнічнага пункту гледжання, убудова для Grafana – гэта angular-кантролер, які захоўваецца ў data-дырэкторыі Grafan'ы (/var/grafana/plugins/ /dist/module.js) і можа быць загружаны як SystemJS-модуль. Таксама ў гэтай дырэкторыі павінен знаходзіцца файл plugin.json, які змяшчае ў сабе ўсю метаінфармацыю аб вашай убудове: назва, версія, тып убудовы, спасылкі на рэпазітар/сайт/ліцэнзію, залежнасці і гэтак далей.
module.ts
plugin.json
Як бачна на скрыншоце, мы паказалі plugin.type = app. Бо плагіны для Grafana могуць быць трох відаў:
панэль: самы распаўсюджаны тып плагінаў - уяўляе сабой панэль для візуалізацыі якіх-небудзь метрык, выкарыстоўваецца для пабудовы розных дашбордаў.
крыніца даных: убудова-канектар да якой-небудзь крыніцы дадзеных (напрыклад, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
прыкладанне: убудова, які дазваляе вам пабудаваць сваё ўласнае фронтэнд-дадатак ўнутры Grafana, ствараць свае ўласныя html-старонкі і ўручную звяртацца да datasource для візуалізацыі розных дадзеных. Таксама ў якасці залежнасцяў могуць выкарыстоўвацца плагіны іншых тыпаў (datasource, panel) і розныя дашборды.
Прыклад залежнасцяў плагіна з type = app.
У якасці мовы праграмавання можна выкарыстоўваць як JavaScript, так і TypeScript (мы свой выбар спынілі на ім). Нарыхтоўкі для hello-world плагінаў любога тыпу вы можаце
Частка 2: падрыхтоўка лакальнага асяроддзя
Для працы над убудовай нам, натуральна, спатрэбіцца kubernetes-кластар са ўсімі прадусталяванымі прыладамі: prometheus, node-exporter, kube-state-metrics, grafana. Асяроддзе павінна сетапиться хутка, лёгка і нязмушана, а для забеспячэння hot-reload data-дырэкторыя Grafana павінна манціравацца непасрэдна з машыны распрацоўніка.
Самым зручным, на наш погляд, спосабам лакальнай працы з kubernetes з'яўляецца
Выніковы скрыпт запуску 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'ов у сутнасці тыпу deployment.
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'аў мы можам выводзіць ці ўсталёўваць патрэбныя нам метрыкі сутнасцяў у зручным і чытэльным выглядзе. Напрыклад адфарматаваная выснова allocatable cpu nod'ы:
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-файла з разметкай. Унутры кантролера, праз dependency injection, мы можам атрымаць доступ да 2-х важных angular-сэрвісаў:
- backendSrv - сэрвіс, які забяспечвае ўзаемадзеянне з api-серверам графаны;
- datasourceSrv - сэрвіс, які забяспечвае лакальнае ўзаемадзеянне з усімі datasource, усталяванымі ў вашай Grafana (напрыклад, метад .getAll() - вяртае спіс усіх усталяваных datasource'аў; .get( ) - вяртае аб'ект-інстанс канкрэтнага datasource.
Частка 4: datasource
З пункту гледжання Grafana, datasource уяўляе сабою сапраўды такая ж убудова, як і ўсе астатнія: у яго ёсць свой пункт уваходу module.js, ёсць файл з метаінфармацыяй plugin.json. Пры распрацоўцы плагіна з type = app мы можам узаемадзейнічаць як з ужо існуючымі datasource'амі (напрыклад, prometheus-datasource), так і сваімі ўласнымі, якія мы можам захоўваць непасрэдна ў дырэкторыі плагіна (dist/datasource/*) або ўсталёўваць як залежнасць. У нашым выпадку datasource пастаўляецца разам з кодам плагіна. Таксама абавязкова наяўнасць шаблону config.html і кантролера ConfigCtrl, якія будуць выкарыстоўвацца для старонкі канфігуравання асобніка datasource'а і кантролера Datasource, у якім рэалізуецца логіка працы вашага datasource'а.
У плагіне KubeGraf, з пункта гледжання карыстацкага інтэрфейсу, datasource уяўляе сабой асобнік kubernetes-кластара, у якім рэалізаваны наступныя магчымасці (зыходны код даступны
- плот дадзеных з api-server'а k8s (атрыманне спісу namespace'ов, deployment'ов…)
- праксіраванне запытаў у prometheus-datasource (які выбіраецца ў наладах плагіна для кожнага канкрэтнага кластара) і фарматаванне адказаў для выкарыстання дадзеных як у статычных старонках, так і ў дашбордах.
- абнаўленне даных на статычных старонках плагіна (з устаноўленым часам refresh rate).
- апрацоўка запытаў для фармавання template-ліста ў 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"};
})
}
Асобным цікавым момантам, на наш погляд, з'яўляецца рэалізацыя механізму аўтэнтыфікацыі і аўтарызацыі для datasource. Як правіла, са скрынкі для канфігурацыі доступу да канчатковай крыніцы дадзеных мы можам выкарыстоўваць убудаваны кампанент Grafana - datasourceHttpSettings. З дапамогай гэтага кампанента мы можам наладзіць доступ да http-крыніцы дадзеных, паказаўшы url і базавыя налады аўтэнтыфікацыі/аўтарызацыі: лагін-пароль, або client-cert/client-key. Для таго каб рэалізаваць магчымасць налады доступу з дапамогай bearer-токена (дэфакта стандарт для k8s), прыйшлося крыху "пахімічыць".
Для рашэння гэтай задачы можна выкарыстоўваць убудаваны механізм Grafana "Plugin Routes" (падрабязней на
/api/v8/namespaces з прастаўленнем загалоўка Authorization: Bearer .
Натуральна, для працы з api-серверам k8s нам неабходны карыстач з readonly доступамі, маніфесты для стварэння якога вы можаце таксама знайсці ў
Частка 5: рэліз
Пасля таго, як вы напішаце свой уласны плягін для Grafana, вам, натуральна, захочацца выкласці яго ў адкрыты доступ. У Grafana гэта бібліятэка плагінаў, даступная па спасылцы
Для таго каб ваша плягін быў даступны ў афіцыйным старонцы, вам неабходна зрабіць PR у
дзе version - версія вашага плагіна, url - спасылка на рэпазітар, а commit - hash коміта, па якім будзе даступная канкрэтная версія плагіна.
І на выхадзе вы ўбачыце цудоўную карцінку віду:
Дадзеныя для яе будуць аўтаматычна зрабаваны з вашага Readme.md, Changelog.md і файла plugin.json з апісаннем плагіна.
Частка 6: замест высноў
Мы не спынілі распрацоўку нашага плагіна пасля рэлізу. І цяпер працуем над карэктным маніторынгам выкарыстання рэсурсаў нод кластара, укараненнем новых фіч для павышэння UX, а таксама разграбаем вялікую колькасць фідбэка, атрыманага пасля ўстановак плагіна як нашымі кліентамі, так і з ишшуев на гітхабе (калі вы пакінеце сваё issue або pull request, я буду вельмі шчаслівы 🙂 ).
Спадзяемся што дадзены артыкул дапаможа вам разабрацца ў такой выдатнай прыладзе як Grafana і, магчыма, напісаць сваю ўласную ўбудову.
Дзякуй!)
Крыніца: habr.com