Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Γεια σε όλους! Πριν από λίγους μήνες, ξεκινήσαμε το νέο μας έργο ανοιχτού κώδικα στην παραγωγή - το πρόσθετο Grafana για την παρακολούθηση kubernetes, το οποίο ονομάσαμε DevOpsProdigy KubeGraf. Ο πηγαίος κώδικας της προσθήκης είναι διαθέσιμος στη διεύθυνση δημόσιο αποθετήριο στο GitHub. Και σε αυτό το άρθρο θέλουμε να μοιραστούμε μαζί σας την ιστορία του πώς δημιουργήσαμε το πρόσθετο, ποια εργαλεία χρησιμοποιήσαμε και ποιες παγίδες συναντήσαμε κατά τη διαδικασία ανάπτυξης. Πάμε!

Μέρος 0 - εισαγωγικό: πώς φτάσαμε σε αυτό το σημείο;

Η ιδέα να γράψουμε το δικό μας πρόσθετο για το Grafan μας ήρθε εντελώς τυχαία. Η εταιρεία μας παρακολουθεί διαδικτυακά έργα διαφόρων επιπέδων πολυπλοκότητας για περισσότερα από 10 χρόνια. Κατά τη διάρκεια αυτής της περιόδου, έχουμε συγκεντρώσει μεγάλη τεχνογνωσία, ενδιαφέρουσες περιπτώσεις και εμπειρία στη χρήση διαφόρων συστημάτων παρακολούθησης. Και κάποια στιγμή αναρωτηθήκαμε: «Υπάρχει κάποιο μαγικό εργαλείο για την παρακολούθηση του Kubernetes, ώστε, όπως λένε, «ρυθμίστε το και ξεχάστε το»;». Το βιομηχανικό πρότυπο για την παρακολούθηση των k8s, φυσικά, ήταν από καιρό Συνδυασμός Προμηθέας + Γραφάνα. Και ως έτοιμες λύσεις για αυτήν τη στοίβα, υπάρχει ένα μεγάλο σετ διαφόρων ειδών εργαλείων: prometheus-operator, ένα σύνολο kubernetes-mixin ταμπλό, grafana-kubernetes-app.

Η προσθήκη grafana-kubernetes-app φαινόταν να είναι η πιο ενδιαφέρουσα επιλογή για εμάς, αλλά δεν υποστηρίζεται για περισσότερο από ένα χρόνο και, επιπλέον, δεν μπορεί να λειτουργήσει με νέες εκδόσεις node-exporter και kube-state-metrics. Και κάποια στιγμή αποφασίσαμε: «Δεν πρέπει να πάρουμε την απόφαση μας;»

Ποιες ιδέες αποφασίσαμε να εφαρμόσουμε στο πρόσθετό μας:

  • οπτικοποίηση του "χάρτου εφαρμογών": βολική παρουσίαση εφαρμογών στο σύμπλεγμα, ομαδοποιημένες κατά χώρους ονομάτων, αναπτύξεις...
  • οπτικοποίηση συνδέσεων όπως "ανάπτυξη - υπηρεσία (+ports)".
  • οπτικοποίηση της κατανομής των εφαρμογών συμπλέγματος μεταξύ των κόμβων συμπλέγματος.
  • συλλογή μετρήσεων και πληροφοριών από διάφορες πηγές: Prometheus και k8s api server.
  • παρακολούθηση τόσο του τμήματος της υποδομής (χρήση χρόνου CPU, μνήμη, υποσύστημα δίσκου, δίκτυο) όσο και της λογικής εφαρμογής - λοβοί κατάστασης υγείας, αριθμός διαθέσιμων αντιγράφων, πληροφορίες σχετικά με την επιτυχία δοκιμών ζωντανότητας/ ετοιμότητας.

Μέρος 1: Τι είναι το "πρόσθετο Grafana";

