שלום לכולם! לפני מספר חודשים השקנו לייצור את פרויקט הקוד הפתוח החדש שלנו - תוסף Grafana לניטור kubernetes, שקראנו לו. . קוד המקור של הפלאגין זמין בכתובת . ובמאמר זה אנחנו רוצים לשתף אתכם בסיפור איך יצרנו את התוסף, באילו כלים השתמשנו ובאילו מלכודות נתקלנו בתהליך הפיתוח. בוא נלך!
חלק 0 - מבוא: איך הגענו למצב הזה?
הרעיון לכתוב תוסף משלנו לגרפן הגיע אלינו ממש במקרה. חברתנו עוקבת כבר יותר מ-10 שנים אחר פרויקטים אינטרנטיים ברמות מורכבות שונות. במהלך תקופה זו, צברנו כמות גדולה של מומחיות, מקרים מעניינים וניסיון בשימוש במערכות ניטור שונות. ובשלב מסוים שאלנו את עצמנו: "האם יש כלי קסם לניטור Kubernetes, כך, כמו שאומרים, "הגדר אותו ותשכח מזה"?".. התקן התעשייה לניטור K8s, כמובן, כבר מזמן שילוב פרומתאוס + גראפנה. וכפתרונות מוכנים לחסימה הזו, ישנו סט גדול של כלים מסוגים שונים: prometheus-operator, סט של לוחות מחוונים של kubernetes-mixin, grafana-kubernetes-app.
נראה שהתוסף grafana-kubernetes-app הוא האפשרות המעניינת ביותר עבורנו, אבל הוא לא נתמך כבר יותר משנה ויותר מכך, לא יכול לעבוד עם גרסאות חדשות של node-exporter ו-kube-state-metrics. ובשלב מסוים החלטנו: "האם לא נחליט בעצמנו?"
אילו רעיונות החלטנו ליישם בתוסף שלנו:
- הדמיה של "מפת האפליקציה": הצגה נוחה של אפליקציות באשכול, מקובצות לפי מרחבי שמות, פריסות...;
- הדמיה של חיבורים כמו "פריסה - שירות (+יציאות)".
- הדמיה של התפלגות יישומי אשכול על פני צמתי אשכול.
- אוסף של מדדים ומידע ממספר מקורות: Prometheus ושרת API K8s.
- ניטור הן של חלק התשתית (שימוש בזמן CPU, זיכרון, תת-מערכת דיסק, רשת) והן לוגיקה של האפליקציה - תרמילים של מצב בריאות, מספר העתקים זמינים, מידע על העברת מבחני חיוניות/מוכנות.
חלק 1: מהו "תוסף גרפאנה"?
מנקודת מבט טכנית, התוסף עבור Grafana הוא בקר זוויתי, המאוחסן בספריית הנתונים של Grafana (/var/grafana/plugins/ /dist/module.js) וניתן לטעון אותו כמודול SystemJS. כמו כן, בספרייה זו אמור להיות קובץ plugin.json המכיל את כל המטא מידע על התוסף שלך: שם, גרסה, סוג תוסף, קישורים למאגר/אתר/רישיון, תלות וכדומה.

module.ts

plugin.json
כפי שניתן לראות בצילום המסך, ציינו plugin.type = app. מכיוון שתוספי גראפאנה יכולים להיות משלושה סוגים:
לוח: הסוג הנפוץ ביותר של תוסף - זהו פאנל להמחשת כל מדדים, המשמש לבניית לוחות מחוונים שונים.
datasource: מחבר תוסף למקור נתונים כלשהו (לדוגמה, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
האפליקציה: תוסף המאפשר לך לבנות יישום חזיתי משלך בתוך Grafana, ליצור דפי HTML משלך ולגשת ידנית למקור הנתונים כדי להמחיש נתונים שונים. כמו כן, תוספים מסוגים אחרים (מקור נתונים, פאנל) ודשבורדים שונים יכולים לשמש כתלות.

תלות תוסף לדוגמה עם type=app.
אתה יכול להשתמש גם ב-JavaScript וגם ב-TypeScript כשפת תכנות (אנחנו בחרנו בה). הכנות לתוספי שלום עולם מכל סוג שאתה יכול : מאגר זה מכיל מספר רב של חבילות מתחילים (יש אפילו דוגמה ניסיונית של תוסף ב-React) עם בונים מותקנים ומוגדרים מראש.
חלק ב': הכנת הסביבה המקומית
כדי לעבוד על הפלאגין, אנו זקוקים באופן טבעי לאשכול kubernetes עם כל הכלים המותקנים מראש: prometheus, node-exporter, kube-state-metrics, grafana. יש להגדיר את הסביבה במהירות, בקלות ובטבעיות, וכדי להבטיח טעינה חמה, יש להרכיב את ספריית הנתונים של Grafana ישירות מהמחשב של המפתח.
הדרך הנוחה ביותר, לדעתנו, לעבוד מקומית עם kubernetes היא . השלב הבא הוא התקנת השילוב של Prometheus + Grafana באמצעות prometheus-operator. IN תהליך התקנת prometheus-operator על minikube מתואר בפירוט. כדי לאפשר התמדה, עליך להגדיר את הפרמטר התמדה: נכון בקובץ 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, המתארת את הבנאי, ההרס, שיטות לעדכון והחלפת נראות. כל אחת מהמחלקות מתארת קשרי גומלין מקוננים עם ישויות אחרות, לדוגמה, רשימה של תרמילים עבור פריסת ישות מסוג.
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 = [];
}
}בעזרת getters ו-seters, נוכל להציג או להגדיר את מדדי הישות הדרושים לנו בצורה נוחה וקריאה. לדוגמה, פלט מעוצב של צמתי מעבד הניתנים להקצאה:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}עמודים
רשימה של כל דפי הפלאגין שלנו מתוארת בתחילה ב-pluing.json שלנו בסעיף התלות:

בבלוק של כל עמוד עלינו לציין את ה-PAGE NAME (לאחר מכן הוא יומר ל-slug שבאמצעותו דף זה יהיה נגיש); שם הרכיב האחראי על פעולת דף זה (רשימת הרכיבים מיוצאת ל-modul.ts); ציון תפקיד המשתמש שעבורו זמינה עבודה עם דף זה והגדרות ניווט עבור סרגל הצד.
ברכיב האחראי על פעולת העמוד, עלינו להגדיר templateUrl, להעביר שם את הנתיב לקובץ ה-html עם סימון. בתוך הבקר, באמצעות הזרקת תלות, אנו יכולים לגשת לעד 2 שירותים זוויתיים חשובים:
- backendSrv - שירות המספק אינטראקציה עם שרת ה-API של Grafana;
- datasourceSrv - שירות המספק אינטראקציה מקומית עם כל מקורות הנתונים המותקנים ב-Grafana שלך (לדוגמה, שיטת .getAll() - מחזיר רשימה של כל מקורות הנתונים המותקנים; .get( ) - מחזירה אובייקט מופע של מקור נתונים ספציפי.



חלק 4: מקור נתונים
מנקודת המבט של Grafana, Datasource הוא בדיוק אותו תוסף כמו כל האחרים: יש לו נקודת כניסה משלו module.js, יש קובץ עם מטא מידע plugin.json. כאשר מפתחים תוסף עם type = app, אנו יכולים לקיים אינטראקציה הן עם מקורות הנתונים הקיימים (לדוגמה, prometheus-datasource) והן עם מקורות הנתונים שלנו, אותם נוכל לאחסן ישירות בספריית הפלאגין (dist/datasource/*) או להתקין כתלות. במקרה שלנו, מקור הנתונים מגיע עם קוד הפלאגין. כמו כן, יש צורך בתבנית config.html ובקר ConfigCtrl, שישמשו עבור דף התצורה של מופע מקורות הנתונים ובקר הנתונים של מקור הנתונים, אשר מיישם את ההיגיון של מקור הנתונים שלך.
בתוסף KubeGraf, מנקודת מבט של ממשק המשתמש, מקור הנתונים הוא מופע של אשכול kubernetes שמיישם את היכולות הבאות (קוד מקור זמין ):
- איסוף נתונים משרת ה- api k8s (קבלת רשימה של מרחבי שמות, פריסות...)
- העברת בקשות ל-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 כדי להגדיר גישה למקור הנתונים הסופי. באמצעות רכיב זה, נוכל להגדיר גישה למקור הנתונים http על ידי ציון כתובת האתר והגדרות האימות/הרשאה הבסיסיות: כניסה-סיסמה, או לקוח-אישור/מפתח לקוח. על מנת ליישם את היכולת להגדיר גישה באמצעות אסימון נושא (התקן דה פקטו ל-k8s), היינו צריכים לעשות קצת תיקון.
כדי לפתור בעיה זו, אתה יכול להשתמש במנגנון "מסלולי תוסף" המובנה של Grafana (פרטים נוספים ב- ). בהגדרות של מקור הנתונים שלנו, אנו יכולים להכריז על קבוצה של כללי ניתוב שיעובדו על ידי שרת ה-proxy grafana. לדוגמה, עבור כל נקודת קצה בודדת ניתן להגדיר כותרות או כתובות URL עם אפשרות של תבנית, שעבורן ניתן לקחת נתונים מהשדות jsonData ו-secureJsonData (לאחסון סיסמאות או אסימונים בצורה מוצפנת). בדוגמה שלנו, שאילתות כמו /__proxy/api/v1/namespaces ישלח פרוקסי לכתובת ה-URL של הטופס
/api/v8/namespaces עם הכותרת Authorization: Bearer.


באופן טבעי, כדי לעבוד עם שרת ה-API k8s אנחנו צריכים משתמש עם גישה לקריאה בלבד, מניפסטים ליצירה אותם תוכלו למצוא גם ב .
חלק 5: שחרור

לאחר שכתבת תוסף Grafana משלך, באופן טבעי תרצה להפוך אותו לזמין לציבור. בגראפאנה זוהי ספריית תוספים הזמינה כאן
כדי שהתוסף שלך יהיה זמין בחנות הרשמית, עליך לבצע יח"צ על ידי הוספת תוכן כזה לקובץ repo.json:

כאשר גרסה היא הגרסה של הפלאגין שלך, url הוא קישור למאגר, ו-commit הוא ה-hash של ה-commit שעבורו גרסה ספציפית של הפלאגין תהיה זמינה.
ובפלט תראה תמונה נפלאה כמו:

הנתונים עבורו ייתפסו אוטומטית מה-Readme.md, Changelog.md ומהקובץ plugin.json עם תיאור הפלאגין.
חלק 6: במקום מסקנות
לא הפסקנו לפתח את התוסף שלנו לאחר השחרור. ועכשיו אנחנו עובדים על ניטור נכון של השימוש במשאבים של צמתי אשכולות, מציגים תכונות חדשות לשיפור ה-UX, וגם לגרוף כמות גדולה של משוב שהתקבל לאחר התקנת התוסף הן על ידי הלקוחות שלנו והן מאנשים ב-GitHub (אם תעזבו בקשת הבעיה או המשיכה שלך, אני אשמח מאוד :)
אנו מקווים שמאמר זה יעזור לך להבין כלי נפלא כמו Grafana ואולי, לכתוב תוסף משלך.
תודה!)
מקור: www.habr.com
