สวัสดีทุกคน! ไม่กี่เดือนที่ผ่านมา เราได้เปิดตัวโปรเจกต์โอเพนซอร์สใหม่ของเรา ซึ่งเป็นปลั๊กอิน Grafana สำหรับการตรวจสอบ Kubernetes สู่การผลิตจริง ซอร์สโค้ดปลั๊กอินมีอยู่ใน ในบทความนี้ เราอยากแบ่งปันเรื่องราวเกี่ยวกับวิธีการสร้างปลั๊กอิน เครื่องมือที่เราใช้ และปัญหาที่เราพบเจอระหว่างการพัฒนา มาเริ่มกันเลย!
ตอนที่ 0 - บทนำ: เราเดินทางมาถึงจุดนี้ได้อย่างไร?
ไอเดียการเขียนปลั๊กอินสำหรับ Grafana ของเราเองเกิดขึ้นโดยบังเอิญ บริษัทของเราได้ติดตามโครงการเว็บที่มีความซับซ้อนหลากหลายมานานกว่า 10 ปี ในช่วงเวลานี้ เราได้สั่งสมความเชี่ยวชาญ กรณีศึกษาที่น่าสนใจ และประสบการณ์การใช้งานระบบติดตามที่หลากหลาย มีอยู่ช่วงหนึ่งที่เราสงสัยว่า "มีเครื่องมือวิเศษสำหรับติดตาม Kubernetes ที่คุณสามารถ 'ตั้งค่าแล้วลืมมันไปได้เลย' อย่างที่ใครๆ พูดกัน" แน่นอนว่าชุด Prometheus + Grafana เป็นมาตรฐานอุตสาหกรรมสำหรับการติดตาม K8S มาอย่างยาวนาน มีเครื่องมือสำเร็จรูปมากมายสำหรับสแต็กนี้ ซึ่งรวมถึง prometheus-operator, kubernetes-mixin dashboard suite และ grafana-kubernetes-app
ปลั๊กอิน grafana-kubernetes-app ดูเหมือนจะเป็นตัวเลือกที่น่าสนใจที่สุดสำหรับเรา แต่มันไม่ได้รับการสนับสนุนมานานกว่าหนึ่งปีแล้ว และยิ่งไปกว่านั้น มันยังไม่สามารถใช้งานได้กับ node-exporter และ kube-state-metrics เวอร์ชันใหม่ ๆ อีกด้วย ถึงจุดหนึ่ง เราจึงตัดสินใจว่า "ทำไมไม่สร้างโซลูชันของเราเองล่ะ?"
เราตัดสินใจนำไอเดียใดมาใช้ในปลั๊กอินของเรา?
- การแสดงภาพแผนที่แอปพลิเคชัน: การแสดงแอปพลิเคชันในคลัสเตอร์อย่างสะดวก โดยจัดกลุ่มตามเนมสเปซ การปรับใช้งาน ฯลฯ
- การแสดงภาพการเชื่อมต่อประเภท "การปรับใช้ - บริการ (+ พอร์ต)"
- การแสดงภาพการกระจายของแอปพลิเคชันคลัสเตอร์ในโหนดคลัสเตอร์
- การรวบรวมเมตริกและข้อมูลจากหลายแหล่ง: เซิร์ฟเวอร์ Prometheus และ K8S API
- การตรวจสอบทั้งโครงสร้างพื้นฐาน (การใช้เวลา CPU, หน่วยความจำ, ระบบย่อยของดิสก์, เครือข่าย) และตรรกะของแอปพลิเคชัน สถานะความสมบูรณ์ของพ็อด จำนวนแบบจำลองที่มีอยู่ และข้อมูลเกี่ยวกับความคืบหน้าของการทดสอบความพร้อมใช้งาน
ตอนที่ 1: ปลั๊กอิน Grafana คืออะไร?
จากมุมมองทางเทคนิค ปลั๊กอินสำหรับ Grafana เป็นตัวควบคุมเชิงมุมที่เก็บไว้ในไดเร็กทอรีข้อมูลของ Grafana (/var/grafana/plugins/ /dist/โมดูล.js) และสามารถโหลดเป็นโมดูล SystemJS ได้ ไดเรกทอรีนี้ควรมีไฟล์ plugin.json ด้วย ซึ่งประกอบด้วยข้อมูลเมตาทั้งหมดเกี่ยวกับปลั๊กอินของคุณ ได้แก่ ชื่อ เวอร์ชัน ประเภทปลั๊กอิน ลิงก์ที่เก็บ/เว็บไซต์/ใบอนุญาต การอ้างอิง และอื่นๆ

