سلام به همه! چند ماه پیش، ما پروژه منبع باز جدید خود را به مرحله تولید راه اندازی کردیم - پلاگین Grafana برای نظارت بر kubernetes، که نام آن را گذاشتیم.
قسمت 0 - مقدمه: چگونه به این نقطه رسیدیم؟
ایده نوشتن پلاگین خودمان برای Grafan کاملاً تصادفی به ذهنمان رسید. شرکت ما بیش از 10 سال است که پروژه های وب با سطوح مختلف پیچیدگی را رصد می کند. در این مدت، تخصص، موارد جالب و تجربه زیادی در استفاده از سیستم های نظارتی مختلف جمع آوری کرده ایم. و در نقطه ای از خود پرسیدیم: "آیا ابزار جادویی برای نظارت بر Kubernetes وجود دارد، به طوری که به قول آنها "آن را تنظیم کنید و آن را فراموش کنید"؟". البته استاندارد صنعت برای نظارت بر k8 ها مدت هاست که ترکیب پرومتئوس + گرافانا. و به عنوان راه حل های آماده برای این پشته، مجموعه بزرگی از انواع مختلف ابزار وجود دارد: prometheus-operator، مجموعه ای از داشبورد kubernetes-mixin، grafana-kubernetes-app.
افزونه grafana-kubernetes-app جالب ترین گزینه برای ما به نظر می رسید، اما بیش از یک سال است که پشتیبانی نمی شود و علاوه بر این، نمی تواند با نسخه های جدید node-exporter و kube-state-metrics کار کند. و در مقطعی تصمیم گرفتیم: "آیا نباید خودمان تصمیم بگیریم؟"
چه ایده هایی تصمیم گرفتیم در افزونه خود پیاده سازی کنیم:
- تجسم "نقشه برنامه": ارائه راحت برنامه ها در خوشه، گروه بندی شده بر اساس فضاهای نام، استقرار ....
- تجسم اتصالاتی مانند "استقرار - سرویس (+پورت ها)".
- تجسم توزیع برنامه های کاربردی خوشه در گره های خوشه.
- مجموعه ای از معیارها و اطلاعات از چندین منبع: سرور Api Prometheus و k8s.
- نظارت بر هر دو بخش زیرساخت (استفاده از زمان CPU، حافظه، زیرسیستم دیسک، شبکه) و منطق برنامه - غلاف وضعیت سلامت، تعداد نسخههای موجود، اطلاعات در مورد گذراندن تستهای زنده بودن/آمادگی.
بخش 1: "افزونه گرافانا" چیست؟
از نقطه نظر فنی، افزونه Grafana یک کنترلر زاویه ای است که در فهرست داده های Grafana ذخیره می شود (/var/grafana/plugins/ /dist/module.js) و می تواند به عنوان یک ماژول SystemJS بارگذاری شود. همچنین در این دایرکتوری باید یک فایل plugin.json حاوی تمام اطلاعات متا در مورد افزونه شما باشد: نام، نسخه، نوع افزونه، پیوندهای مخزن/سایت/مجوز، وابستگی ها و غیره.
module.ts
plugin.json
همانطور که در تصویر می بینید، ما plugin.type = app را مشخص کردیم. زیرا پلاگین های Grafana می توانند سه نوع باشند:
تابلو: رایج ترین نوع پلاگین - پانلی برای تجسم هر معیاری است که برای ساخت داشبوردهای مختلف استفاده می شود.
منبع اطلاعات: اتصال پلاگین به برخی از منابع داده (به عنوان مثال، منبع داده Prometheus، منبع داده ClickHouse، منبع داده ElasticSearch).
نرم افزار: افزونهای که به شما امکان میدهد اپلیکیشن frontend خود را در Grafana بسازید، صفحات html خود را ایجاد کنید و به صورت دستی به منبع داده دسترسی داشته باشید تا دادههای مختلف را تجسم کنید. همچنین از انواع دیگر پلاگین ها (داده منبع، پنل) و داشبوردهای مختلف می توان به عنوان وابستگی استفاده کرد.
نمونه وابستگی پلاگین با type=app.
شما می توانید از جاوا اسکریپت و تایپ اسکریپت به عنوان یک زبان برنامه نویسی استفاده کنید (ما آن را انتخاب کردیم). آماده سازی پلاگین های hello-world از هر نوع که می توانید
بخش 2: آماده سازی محیط محلی
برای کار بر روی افزونه، طبیعتاً به یک خوشه kubernetes با تمام ابزارهای از پیش نصب شده نیاز داریم: prometheus، node-exporter، kube-state-metrics، grafana. محیط باید سریع، آسان و طبیعی تنظیم شود و برای اطمینان از بارگذاری مجدد داغ، دایرکتوری داده 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 مشترک به ارث میبرند، که سازنده، مخرب، روشهای بهروزرسانی و تغییر قابلیت مشاهده را توصیف میکند. هر یک از کلاسها روابط تودرتو با موجودیتهای دیگر را توصیف میکنند، برای مثال، فهرستی از pods برای یک موجودیت از نوع استقرار.
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 = [];
}
}
با کمک گرفتنکنندهها و تنظیمکنندهها، میتوانیم معیارهای موجودیت مورد نیاز خود را به شکلی راحت و خوانا نمایش دهیم یا تنظیم کنیم. به عنوان مثال، خروجی فرمت شده گره های cpu قابل تخصیص:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}
صفحات
لیستی از تمام صفحات افزونه ما در ابتدا در pluing.json ما در بخش وابستگی ها توضیح داده شده است:
در بلوک هر صفحه باید نام PAGE را مشخص کنیم (سپس به یک اسلاگ تبدیل می شود که توسط آن این صفحه قابل دسترسی خواهد بود). نام مؤلفه مسئول عملکرد این صفحه (لیست مؤلفه ها به module.ts صادر می شود). نشان دهنده نقش کاربری که کار با این صفحه برای آن در دسترس است و تنظیمات پیمایش برای نوار کناری.
در مؤلفه ای که مسئولیت عملکرد صفحه را بر عهده دارد، باید templateUrl را تنظیم کنیم و مسیر فایل html را با نشانه گذاری به آنجا منتقل کنیم. در داخل کنترلر، از طریق تزریق وابستگی، می توانیم به 2 سرویس مهم زاویه ای دسترسی داشته باشیم:
- backendSrv - سرویسی که تعامل با سرور Grafana API را فراهم می کند.
- datasourceSrv - سرویسی که تعامل محلی را با تمام منابع داده نصب شده در Grafana شما فراهم می کند (به عنوان مثال، متد .getAll() - لیستی از همه منابع داده نصب شده را برمی گرداند؛ .get( ) - یک شی نمونه از یک منبع داده خاص را برمی گرداند.
بخش 4: منبع داده
از دیدگاه گرافانا، منبع داده دقیقاً همان افزونه های دیگر است: دارای module.js نقطه ورود خود است، یک فایل با اطلاعات متا plugin.json وجود دارد. هنگام توسعه یک افزونه با type = app، میتوانیم با هر دو منبع داده موجود (به عنوان مثال، منبع دادههای prometheus) و خودمان تعامل داشته باشیم، که میتوانیم مستقیماً در فهرست پلاگین (dist/datasource/*) ذخیره کنیم یا به عنوان یک وابستگی نصب کنیم. در مورد ما، منبع داده با کد افزونه همراه است. همچنین لازم است که یک قالب config.html و یک کنترلر ConfigCtrl داشته باشید که برای صفحه پیکربندی نمونه منبع داده و کنترلر Datasource که منطق منبع داده شما را پیاده سازی می کند، استفاده می شود.
در افزونه KubeGraf، از نقطه نظر رابط کاربری، منبع داده نمونه ای از خوشه kubernetes است که قابلیت های زیر را پیاده سازی می کند (کد منبع موجود است
- جمع آوری داده ها از سرور api k8s (دریافت لیستی از فضاهای نام، استقرار...)
- درخواستهای پروکسی به منبع داده پرومته (که در تنظیمات افزونه برای هر خوشه خاص انتخاب میشود) و قالببندی پاسخها برای استفاده از دادهها هم در صفحات استاتیک و هم در داشبورد.
- به روز رسانی داده ها در صفحات پلاگین ایستا (با نرخ تازه سازی تنظیم شده).
- پردازش پرس و جوها برای تولید یک برگه الگو در 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 برای پیکربندی دسترسی به منبع داده نهایی استفاده کنیم. با استفاده از این مؤلفه، میتوانیم دسترسی به منبع داده http را با تعیین url و تنظیمات اصلی تأیید اعتبار/مجوز: login-password یا client-cert/client-key پیکربندی کنیم. برای پیادهسازی قابلیت پیکربندی دسترسی با استفاده از توکن حامل (استاندارد واقعی برای k8s)، مجبور شدیم کمی تغییرات را انجام دهیم.
برای حل این مشکل، می توانید از مکانیزم داخلی Grafana "Plugin Routes" استفاده کنید (جزئیات بیشتر در
/api/v8/namespaces با هدر Authorization: Bearer.
به طور طبیعی، برای کار با سرور api k8s به یک کاربر با دسترسی فقط خواندنی نیاز داریم، مانیفست هایی برای ایجاد که می توانید آنها را نیز پیدا کنید.
قسمت 5: انتشار
هنگامی که پلاگین Grafana خود را نوشتید، طبیعتاً می خواهید آن را در دسترس عموم قرار دهید. در Grafana این یک کتابخانه از پلاگین های موجود در اینجا است
برای اینکه افزونه شما در فروشگاه رسمی در دسترس باشد، باید یک PR در آن ایجاد کنید
که در آن نسخه، نسخه افزونه شما است، url پیوندی به مخزن است، و commit هش commit است که نسخه خاصی از افزونه برای آن در دسترس خواهد بود.
و در خروجی تصویر فوق العاده ای مانند:
داده های مربوط به آن به طور خودکار از فایل Readme.md، Changelog.md و plugin.json همراه با توضیحات افزونه برداشته می شود.
قسمت ششم: به جای نتیجه گیری
ما توسعه افزونه خود را پس از انتشار متوقف نکردیم. و اکنون ما در حال کار بر روی نظارت صحیح بر استفاده از منابع گرههای خوشهای، معرفی ویژگیهای جدید برای بهبود UX، و همچنین جمعآوری تعداد زیادی بازخورد دریافتی پس از نصب افزونه، هم توسط مشتریانمان و هم از سوی افراد در GitHub هستیم (در صورت خروج مشکل یا درخواست شما، من بسیار خوشحال خواهم شد :)
امیدواریم این مقاله به شما کمک کند تا ابزار فوق العاده ای مانند Grafana را درک کنید و شاید افزونه خود را بنویسید.
ممنونم!)
منبع: www.habr.com