Από τεχνική άποψη, το πρόσθετο για το Grafana είναι ένας γωνιακός ελεγκτής, ο οποίος αποθηκεύεται στον κατάλογο δεδομένων Grafana (/var/grafana/plugins/ /dist/module.js) και μπορεί να φορτωθεί ως λειτουργική μονάδα SystemJS. Επίσης σε αυτόν τον κατάλογο θα πρέπει να υπάρχει ένα αρχείο plugin.json που να περιέχει όλες τις μετα-πληροφορίες σχετικά με την προσθήκη σας: όνομα, έκδοση, τύπος προσθήκης, συνδέσμους προς το αποθετήριο/ιστότοπο/άδεια χρήσης, εξαρτήσεις και ούτω καθεξής.

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων
module.ts

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων
plugin.json

Όπως μπορείτε να δείτε στο στιγμιότυπο οθόνης, καθορίσαμε plugin.type = app. Επειδή τα πρόσθετα για το Grafana μπορούν να είναι τριών τύπων:

πίνακας: ο πιο συνηθισμένος τύπος προσθήκης - είναι ένας πίνακας για την οπτικοποίηση οποιωνδήποτε μετρήσεων, που χρησιμοποιείται για τη δημιουργία διαφόρων πινάκων εργαλείων.
πηγή δεδομένων: σύνδεσμος προσθήκης σε κάποια πηγή δεδομένων (για παράδειγμα, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
app: Ένα πρόσθετο που σας επιτρέπει να δημιουργήσετε τη δική σας εφαρμογή frontend μέσα στο Grafana, να δημιουργήσετε τις δικές σας σελίδες html και να αποκτήσετε μη αυτόματη πρόσβαση στην πηγή δεδομένων για να οπτικοποιήσετε διάφορα δεδομένα. Επίσης, πρόσθετα άλλων τύπων (πηγή δεδομένων, πίνακας) και διάφοροι πίνακες εργαλείων μπορούν να χρησιμοποιηθούν ως εξαρτήσεις.

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων
Παραδείγματα εξαρτήσεων προσθηκών με type=app.

Μπορείτε να χρησιμοποιήσετε και JavaScript και TypeScript ως γλώσσα προγραμματισμού (εμείς το επιλέξαμε). Προετοιμασίες για πρόσθετα hello-world οποιουδήποτε τύπου μπορείτε βρείτε το σύνδεσμο: αυτό το αποθετήριο περιέχει μεγάλο αριθμό πακέτων εκκίνησης (υπάρχει ακόμη και ένα πειραματικό παράδειγμα πρόσθετου στο React) με προεγκατεστημένα και διαμορφωμένα builders.

Μέρος 2: προετοιμασία του τοπικού περιβάλλοντος

Για να εργαστούμε στο πρόσθετο, χρειαζόμαστε φυσικά ένα σύμπλεγμα kubernetes με όλα τα προεγκατεστημένα εργαλεία: prometheus, node-exporter, kube-state-metrics, grafana. Το περιβάλλον θα πρέπει να ρυθμιστεί γρήγορα, εύκολα και φυσικά, και για να διασφαλιστεί η επανάληψη φόρτωσης, ο κατάλογος δεδομένων Grafana θα πρέπει να τοποθετηθεί απευθείας από το μηχάνημα του προγραμματιστή.

Ο πιο βολικός τρόπος, κατά τη γνώμη μας, να εργαστείτε τοπικά με το kubernetes είναι minikube. Το επόμενο βήμα είναι να εγκαταστήσετε τον συνδυασμό Prometheus + Grafana χρησιμοποιώντας prometheus-operator. ΣΕ αυτό το άρθρο Η διαδικασία εγκατάστασης του 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 = [];
   }
}

Με τη βοήθεια ληπτών και ρυθμιστών, μπορούμε να εμφανίσουμε ή να ορίσουμε τις μετρήσεις οντοτήτων που χρειαζόμαστε σε μια βολική και ευανάγνωστη μορφή. Για παράδειγμα, μορφοποιημένη έξοδος με δυνατότητα κατανομής κόμβων CPU:

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

