ããã«ã¡ã¯ãã¿ããªïŒæ°ãæåãç§ãã¡ã¯æ°ãããªãŒãã³ãœãŒã¹ãããžã§ã¯ããæ¬çªç°å¢ã§ãªãªãŒã¹ããŸãããKubernetesãç£èŠããããã®Grafanaãã©ã°ã€ã³ã§ãã ããã©ã°ã€ã³ã®ãœãŒã¹ã³ãŒãã¯ä»¥äžããå
¥æã§ããŸãã ããã®èšäºã§ã¯ããã©ã°ã€ã³ãã©ã®ããã«äœæããããã©ã®ãããªããŒã«ã䜿çšããããéçºããã»ã¹äžã«ã©ã®ãããªèœãšã穎ã«ééãããã«ã€ããŠã話ãããããšæããŸããããè¡ããïŒ
ããŒã 0 - ã¯ããã«: ã©ã®ããã«ããŠãããŸã§æ¥ãã®ã§ãããã?
Grafana çšã®ç¬èªã®ãã©ã°ã€ã³ãäœæãããšããã¢ã€ãã¢ã¯ããŸã£ããã®å¶ç¶ããçãŸããŸãããåœç€Ÿã¯ 10 幎以äžã«ããããããŸããŸãªè€éãã®ã¬ãã«ã® Web ãããžã§ã¯ããç£èŠããŠããŸããããã®éãåœç€Ÿã¯ããŸããŸãªç£èŠã·ã¹ãã ã®äœ¿çšã«é¢ããŠãèšå€§ãªå°éç¥èãè峿·±ãäºäŸãçµéšãèç©ããŠããŸããããããŠããæç¹ã§ãç§ãã¡ã¯èªåããŸããããKubernetes ãç£èŠããããã®éæ³ã®ããŒã«ã¯ããã®ã§ããããããããããèšå®ããŠå¿ãããããšãã§ããããŒã«ã¯ããã®ã ãããïŒããåœç¶ãªãããK8S ãç£èŠããããã®æ¥çæšæºã¯é·ãéãPrometheus + Grafana ãã³ãã«ã§ããããŸãããã®ã¹ã¿ãã¯ã®æ¢æãœãªã¥ãŒã·ã§ã³ãšããŠãprometheus-operatorãããã·ã¥ããŒãã®ã»ãã kubernetes-mixinãgrafana-kubernetes-app ãªã©ãããŸããŸãªçš®é¡ã®ããŒã«ã®å€§èŠæš¡ãªã»ããããããŸãã
ç§ãã¡ã«ãšã£ãŠæãè峿·±ããªãã·ã§ã³ã¯ grafana-kubernetes-app ãã©ã°ã€ã³ã§ããããã«æãããŸãããããã㯠1 幎以äžãµããŒããããŠããããããã«ãnode-exporter ããã³ kube-state-metrics ã®æ°ããããŒãžã§ã³ã§ã¯åäœããŸããããããŠããæç¹ã§ãç§ãã¡ã¯ãèªåãã¡ã§è§£æ±ºçãäœããããšæ±ºå¿ããŸããã
ãã©ã°ã€ã³ã«å®è£ ããããšã«ããã¢ã€ãã¢ã¯äœã§ãã?
- ãã¢ããªã±ãŒã·ã§ã³ ããããã®èŠèŠå: åå空éããããã€ã¡ã³ããªã©ã§ã°ã«ãŒãåããããã¯ã©ã¹ã¿ãŒå ã®ã¢ããªã±ãŒã·ã§ã³ã®äŸ¿å©ãªè¡šçŸã
- ããããã€ã¡ã³ã - ãµãŒãã¹ (+ ããŒã)ãã¿ã€ãã®æ¥ç¶ã®èŠèŠåã
- ã¯ã©ã¹ã¿ãŒ ããŒãå šäœã«ãããã¯ã©ã¹ã¿ãŒ ã¢ããªã±ãŒã·ã§ã³ã®åæ£ã®èŠèŠåã
- è€æ°ã®ãœãŒã¹ïŒPrometheus ããã³ k8s API ãµãŒããŒïŒããã¡ããªãã¯ãšæ å ±ãåéããŸãã
- ã€ã³ãã©ã¹ãã©ã¯ãã£éšå (ããã»ããµæéãã¡ã¢ãªããã£ã¹ã¯ ãµãã·ã¹ãã ããããã¯ãŒã¯ã®äœ¿çš) ãšã¢ããªã±ãŒã·ã§ã³ ããžã㯠(ãããã®ãã«ã¹ ã¹ããŒã¿ã¹ã䜿çšå¯èœãªã¬ããªã«ã®æ°ãçå/æºåãã¹ãã®ééã«é¢ããæ å ±) ã®äž¡æ¹ãç£èŠããŸãã
ããŒã 1: ãGrafana ãã©ã°ã€ã³ããšã¯äœã§ãã?
æè¡çã«ã¯ãGrafanaãã©ã°ã€ã³ã¯Grafanaã®ããŒã¿ãã£ã¬ã¯ããªïŒ/var/grafana/ãã©ã°ã€ã³/ /dist/module.js) ã§ãããSystemJS ã¢ãžã¥ãŒã«ãšããŠèªã¿èŸŒãããšãã§ããŸãããŸãããã®ãã£ã¬ã¯ããªã«ã¯ plugin.json ãã¡ã€ã«ãããããã®ãã¡ã€ã«ã«ã¯ããã©ã°ã€ã³ã«é¢ãããã¹ãŠã®ã¡ã¿æ å ± (ååãããŒãžã§ã³ããã©ã°ã€ã³ã®çš®é¡ããªããžããª/ãµã€ã/ã©ã€ã»ã³ã¹ãžã®ãªã³ã¯ãäŸåé¢ä¿ãªã©) ãå«ãŸããŠããŸãã

ã¢ãžã¥ãŒã«.ts

ãã©ã°ã€ã³.json
ã¹ã¯ãªãŒã³ã·ã§ãããããããããã«ãplugin.type = app ãæå®ããŸããã Grafana ã«ã¯ 3 çš®é¡ã®ãã©ã°ã€ã³ãããããã§ãã
ããã«: æãäžè¬çãªã¿ã€ãã®ãã©ã°ã€ã³ - ããŸããŸãªããã·ã¥ããŒããæ§ç¯ããããã«äœ¿çšããããããã€ãã®ã¡ããªãã¯ãèŠèŠåããããã®ããã«ã§ãã
æ
å ±æº: ããŒã¿ ãœãŒã¹ãžã®ãã©ã°ã€ã³ ã³ãã¯ã¿ (ããšãã°ãPrometheus ããŒã¿ ãœãŒã¹ãClickHouse ããŒã¿ ãœãŒã¹ãElasticSearch ããŒã¿ ãœãŒã¹)ã
ã¢ããª: Grafana å
ã§ç¬èªã®ããã³ããšã³ã ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããç¬èªã® HTML ããŒãžãäœæããããŒã¿ ãœãŒã¹ã«æåã§ã¢ã¯ã»ã¹ããŠããŸããŸãªããŒã¿ãèŠèŠåã§ãããã©ã°ã€ã³ããŸããä»ã®ã¿ã€ãã®ãã©ã°ã€ã³ (ããŒã¿ãœãŒã¹ãããã«) ãããŸããŸãªããã·ã¥ããŒããäŸåé¢ä¿ãšããŠäœ¿çšã§ããŸãã