โมดูล.ts

Plugin.json
อย่างที่คุณเห็นในภาพหน้าจอ เราได้ระบุ plugin.type = app ไว้แล้ว เนื่องจากปลั๊กอินสำหรับ Grafana มีสามประเภท:
แผง:ปลั๊กอินประเภทที่พบมากที่สุด - เป็นแผงสำหรับแสดงข้อมูลเมตริกบางอย่าง และใช้ในการสร้างแดชบอร์ดต่างๆ
แหล่งข้อมูล:ตัวเชื่อมต่อปลั๊กอินไปยังแหล่งข้อมูลใดๆ (เช่น Prometheus-datasource, ClickHouse-datasource, ElasticSearch-datasource)
app:ปลั๊กอินที่ช่วยให้คุณสร้างแอปพลิเคชันส่วนหน้าของคุณเองภายใน Grafana สร้างหน้า HTML ของคุณเอง และเข้าถึงแหล่งข้อมูลด้วยตนเองเพื่อแสดงข้อมูลต่างๆ ปลั๊กอินประเภทอื่นๆ (แหล่งข้อมูล, แผงควบคุม) และแดชบอร์ดต่างๆ สามารถใช้เป็น dependencies ได้เช่นกัน

ตัวอย่างการพึ่งพาปลั๊กอินที่มีประเภท = app.
คุณสามารถใช้ JavaScript หรือ TypeScript เป็นภาษาโปรแกรมได้ (เราเลือก TypeScript) คุณสามารถสร้างเทมเพลตสำหรับปลั๊กอิน hello-world ทุกประเภทได้ :ที่เก็บข้อมูลนี้ประกอบด้วยแพ็คเริ่มต้นจำนวนมาก (ยังมีตัวอย่างทดลองของปลั๊กอิน React ด้วย) โดยมีตัวสร้างที่ติดตั้งและกำหนดค่าไว้ล่วงหน้า
ส่วนที่ 2: การเตรียมสภาพแวดล้อมในท้องถิ่น
ในการใช้งานปลั๊กอิน เราจำเป็นต้องมีคลัสเตอร์ Kubernetes พร้อมเครื่องมือทั้งหมดที่ติดตั้งไว้ล่วงหน้า ได้แก่ Prometheus, Node-Exporter, Kube-State-Metrics และ Grafana สภาพแวดล้อมควรตั้งค่าได้อย่างรวดเร็ว ง่ายดาย และปราศจากความยุ่งยาก และเพื่อให้มั่นใจว่าสามารถโหลดซ้ำได้ทันที ไดเรกทอรีข้อมูล Grafana ควรถูกเมาท์โดยตรงจากเครื่องของนักพัฒนา
ในความคิดของเรา วิธีที่สะดวกที่สุดในการทำงานในเครื่องด้วย Kubernetes คือ ขั้นตอนถัดไปคือการติดตั้งชุด 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 ทั่วไป ซึ่งกำหนด constructor, destructor และเมธอดสำหรับการอัปเดตและสลับการมองเห็น นอกจากนี้ แต่ละคลาสยังกำหนดความสัมพันธ์แบบซ้อนกับเอนทิตีอื่นๆ เช่น รายการ pod สำหรับเอนทิตีการปรับใช้
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 ในส่วนการอ้างอิง:

ในบล็อกสำหรับแต่ละหน้า เราต้องระบุชื่อหน้า (ซึ่งจะถูกแปลงเป็นสลักที่สามารถเข้าถึงหน้านี้ได้) ชื่อของส่วนประกอบที่รับผิดชอบในการทำงานของหน้านี้ (รายการส่วนประกอบจะถูกส่งออกไปยัง module.ts) ข้อบ่งชี้บทบาทของผู้ใช้ที่สามารถทำงานกับหน้านี้ได้ และการตั้งค่าการนำทางสำหรับแถบด้านข้าง
ในคอมโพเนนต์ที่รับผิดชอบการทำงานของเพจ เราต้องตั้งค่า templateUrl โดยส่งพาธไปยังไฟล์ HTML ที่มีมาร์กอัป ภายในตัวควบคุม เราสามารถเข้าถึงบริการ Angular ที่สำคัญสองบริการได้ผ่านการฉีดการอ้างอิง:
- backendSrv เป็นบริการที่ให้การโต้ตอบกับเซิร์ฟเวอร์ Grafana API
- datasourceSrv เป็นบริการที่ให้การโต้ตอบภายในเครื่องกับแหล่งข้อมูลทั้งหมดที่ติดตั้งใน Grafana ของคุณ (ตัวอย่างเช่น วิธี .getAll() จะส่งคืนรายการแหล่งข้อมูลที่ติดตั้งทั้งหมด; .get( ) — ส่งคืนวัตถุอินสแตนซ์ของแหล่งข้อมูลที่ระบุ



ส่วนที่ 4: แหล่งข้อมูล
จากมุมมองของ Grafana แหล่งข้อมูลก็คือปลั๊กอินเช่นเดียวกับปลั๊กอินอื่นๆ ทั่วไป คือมีจุดเข้าใช้งานของตัวเองคือ module.js และไฟล์ plugin.json ที่มีเมตาดาต้า เมื่อพัฒนาปลั๊กอินที่มีประเภท = app เราสามารถโต้ตอบกับแหล่งข้อมูลที่มีอยู่ (เช่น prometheus-datasource) หรือแหล่งข้อมูลของเราเอง ซึ่งเราสามารถจัดเก็บโดยตรงในไดเรกทอรีปลั๊กอิน (dist/datasource/*) หรือติดตั้งเป็น dependency ก็ได้ ในกรณีของเรา แหล่งข้อมูลจะรวมอยู่กับโค้ดปลั๊กอิน นอกจากนี้ สิ่งที่จำเป็นต้องมีคือเทมเพลต config.html และตัวควบคุม ConfigCtrl ซึ่งจะใช้สำหรับหน้าการกำหนดค่าอินสแตนซ์ของแหล่งข้อมูล และตัวควบคุมแหล่งข้อมูล ซึ่งจะนำตรรกะไปใช้กับแหล่งข้อมูลของคุณ
ในปลั๊กอิน KubeGraf จากมุมมองของอินเทอร์เฟซผู้ใช้ แหล่งข้อมูลคืออินสแตนซ์ของคลัสเตอร์ Kubernetes ที่ใช้ความสามารถต่อไปนี้ (มีโค้ดต้นฉบับ) ):
- การดึงข้อมูลจากเซิร์ฟเวอร์ api ของ k8s (รับรายชื่อเนมสเปซ การปรับใช้ ฯลฯ)
- การร้องขอพร็อกซีไปยัง 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"};
})
}ในความเห็นของเรา สิ่งที่น่าสนใจเป็นพิเศษอย่างหนึ่งคือการใช้งานกลไกการตรวจสอบสิทธิ์และการอนุญาตสำหรับแหล่งข้อมูล โดยทั่วไปแล้ว เราสามารถใช้ส่วนประกอบ datasourceHttpSettings ในตัวของ Grafana เพื่อกำหนดค่าการเข้าถึงแหล่งข้อมูลขั้นสุดท้ายได้ทันที ด้วยส่วนประกอบนี้ เราสามารถกำหนดค่าการเข้าถึงแหล่งข้อมูล HTTP ได้โดยการระบุ URL และการตั้งค่าการตรวจสอบสิทธิ์/การอนุญาตพื้นฐาน ได้แก่ ล็อกอิน/รหัสผ่าน หรือ client-cert/client-key การใช้งานความสามารถในการกำหนดค่าการเข้าถึงโดยใช้โทเค็นผู้ถือ (มาตรฐานโดยพฤตินัยสำหรับ k8s) จำเป็นต้องมีการปรับแต่งเล็กน้อย
เพื่อแก้ไขปัญหานี้ คุณสามารถใช้กลไก "Plugin Routes" ในตัวของ Grafana ได้ (รายละเอียดเพิ่มเติมเกี่ยวกับ ) ในการตั้งค่าแหล่งข้อมูลของเรา เราสามารถประกาศชุดกฎการกำหนดเส้นทางที่จะถูกประมวลผลโดยเซิร์ฟเวอร์พร็อกซี grafana ตัวอย่างเช่น สำหรับแต่ละจุดสิ้นสุด จะมีตัวเลือกในการตั้งค่าส่วนหัวหรือ URL พร้อมการรองรับเทมเพลต ซึ่งข้อมูลสามารถนำมาจากฟิลด์ jsonData และ secureJsonData (สำหรับการจัดเก็บรหัสผ่านหรือโทเค็นในรูปแบบที่เข้ารหัส) ในตัวอย่างของเรา คำขอของแบบฟอร์ม /__proxy/api/v1/เนมสเปซ จะถูกพร็อกซีไปยัง URL ประเภทต่อไปนี้
/api/v1/namespaces ที่มีการอนุญาต: ชุดส่วนหัวของ Bearer


โดยธรรมชาติแล้ว ในการทำงานกับเซิร์ฟเวอร์ API ของ K8S เราจำเป็นต้องมีผู้ใช้ที่มีสิทธิ์เข้าถึงแบบอ่านอย่างเดียว ซึ่งคุณสามารถดูรายการสำหรับการสร้างได้ใน .
ส่วนที่ 5: การปล่อยตัว

เมื่อคุณเขียนปลั๊กอิน Grafana ของตัวเองแล้ว คุณคงอยากจะทำให้มันเป็นโอเพนซอร์สอยู่แล้ว ใน Grafana นี่คือไลบรารีปลั๊กอิน พร้อมใช้งานที่
เพื่อให้ปลั๊กอินของคุณพร้อมใช้งานในร้านค้าอย่างเป็นทางการ คุณต้องสร้าง PR ใน เพิ่มเนื้อหาเช่นนี้ลงในไฟล์ repo.json:

โดยที่ version คือเวอร์ชันของปลั๊กอินของคุณ url คือลิงก์ไปยังที่เก็บข้อมูล และ commit คือแฮชของการ commit ที่จะทำให้เวอร์ชันเฉพาะของปลั๊กอินพร้อมใช้งาน
และเมื่อแสดงผลออกมาจะเห็นภาพที่สวยงามดังนี้:

ข้อมูลจะถูกดึงโดยอัตโนมัติจากไฟล์ Readme.md, Changelog.md และไฟล์ plugin.json พร้อมคำอธิบายปลั๊กอิน
ตอนที่ 6: แทนข้อสรุป
เรายังคงพัฒนาปลั๊กอินของเราอย่างต่อเนื่องนับตั้งแต่เปิดตัว ขณะนี้เรากำลังดำเนินการตรวจสอบการใช้งานทรัพยากรโหนดคลัสเตอร์อย่างเหมาะสม การนำฟีเจอร์ใหม่ๆ มาใช้เพื่อปรับปรุงประสบการณ์ผู้ใช้ และพิจารณาความคิดเห็นจำนวนมากที่เราได้รับจากทั้งลูกค้าและผู้ใช้บน GitHub หลังจากติดตั้งปลั๊กอิน (หากคุณทิ้งปัญหาหรือคำขอ Pull Request ไว้ ผมจะยินดีเป็นอย่างยิ่ง :))
เราหวังว่าบทความนี้จะช่วยให้คุณเข้าใจเครื่องมืออันยอดเยี่ยมอย่าง Grafana และอาจช่วยให้คุณเขียนปลั๊กอินของคุณเองได้
ขอบคุณ!)
ที่มา: will.com