Σελίδες

Μια λίστα με όλες τις σελίδες προσθηκών περιγράφεται αρχικά στο pluing.json στην ενότητα εξαρτήσεων:

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Στο μπλοκ για κάθε σελίδα πρέπει να αναφέρουμε το ΟΝΟΜΑ ΣΕΛΙΔΑΣ (στη συνέχεια θα μετατραπεί σε γυμνοσάλιαγκα με την οποία θα είναι προσβάσιμη αυτή η σελίδα). το όνομα του στοιχείου που είναι υπεύθυνο για τη λειτουργία αυτής της σελίδας (η λίστα των στοιχείων εξάγεται στο module.ts). υποδεικνύοντας τον ρόλο χρήστη για τον οποίο είναι διαθέσιμη η εργασία με αυτήν τη σελίδα και τις ρυθμίσεις πλοήγησης για την πλαϊνή γραμμή.

Στο στοιχείο που είναι υπεύθυνο για τη λειτουργία της σελίδας, πρέπει να ορίσουμε templateUrl, περνώντας εκεί τη διαδρομή προς το αρχείο html με σήμανση. Μέσα στον ελεγκτή, μέσω της έγχυσης εξάρτησης, μπορούμε να έχουμε πρόσβαση σε έως και 2 σημαντικές γωνιακές υπηρεσίες:

  • backendSrv - μια υπηρεσία που παρέχει αλληλεπίδραση με τον διακομιστή API Grafana.
  • datasourceSrv - μια υπηρεσία που παρέχει τοπική αλληλεπίδραση με όλες τις πηγές δεδομένων που είναι εγκατεστημένες στο Grafana σας (για παράδειγμα, η μέθοδος .getAll() - επιστρέφει μια λίστα με όλες τις εγκατεστημένες πηγές δεδομένων· .get( ) - επιστρέφει ένα αντικείμενο παρουσίας μιας συγκεκριμένης προέλευσης δεδομένων.

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Μέρος 4: πηγή δεδομένων

Από την άποψη του Grafana, η πηγή δεδομένων είναι ακριβώς το ίδιο πρόσθετο με όλα τα άλλα: έχει το δικό του σημείο εισόδου module.js, υπάρχει ένα αρχείο με μετα-πληροφορίες plugin.json. Κατά την ανάπτυξη μιας προσθήκης με type = app, μπορούμε να αλληλεπιδράσουμε τόσο με υπάρχουσες πηγές δεδομένων (για παράδειγμα, prometheus-datasource) όσο και με τις δικές μας, τις οποίες μπορούμε να αποθηκεύσουμε απευθείας στον κατάλογο της προσθήκης (dist/datasource/*) ή να εγκαταστήσουμε ως εξάρτηση. Στην περίπτωσή μας, η πηγή δεδομένων συνοδεύεται από τον κωδικό προσθήκης. Είναι επίσης απαραίτητο να έχετε ένα πρότυπο config.html και έναν ελεγκτή ConfigCtrl, που θα χρησιμοποιηθούν για τη σελίδα διαμόρφωσης της παρουσίας πηγής δεδομένων και τον ελεγκτή Datasource, που υλοποιεί τη λογική της πηγής δεδομένων σας.

Στο πρόσθετο 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 για να διαμορφώσουμε την πρόσβαση στην τελική προέλευση δεδομένων. Χρησιμοποιώντας αυτό το στοιχείο, μπορούμε να διαμορφώσουμε την πρόσβαση στην πηγή δεδομένων http καθορίζοντας τη διεύθυνση url και τις βασικές ρυθμίσεις ελέγχου ταυτότητας/εξουσιοδότησης: κωδικός σύνδεσης ή κωδικός πρόσβασης πελάτη/κλειδί πελάτη. Για να εφαρμόσουμε τη δυνατότητα ρύθμισης της πρόσβασης χρησιμοποιώντας ένα διακριτικό φορέα (το de facto πρότυπο για τα k8s), έπρεπε να κάνουμε μια μικρή προσαρμογή.

Για να λύσετε αυτό το πρόβλημα, μπορείτε να χρησιμοποιήσετε τον ενσωματωμένο μηχανισμό Grafana “Plugin Routes” (περισσότερες λεπτομέρειες στο επίσημη σελίδα τεκμηρίωσης). Στις ρυθμίσεις της πηγής δεδομένων μας, μπορούμε να δηλώσουμε ένα σύνολο κανόνων δρομολόγησης που θα υποστούν επεξεργασία από τον διακομιστή μεσολάβησης grafana. Για παράδειγμα, για κάθε μεμονωμένο τελικό σημείο είναι δυνατό να οριστούν κεφαλίδες ή url με δυνατότητα προτύπου, τα δεδομένα για τα οποία μπορούν να ληφθούν από τα πεδία jsonData και safeJsonData (για αποθήκευση κωδικών πρόσβασης ή διακριτικών σε κρυπτογραφημένη μορφή). Στο παράδειγμά μας, ερωτήματα όπως /__proxy/api/v1/namespace θα μεταφερθεί με μεσολάβηση στη διεύθυνση url της φόρμας
/api/v8/namespace με την κεφαλίδα Εξουσιοδότηση: Bearer.

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Φυσικά, για να δουλέψουμε με τον διακομιστή api k8s χρειαζόμαστε έναν χρήστη με πρόσβαση μόνο για ανάγνωση, μανιφέστα για τη δημιουργία των οποίων μπορείτε επίσης να βρείτε στο πηγαίος κώδικας προσθήκης.

Μέρος 5: απελευθέρωση

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Αφού γράψετε το δικό σας πρόσθετο Grafana, φυσικά θα θέλετε να το κάνετε δημόσια διαθέσιμο. Στη Γραφάνα αυτή είναι μια βιβλιοθήκη προσθηκών διαθέσιμη εδώ grafana.com/grafana/plugins

Για να είναι διαθέσιμο το πρόσθετό σας στο επίσημο κατάστημα, πρέπει να κάνετε μια PR in αυτό το αποθετήριοπροσθέτοντας περιεχόμενο όπως αυτό στο αρχείο repo.json:

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

όπου η έκδοση είναι η έκδοση της προσθήκης σας, η διεύθυνση url είναι ένας σύνδεσμος προς το αποθετήριο και η δέσμευση είναι ο κατακερματισμός της δέσμευσης για την οποία θα είναι διαθέσιμη μια συγκεκριμένη έκδοση της προσθήκης.

Και στην έξοδο θα δείτε μια υπέροχη εικόνα όπως:

Ανάπτυξη ενός πρόσθετου για το Grafana: μια ιστορία μεγάλων λήψεων

Τα δεδομένα για αυτό θα συλληφθούν αυτόματα από το αρχείο Readme.md, Changelog.md και το plugin.json με την περιγραφή της προσθήκης.

Μέρος 6: αντί για συμπεράσματα

Δεν σταματήσαμε να αναπτύσσουμε την προσθήκη μας μετά την κυκλοφορία. Και τώρα εργαζόμαστε για τη σωστή παρακολούθηση της χρήσης των πόρων των κόμβων συμπλέγματος, εισάγοντας νέες δυνατότητες για τη βελτίωση του UX και επίσης συλλέγουμε μεγάλο αριθμό σχολίων που λαμβάνονται μετά την εγκατάσταση της προσθήκης τόσο από τους πελάτες μας όσο και από άτομα στο GitHub (αν αποχωρήσετε το πρόβλημά σας ή το αίτημά σας, θα είμαι πολύ χαρούμενος :)

Ελπίζουμε ότι αυτό το άρθρο θα σας βοηθήσει να κατανοήσετε ένα τόσο υπέροχο εργαλείο όπως το Grafana και, ίσως, να γράψετε το δικό σας πρόσθετο.

Ευχαριστώ!)

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο