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

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

Μέρος 0 - Εισαγωγή: Πώς φτάσαμε ως εδώ;

Η ιδέα να γράψουμε το δικό μας πρόσθετο για το Grafana μας ήρθε εντελώς τυχαία. Η εταιρεία μας παρακολουθεί διαδικτυακά έργα ποικίλης πολυπλοκότητας για πάνω από 10 χρόνια. Κατά τη διάρκεια αυτής της περιόδου, έχουμε συσσωρεύσει πλούτο εμπειρογνωμοσύνης, ενδιαφέρουσες περιπτώσεις και εμπειρία χρησιμοποιώντας διάφορα συστήματα παρακολούθησης. Και κάποια στιγμή, αναρωτηθήκαμε: "Υπάρχει κάποιο μαγικό εργαλείο για την παρακολούθηση του Kubernetes που μπορείτε, όπως λένε, να "ρυθμίσετε και να ξεχάσετε";" Φυσικά, το πακέτο Prometheus + Grafana αποτελεί εδώ και καιρό το βιομηχανικό πρότυπο για την παρακολούθηση του K8S. Και ως έτοιμες λύσεις για αυτήν τη στοίβα, υπάρχει ένα μεγάλο σύνολο από διάφορα εργαλεία: prometheus-operator, ένα σύνολο dashboards kubernetes-mixin, grafana-kubernetes-app.

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

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

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

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

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

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

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

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

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

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

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

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

Για να εργαστούμε με το πρόσθετο, θα χρειαστούμε φυσικά ένα cluster 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, η οποία περιγράφει τον κατασκευαστή, τον καταστροφέα, τις μεθόδους ενημέρωσης και εναλλαγής ορατότητας. Κάθε μία από τις κλάσεις περιγράφει ένθετες σχέσεις με άλλες οντότητες, για παράδειγμα, μια λίστα pods για μια οντότητα του τύπου 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 = [];
   }
}

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

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

Σελίδες

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

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

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

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

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

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

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

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

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

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

Στο πρόσθετο KubeGraf, από την οπτική γωνία του περιβάλλοντος εργασίας χρήστη, μια πηγή δεδομένων είναι μια παρουσία ενός συμπλέγματος kubernetes που υλοποιεί τις ακόλουθες δυνατότητες (διαθέσιμος πηγαίος κώδικας по ссылке):

  • ανάκτηση δεδομένων από τον k8s api-server (λήψη λίστας ονομάτων, αναπτύξεων...)
  • αιτήματα proxy στο 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 και τις βασικές ρυθμίσεις ελέγχου ταυτότητας/εξουσιοδότησης: login-password ή client-cert/client-key. Για να εφαρμόσουμε τη δυνατότητα διαμόρφωσης πρόσβασης χρησιμοποιώντας ένα διακριτικό φορέα (το de facto πρότυπο για το k8s), έπρεπε να "κλέψουμε" λίγο.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Σας ευχαριστώ!)

Πηγή: www.habr.com

Αγοράστε αξιόπιστη φιλοξενία για ιστότοπους με προστασία DDoS, διακομιστές VPS VDS 🔥 Αγοράστε αξιόπιστη φιλοξενία ιστοσελίδων με προστασία DDoS, διακομιστές VPS VDS | ProHoster