Ola a todos! Hai uns meses lanzamos a produción o noso novo proxecto de código aberto, un plugin de Grafana para a monitorización de Kubernetes. O código fonte do complemento está dispoñible en Neste artigo, queremos compartir convosco a historia de como creamos o complemento, as ferramentas que empregamos e os erros que atopamos durante o desenvolvemento. Comecemos!
Parte 0 - Introdución: Como chegamos aquí?
A idea de escribir o noso propio plugin para Grafana xurdiunos por casualidade. A nosa empresa leva máis de 10 anos monitorizando proxectos web de diversa complexidade. Durante este tempo, acumulamos unha gran cantidade de coñecementos, estudos de casos interesantes e experiencia no uso de varios sistemas de monitorización. Nalgún momento, preguntámonos: "Existe unha ferramenta máxica para monitorizar Kubernetes que poidas, como din, 'configurala e esquecela'"? Naturalmente, a combinación Prometheus + Grafana leva moito tempo sendo o estándar da industria para a monitorización de K8S. Existe unha ampla gama de ferramentas predefinidas para esta pila, incluíndo prometheus-operator, o conxunto de paneis kubernetes-mixin e grafana-kubernetes-app.
O plugin grafana-kubernetes-app parecíanos a opción máis interesante, pero non ten soporte desde hai máis dun ano e, ademais, non funciona coas novas versións de node-exporter e kube-state-metrics. Nalgún momento, decidimos: "Por que non crear a nosa propia solución?".
Que ideas decidimos implementar no noso plugin?
- Visualización do mapa de aplicacións: unha representación práctica das aplicacións nun clúster, agrupadas por espazos de nomes, despregamentos, etc.;
- visualización de conexións do tipo "despregamento - servizo (+portos)".
- Visualización da distribución de aplicacións en clúster entre os nodos do clúster.
- Recompilación de métricas e información de múltiples fontes: Prometheus e o servidor API de k8s.
- Monitorización tanto da infraestrutura (uso do tempo de CPU, memoria, subsistema de disco, rede) como da lóxica da aplicación: o estado dos pods, o número de réplicas dispoñibles e información sobre o progreso das probas de activación/preparación.
Parte 1: Que é un plugin de Grafana?
Desde un punto de vista técnico, un plugin para Grafana é un controlador angular que se almacena no directorio de datos de Grafana (/var/grafana/plugins/ /dist/módulo.js) e pódese cargar como un módulo SystemJS. Este directorio tamén debería conter un ficheiro plugin.json, que contén todos os metadatos sobre o teu complemento: nome, versión, tipo de complemento, ligazóns de repositorio/sitio web/licenza, dependencias, etc.

módulo.ts

plugin.json
Como podes ver na captura de pantalla, especificamos plugin.type = app. Isto débese a que hai tres tipos de complementos para Grafana:
taboleiro: o tipo de plugin máis común: é un panel para visualizar certas métricas e úsase para crear varios cadros de mando.
fonte de datosun conector de complemento para calquera fonte de datos (por exemplo, Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource).
appUn complemento que che permite crear a túa propia aplicación frontend dentro de Grafana, crear as túas propias páxinas HTML e acceder manualmente á fonte de datos para visualizar varios datos. Outros tipos de complementos (fonte de datos, panel) e varios cadros de mando tamén se poden usar como dependencias.

Exemplo de dependencias de complementos con type = app.
Podes usar JavaScript ou TypeScript como linguaxe de programación (nós escollemos TypeScript). Podes crear modelos para calquera tipo de plugin de ola mundo. Este repositorio contén unha gran cantidade de paquetes de inicio (mesmo hai un exemplo experimental dun plugin de React) con construtores preinstalados e configurados.
Parte 2: Preparación do entorno local
Para traballar no complemento, naturalmente necesitaremos un clúster de Kubernetes con todas as ferramentas preinstaladas: prometheus, node-exporter, kube-state-metrics e grafana. O entorno debería ser rápido, sinxelo e sen complicacións de configurar e, para garantir a recarga en quente, o directorio de datos de Grafana debería montarse directamente desde a máquina do desenvolvedor.
Na nosa opinión, o xeito máis cómodo de traballar localmente con Kubernetes é O seguinte paso é instalar o paquete Prometheus + Grafana usando prometheus-operator. Descríbese en detalle o proceso de instalación de prometheus-operator en minikube. Para activar a persistencia, cómpre definir o parámetro persistencia: verdadeira No ficheiro charts/grafana/values.yaml, engade os teus propios valores PV e PVC e especifícaos no parámetro persistence.existingClaim.
O noso script final de lanzamento de minikube ten este aspecto:
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.LParte 3: Desenvolvemento directo
Modelo de obxectos
Como preparación para a implementación do complemento, decidimos definir todas as entidades básicas de Kubernetes coas que traballaremos como clases de TypeScript: pod, deployment, daemonset, statefulset, job, cronjob, service, node e namespace. Cada unha destas clases herda dunha clase BaseModel común, que define un construtor, un destrutor e métodos para actualizar e activar/desactivar a visibilidade. Cada clase tamén define relacións aniñadas con outras entidades, como unha lista de pods para unha entidade de despregamento.
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 = [];
}
}Usando getters e setters, podemos mostrar ou definir as métricas de entidade desexadas nun formato cómodo e lexible. Por exemplo, a saída formatada dos nodos de CPU asignables:
get cpuAllocatableFormatted(){
let cpu = this.data.status.allocatable.cpu;
if(cpu.indexOf('m') > -1){
cpu = parseInt(cpu)/1000;
}
return cpu;
}páxinas
A lista de todas as páxinas do noso complemento descríbese inicialmente no noso ficheiro pluing.json, na sección de dependencias:

No bloque de cada páxina, debemos especificar o NOME DA PÁXINA (isto converterase nun slug mediante o cal se poderá acceder a esta páxina); o nome do compoñente responsable do funcionamento desta páxina (a lista de compoñentes expórtase a module.ts); unha indicación do rol de usuario para o que está dispoñible o traballo con esta páxina e a configuración de navegación da barra lateral.
No compoñente responsable do funcionamento da páxina, debemos definir o templateUrl, pasándolle a ruta ao ficheiro HTML que contén o código. Dentro do controlador, mediante a inxección de dependencias, podemos acceder a dous servizos Angular importantes:
- backendSrv é un servizo que proporciona interacción co servidor da API de Grafana;
- datasourceSrv é un servizo que proporciona interacción local con todas as fontes de datos instaladas en Grafana (por exemplo, o método .getAll() devolve unha lista de todas as fontes de datos instaladas; .get( ) — devolve un obxecto de instancia dunha fonte de datos específica.



Parte 4: Fonte de datos
Desde a perspectiva de Grafana, unha fonte de datos é un complemento coma calquera outro: ten o seu propio punto de entrada, module.js, e un ficheiro plugin.json con metadatos. Ao desenvolver un complemento con type = app, podemos interactuar con fontes de datos existentes (por exemplo, prometheus-datasource) ou coas nosas propias, que podemos almacenar directamente no directorio do complemento (dist/datasource/*) ou instalar como unha dependencia. No noso caso, a fonte de datos inclúese co código do complemento. Tamén se require un modelo config.html e un controlador ConfigCtrl, que se usará para a páxina de configuración da instancia da fonte de datos e o controlador Datasource, que implementa a lóxica para a túa fonte de datos.
No complemento KubeGraf, desde a perspectiva da interface de usuario, unha fonte de datos é unha instancia dun clúster de Kubernetes que implementa as seguintes capacidades (código fonte dispoñible ):
- Obter datos do servidor da API de k8s (obter unha lista de espazos de nomes, despregamentos, etc.)
- Enviar solicitudes por proxy á fonte de datos prometheus (que está seleccionada na configuración do complemento para cada clúster específico) e formatar respostas para usar datos tanto en páxinas estáticas como en paneis.
- actualizando datos en páxinas estáticas do complemento (cunha taxa de actualización establecida).
- Procesando consultas para xerar unha folla de modelo en grafana-dashboards (método .metriFindQuery())



- proba de conexión co clúster 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 aspecto particularmente interesante, na nosa opinión, é a implementación do mecanismo de autenticación e autorización para a fonte de datos. Normalmente, de fábrica, podemos usar o compoñente datasourceHttpSettings integrado de Grafana para configurar o acceso á fonte de datos final. Con este compoñente, podemos configurar o acceso á fonte de datos HTTP especificando o URL e a configuración básica de autenticación/autorización: inicio de sesión/contrasinal ou certificado-de-cliente/clave-de-cliente. Implementar a capacidade de configurar o acceso usando un token de portador (o estándar de facto para k8s) requiriu algúns axustes.
Para solucionar este problema, podes usar o mecanismo "Rutas de complementos" integrado de Grafana (máis detalles en ). Na nosa configuración de fonte de datos, podemos declarar un conxunto de regras de enrutamento que serán procesadas polo servidor proxy de grafana. Por exemplo, para cada punto final individual, existe a opción de definir cabeceiras ou URL con soporte de modelos, cuxos datos poden obterse dos campos jsonData e secureJsonData (para almacenar contrasinais ou tokens en forma cifrada). No noso exemplo, as solicitudes do tipo /__proxy/api/v1/espazos de nomes será enviado por proxy a URL do seguinte tipo
/api/v1/namespaces coa cabeceira Authorization: Bearer definida.


Naturalmente, para traballar co servidor da API de k8s, precisamos un usuario con acceso de só lectura, cuxos manifestos para crear tamén podes atopar en .
Parte 5: Publicación

Unha vez que teñas escrito o teu propio plugin de Grafana, naturalmente quererás facelo de código aberto. En Grafana, esta é unha biblioteca de plugins, dispoñible en
Para que o teu plugin estea dispoñible na tenda oficial, debes facer unha PR en , engadindo contido coma este ao ficheiro repo.json:

onde version é a versión do teu plugin, url é a ligazón ao repositorio e commit é o hash do commit que fará que a versión específica do plugin estea dispoñible.
E na saída verás unha imaxe marabillosa coma esta:

Os datos extraeranse automaticamente dos teus ficheiros Readme.md, Changelog.md e plugin.json coa descrición do plugin.
Parte 6: En lugar de conclusións
Non paramos de desenvolver o noso plugin dende o seu lanzamento. Actualmente estamos a traballar na monitorización axeitada do uso dos recursos dos nodos do clúster, na implementación de novas funcionalidades para mellorar a experiencia do usuario e na revisión da gran cantidade de comentarios que recibimos tanto dos nosos clientes como dos usuarios de GitHub despois de instalar o plugin (se deixas unha incidencia ou unha solicitude de extracción, estarei moi contento :)).
Agardamos que este artigo che axude a comprender unha ferramenta tan marabillosa como Grafana e, quizais, a escribir o teu propio plugin.
Grazas!)
Fonte: www.habr.com