type = app ã®ãã©ã°ã€ã³äŸåé¢ä¿ã®äŸ.
ããã°ã©ãã³ã°èšèªãšã㊠JavaScript ãŸã㯠TypeScript ã®ããããã䜿çšã§ããŸã (ããã§ã¯ TypeScript ãéžæããŸãã)ãããããã¿ã€ãã®Hello-Worldãã©ã°ã€ã³çšã®ç©ºçœ : ãã®ãªããžããªã«ã¯ãããªã€ã³ã¹ããŒã«ããæ§æããããã«ããŒãåãã倿°ã®ã¹ã¿ãŒã¿ãŒ ãã㯠(React äžã®ãã©ã°ã€ã³ã®å®éšçãªäŸãå«ãŸããŠããŸã) ãå«ãŸããŠããŸãã
ããŒã2: ããŒã«ã«ç°å¢ã®æºå
ãã©ã°ã€ã³ãæäœããã«ã¯ãåœç¶ã®ããšãªãããprometheusãnode-exporterãkube-state-metricsãgrafana ãªã©ã®ãã¹ãŠã®ããŒã«ãããªã€ã³ã¹ããŒã«ããã Kubernetes ã¯ã©ã¹ã¿ãŒãå¿ èŠã«ãªããŸããç°å¢ã¯è¿ éãã€ç°¡åã«ã»ããã¢ããã§ããããããªããŒãã確å®ã«å®è¡ã§ããããã«ãGrafana ããŒã¿ ãã£ã¬ã¯ããªãéçºè ã®ãã·ã³ããçŽæ¥ããŠã³ãããå¿ èŠããããŸãã
ç§ãã¡ã®æèŠã§ã¯ãKubernetesãããŒã«ã«ã§æäœããæã䟿å©ãªæ¹æ³ã¯ ãæ¬¡ã®ã¹ãããã¯ãprometheus-operator ã䜿çšã㊠Prometheus + Grafana ãã³ãã«ãã€ã³ã¹ããŒã«ããããšã§ããã§ minikube ã« prometheus-operator ãã€ã³ã¹ããŒã«ããããã»ã¹ã詳现ã«èª¬æãããŠããŸããæ°žç¶æ§ãæå¹ã«ããã«ã¯ããã©ã¡ãŒã¿ãèšå®ããå¿ èŠããããŸã æ°žç¶æ§: true 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ïŒçŽæ¥éçº
ãªããžã§ã¯ãã¢ãã«
ãã©ã°ã€ã³ã®å®è£ ã«åããŠãTypeScript ã¯ã©ã¹ãšããŠæäœãããã¹ãŠã®åºæ¬ç㪠Kubernetes ãšã³ãã£ã㣠(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 ã®äŸåé¢ä¿ã»ã¯ã·ã§ã³ã«èšè¿°ãããŸãã

åããŒãžã®ãããã¯ã§ã¯ãããŒãžåãæå®ããå¿
èŠããããŸã (ããã¯ããã®ããŒãžã«ã¢ã¯ã»ã¹ããããã®ã¹ã©ãã°ã«å€æãããŸã)ããã®ããŒãžã®æäœãæ
åœããã³ã³ããŒãã³ãã®åå (ã³ã³ããŒãã³ãã®ãªã¹ã㯠module.ts ã«ãšã¯ã¹ããŒããããŸã)ããã®ããŒãžã§äœæ¥ã§ãããŠãŒã¶ãŒ ããŒã«ãšãµã€ãããŒã®ããã²ãŒã·ã§ã³èšå®ãæå®ããŸãã
ããŒãžã®æäœãæ åœããã³ã³ããŒãã³ãã§ã¯ãtemplateUrl ãèšå®ããããŒã¯ã¢ãããå«ã HTML ãã¡ã€ã«ãžã®ãã¹ãæž¡ãå¿ èŠããããŸããã³ã³ãããŒã©ãŒå ã§ã¯ãäŸåæ§æ³šå ¥ãéããŠãæå€§ 2 ã€ã®éèŠãª Angular ãµãŒãã¹ã«ã¢ã¯ã»ã¹ã§ããŸãã
- backendSrv ã¯ãGrafana API ãµãŒããŒãšã®å¯Ÿè©±ãæäŸãããµãŒãã¹ã§ãã
- datasourceSrv â Grafanaã«ã€ã³ã¹ããŒã«ãããŠãããã¹ãŠã®ããŒã¿ãœãŒã¹ãšã®ããŒã«ã«ãªãããšããæäŸãããµãŒãã¹ïŒããšãã°ã.getAll()ã¡ãœããã¯ã€ã³ã¹ããŒã«ãããŠãããã¹ãŠã®ããŒã¿ãœãŒã¹ã®ãªã¹ããè¿ããŸãã.get( ) - ç¹å®ã®ããŒã¿ãœãŒã¹ã®ã€ã³ã¹ã¿ã³ã¹ ãªããžã§ã¯ããè¿ããŸãã



ããŒã4: ããŒã¿ãœãŒã¹
Grafana ã®èгç¹ããèŠããšãããŒã¿ãœãŒã¹ã¯ä»ã®ãã¹ãŠã®ãã©ã°ã€ã³ãšãŸã£ããåãã§ããç¬èªã®ãšã³ã㪠ãã€ã³ã module.js ããããã¡ã¿æ å ±ãå«ããã¡ã€ã« plugin.json ããããŸãã type = app ã§ãã©ã°ã€ã³ãéçºããå Žåãæ¢åã®ããŒã¿ãœãŒã¹ (ããšãã°ãprometheus-datasource) ãšç¬èªã®ããŒã¿ãœãŒã¹ã®äž¡æ¹ãšå¯Ÿè©±ã§ããŸãããããã®ããŒã¿ãœãŒã¹ã¯ããã©ã°ã€ã³ ãã£ã¬ã¯ã㪠(dist/datasource/*) ã«çŽæ¥ä¿åããããšããäŸåé¢ä¿ãšããŠã€ã³ã¹ããŒã«ããããšãã§ããŸããç§ãã¡ã®å ŽåãããŒã¿ ãœãŒã¹ã¯ãã©ã°ã€ã³ ã³ãŒããšãšãã«æäŸãããŸãããŸããããŒã¿ ãœãŒã¹ ã€ã³ã¹ã¿ã³ã¹æ§æããŒãžã«äœ¿çšããã config.html ãã³ãã¬ãŒããš ConfigCtrl ã³ã³ãããŒã©ãŒãããã³ããŒã¿ ãœãŒã¹ã®ããžãã¯ãå®è£ ãã Datasource ã³ã³ãããŒã©ãŒãå¿ èŠã§ãã
KubeGrafãã©ã°ã€ã³ã§ã¯ããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ã®èгç¹ãããããŒã¿ãœãŒã¹ã¯æ¬¡ã®æ©èœãå®è£ ããKubernetesã¯ã©ã¹ã¿ã®ã€ã³ã¹ã¿ã³ã¹ã§ãïŒãœãŒã¹ã³ãŒãã¯å ¥æå¯èœã§ãïŒã ):
- k8s api-server ããããŒã¿ãååŸãã (åå空éããããã€ã¡ã³ãã®ãªã¹ããååŸãããªã©)
- ãªã¯ãšã¹ãã 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) ã䜿çšããŠãæçµããŒã¿ ãœãŒã¹ãžã®ã¢ã¯ã»ã¹ãæ§æã§ããŸãããã®ã³ã³ããŒãã³ãã䜿çšãããšãURL ãšåºæ¬èªèšŒ/æ¿èªèšå® (login-passwordããŸã㯠client-cert/client-key) ãæå®ããŠãhttp ããŒã¿ ãœãŒã¹ãžã®ã¢ã¯ã»ã¹ãæ§æã§ããŸãããã¢ã©ãŒ ããŒã¯ã³ (k8s ã®äºå®äžã®æšæº) ã䜿çšããŠã¢ã¯ã»ã¹ãæ§æããæ©èœãå®è£ ããã«ã¯ãå°ã調æŽããå¿ èŠããããŸããã
ãã®åé¡ã解決ããã«ã¯ãGrafanaã«çµã¿èŸŒãŸããŠããããã©ã°ã€ã³ã«ãŒããã¡ã«ããºã ã䜿çšããããšãã§ããŸãïŒè©³çŽ°ã¯ ïŒãããŒã¿ ãœãŒã¹èšå®ã§ã¯ãGrafana ãããã· ãµãŒããŒã«ãã£ãŠåŠçãããã«ãŒãã£ã³ã° ã«ãŒã«ã®ã»ããã宣èšã§ããŸããããšãã°ãåã
ã®ãšã³ããã€ã³ãããšã«ããã³ãã¬ãŒãæ©èœã䜿çšããŠããããŒãŸã㯠URL ãèšå®ããæ©èœãããããã®ããŒã¿ã¯ jsonData ãã£ãŒã«ããš secureJsonData ãã£ãŒã«ã (ãã¹ã¯ãŒããŸãã¯ããŒã¯ã³ãæå·å圢åŒã§ä¿åãããã) ããååŸã§ããŸãããã®äŸã§ã¯ã次ã®ãããªã¯ãšãªã /__proxy/api/v1/åå空é 圢åŒã®URLã«ãããã·ãããŸã
Authorization: Bearer ããããŒãèšå®ããã /api/v8/namespacesã


åœç¶ãk8s apiãµãŒããŒãæäœããã«ã¯èªã¿åãå°çšã¢ã¯ã»ã¹ãæã€ãŠãŒã¶ãŒãå¿
èŠã§ããäœæããããã®ãããã§ã¹ãã¯æ¬¡ã®å Žæã«ãããŸãã .
ããŒã5ïŒãªãªãŒã¹

ç¬èªã® Grafana ãã©ã°ã€ã³ãäœæããããåœç¶ããããªãŒãã³ãœãŒã¹ã«ããããšæãã§ãããã Grafanaã§ã¯ãããã¯ãã©ã°ã€ã³ã®ã©ã€ãã©ãªã§ããããã®ãªã³ã¯ããå
¥æã§ããŸãã
ãã©ã°ã€ã³ãå ¬åŒã¹ãã¢ã§å ¬éããã«ã¯ãPRãäœæããå¿ èŠããããŸãã æ¬¡ã®ãããªå 容ã repo.json ãã¡ã€ã«ã«è¿œå ããŸãã

ããã§ãversion ã¯ãã©ã°ã€ã³ã®ããŒãžã§ã³ãurl ã¯ãªããžããªãžã®ãªã³ã¯ãcommit ã¯ãã©ã°ã€ã³ã®ç¹å®ã®ããŒãžã§ã³ãå©çšã§ããããã«ããã³ãããã®ããã·ã¥ã§ãã
ãããŠåºå£ã«ã¯æ¬¡ã®ãããªçŽ æŽãããçµµãèŠããŸãã

ããŒã¿ã¯ããã©ã°ã€ã³ã®èª¬æãå«ã Readme.mdãChangelog.mdãplugin.json ãã¡ã€ã«ããèªåçã«ååŸãããŸãã
第6éšïŒçµè«ã®ä»£ããã«
ãªãªãŒã¹åŸããã©ã°ã€ã³ã®éçºã¯äžæ¢ããŸããã§ããããããŠçŸåšãç§ãã¡ã¯ã¯ã©ã¹ã¿ãŒããŒãã®ãªãœãŒã¹äœ¿çšç¶æ³ãæ£ããç£èŠããUX ãæ¹åããããã®æ°æ©èœãå®è£ ãããã©ã°ã€ã³ã®ã€ã³ã¹ããŒã«åŸã«ã¯ã©ã€ã¢ã³ããš GitHub ã®ãªã¯ãšã¹ãã®äž¡æ¹ããåãåã£ã倧éã®ãã£ãŒãããã¯ãæŽçããããšã«åãçµãã§ããŸã (åé¡ããã«ãªã¯ãšã¹ããæ®ããŠããã ããã°ããšãŠãããããæããŸã ð )ã
ãã®èšäºããGrafana ã®ãããªçŽ æŽãããããŒã«ãçè§£ããç¬èªã®ãã©ã°ã€ã³ãäœæããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
ããããšãããããŸãïŒïŒ
åºæïŒ habr.com
