Salut tout le monde! Il y a quelques mois, nous avons lancé en production notre nouveau projet open source - le plugin Grafana pour surveiller Kubernetes, que nous avons appelé
Partie 0 - introduction : comment en sommes-nous arrivés là ?
L’idée d’écrire notre propre plugin pour Grafan nous est venue par hasard. Notre entreprise suit depuis plus de 10 ans des projets web de différents niveaux de complexité. Au cours de cette période, nous avons accumulé une grande expertise, des cas intéressants et une expérience dans l’utilisation de divers systèmes de surveillance. Et à un moment donné, nous nous sommes demandés : « Existe-t-il un outil magique pour surveiller Kubernetes, de sorte que, comme on dit, « configurez-le et oubliez-le » ? Combinaison Prométhée + Grafana. Et comme solutions prêtes à l'emploi pour cette pile, il existe un large éventail d'outils de différents types : prometheus-operator, un ensemble de tableaux de bord kubernetes-mixin, grafana-kubernetes-app.
Le plugin grafana-kubernetes-app nous a semblé être l'option la plus intéressante, mais il n'est plus supporté depuis plus d'un an et, de plus, ne peut pas fonctionner avec les nouvelles versions de node-exporter et kube-state-metrics. Et à un moment donné, nous avons décidé : « Ne devrions-nous pas prendre notre propre décision ?
Quelles idées nous avons décidé de mettre en œuvre dans notre plugin :
- visualisation de la « carte des applications » : présentation pratique des applications du cluster, regroupées par espaces de noms, déploiements... ;
- visualisation des connexions comme « déploiement - service (+ports) ».
- visualisation de la distribution des applications de cluster sur les nœuds du cluster.
- collecte de métriques et d'informations provenant de plusieurs sources : Prometheus et le serveur api k8s.
- surveillance à la fois de la partie infrastructure (utilisation du temps CPU, de la mémoire, du sous-système de disque, du réseau) et de la logique de l'application - pods d'état de santé, nombre de répliques disponibles, informations sur la réussite des tests d'activité/préparation.
Partie 1 : Qu'est-ce qu'un « plugin Grafana » ?
D'un point de vue technique, le plugin pour Grafana est un contrôleur angulaire, qui est stocké dans le répertoire de données Grafana (/var/grafana/plugins/ /dist/module.js) et peut être chargé en tant que module SystemJS. Ce répertoire devrait également contenir un fichier plugin.json contenant toutes les méta-informations sur votre plugin : nom, version, type de plugin, liens vers le référentiel/site/licence, dépendances, etc.
module.ts
plugin.json
Comme vous pouvez le voir sur la capture d'écran, nous avons spécifié plugin.type = app. Car les plugins pour Grafana peuvent être de trois types :
panneau: le type de plugin le plus courant - il s'agit d'un panneau permettant de visualiser toutes les métriques, utilisé pour créer divers tableaux de bord.
source de données: connecteur de plugin vers une source de données (par exemple, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
appli: Un plugin qui vous permet de créer votre propre application front-end dans Grafana, de créer vos propres pages html et d'accéder manuellement à la source de données pour visualiser diverses données. De plus, des plugins d'autres types (source de données, panneau) et divers tableaux de bord peuvent être utilisés comme dépendances.
Exemples de dépendances de plugin avec type=app.
Vous pouvez utiliser à la fois JavaScript et TypeScript comme langage de programmation (nous l'avons choisi). Préparations pour les plugins hello-world de tout type que vous pouvez
Partie 2 : préparer l’environnement local
Pour travailler sur le plugin, nous avons naturellement besoin d'un cluster kubernetes avec tous les outils préinstallés : prometheus, node-exporter, kube-state-metrics, grafana. L'environnement doit être configuré rapidement, facilement et naturellement, et pour garantir le rechargement à chaud, le répertoire de données Grafana doit être monté directement depuis la machine du développeur.
Le moyen le plus pratique, à notre avis, de travailler localement avec Kubernetes est
Notre script de lancement final du minikube ressemble à ceci :
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
Partie 3 : développement réel
Modèle objet
En préparation de l'implémentation du plugin, nous avons décidé de décrire toutes les entités de base Kubernetes avec lesquelles nous travaillerons sous forme de classes TypeScript : pod, déploiement, démonset, statefulset, travail, cronjob, service, nœud, espace de noms. Chacune de ces classes hérite de la classe commune BaseModel, qui décrit le constructeur, le destructeur, les méthodes de mise à jour et de changement de visibilité. Chacune des classes décrit des relations imbriquées avec d'autres entités, par exemple une liste de pods pour une entité de type déploiement.
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 = [];
}
}
Avec l'aide des getters et des setters, nous pouvons afficher ou définir les métriques d'entité dont nous avons besoin sous une forme pratique et lisible. Par exemple, sortie formatée des nœuds CPU allouables :
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}
Nos Pages
Une liste de toutes nos pages de plugins est initialement décrite dans notre pluing.json dans la section dépendances :
Dans le bloc de chaque page il faut indiquer le NOM DE LA PAGE (il sera ensuite converti en un slug par lequel cette page sera accessible) ; le nom du composant responsable du fonctionnement de cette page (la liste des composants est exportée vers module.ts) ; indiquant le rôle d'utilisateur pour lequel le travail avec cette page est disponible et les paramètres de navigation pour la barre latérale.
Dans le composant responsable du fonctionnement de la page, nous devons définir templateUrl, en y passant le chemin d'accès au fichier html avec balisage. À l'intérieur du contrôleur, grâce à l'injection de dépendances, nous pouvons accéder à jusqu'à 2 services angulaires importants :
- backendSrv - un service qui permet une interaction avec le serveur API Grafana ;
- datasourceSrv - un service qui fournit une interaction locale avec toutes les sources de données installées dans votre Grafana (par exemple, la méthode .getAll() - renvoie une liste de toutes les sources de données installées ; .get( ) - renvoie un objet instance d'une source de données spécifique.
Partie 4 : source de données
Du point de vue de Grafana, datasource est exactement le même plugin que tous les autres : il a son propre point d'entrée module.js, il y a un fichier avec des méta informations plugin.json. Lors du développement d'un plugin avec type = app, nous pouvons interagir à la fois avec les sources de données existantes (par exemple, prometheus-datasource) et les nôtres, que nous pouvons stocker directement dans le répertoire du plugin (dist/datasource/*) ou installer en tant que dépendance. Dans notre cas, la source de données est livrée avec le code du plugin. Il est également nécessaire d'avoir un modèle config.html et un contrôleur ConfigCtrl, qui seront utilisés pour la page de configuration de l'instance de source de données et le contrôleur Datasource, qui implémente la logique de votre source de données.
Dans le plugin KubeGraf, du point de vue de l'interface utilisateur, la source de données est une instance d'un cluster Kubernetes qui implémente les fonctionnalités suivantes (le code source est disponible
- collecte de données à partir du serveur API k8s (obtention d'une liste d'espaces de noms, de déploiements...)
- proxy des requêtes vers prometheus-datasource (qui est sélectionné dans les paramètres du plugin pour chaque cluster spécifique) et formatage des réponses pour utiliser les données à la fois dans les pages statiques et dans les tableaux de bord.
- mise à jour des données sur les pages de plugin statiques (avec un taux de rafraîchissement défini).
- traitement des requêtes pour générer une feuille de modèle dans grafana-dashboards (méthode metriFindQuery())
- test de connexion avec le cluster k8s final.
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"};
})
}
Un autre point intéressant, à notre avis, est la mise en œuvre d'un mécanisme d'authentification et d'autorisation pour la source de données. En règle générale, nous pouvons utiliser le composant Grafana intégré datasourceHttpSettings pour configurer l'accès à la source de données finale. À l'aide de ce composant, nous pouvons configurer l'accès à la source de données http en spécifiant l'URL et les paramètres d'authentification/autorisation de base : login-password ou client-cert/client-key. Afin d'implémenter la possibilité de configurer l'accès à l'aide d'un jeton de porteur (la norme de facto pour les k8), nous avons dû procéder à quelques ajustements.
Pour résoudre ce problème, vous pouvez utiliser le mécanisme intégré Grafana « Plugin Routes » (plus de détails sur
/api/v8/namespaces avec l'en-tête Authorization: Bearer.
Naturellement, pour travailler avec le serveur API k8s, nous avons besoin d'un utilisateur avec un accès en lecture seule, des manifestes de création que vous pouvez également trouver dans
Partie 5 : sortie
Une fois que vous aurez écrit votre propre plugin Grafana, vous souhaiterez naturellement le rendre public. Dans Grafana, c'est une bibliothèque de plugins disponible ici
Pour que votre plugin soit disponible sur la boutique officielle, vous devez faire un PR en
où version est la version de votre plugin, url est un lien vers le référentiel et commit est le hachage du commit pour lequel une version spécifique du plugin sera disponible.
Et à la sortie, vous verrez une magnifique image comme :
Les données correspondantes seront automatiquement extraites de votre fichier Readme.md, Changelog.md et du fichier plugin.json avec la description du plugin.
Partie 6 : au lieu de conclusions
Nous n'avons pas arrêté de développer notre plugin après sa sortie. Et maintenant, nous travaillons à surveiller correctement l'utilisation des ressources des nœuds de cluster, à introduire de nouvelles fonctionnalités pour améliorer l'UX, et également à récolter une grande quantité de commentaires reçus après l'installation du plugin à la fois par nos clients et par les personnes sur GitHub (si vous quittez votre problème ou pull request, je serai très heureux :)
Nous espérons que cet article vous aidera à comprendre un outil aussi merveilleux que Grafana et, peut-être, à écrire votre propre plugin.
Merci!)
Source: habr.com