การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

สวัสดีทุกคน! เมื่อไม่กี่เดือนที่ผ่านมา เราได้เปิดตัวโปรเจ็กต์โอเพ่นซอร์สใหม่สู่การใช้งานจริง - ปลั๊กอิน Grafana สำหรับการตรวจสอบ kubernetes ซึ่งเราเรียกว่า DevOpsProdigy Kubeกราฟ. ซอร์สโค้ดปลั๊กอินมีอยู่ที่ พื้นที่เก็บข้อมูลสาธารณะบน GitHub. และในบทความนี้ เราต้องการแบ่งปันเรื่องราวเกี่ยวกับวิธีการสร้างปลั๊กอิน เครื่องมือที่เราใช้ และข้อผิดพลาดที่เราพบในระหว่างกระบวนการพัฒนา ไปกันเถอะ!

ตอนที่ 0 - เกริ่นนำ: เรามาถึงจุดนี้ได้อย่างไร?

ความคิดในการเขียนปลั๊กอินของเราเองสำหรับ Grafan เกิดขึ้นกับเราโดยบังเอิญ บริษัทของเราได้ติดตามโครงการเว็บที่มีระดับความซับซ้อนต่างๆ มานานกว่า 10 ปี ในช่วงเวลานี้เราได้สั่งสมความเชี่ยวชาญ กรณีที่น่าสนใจ และประสบการณ์ในการใช้ระบบติดตามต่างๆ เป็นจำนวนมาก และเมื่อถึงจุดหนึ่ง เราก็ถามตัวเองว่า: “มีเครื่องมือวิเศษสำหรับการตรวจสอบ Kubernetes หรือไม่ ดังนั้นอย่างที่พวกเขาพูดว่า “ตั้งค่าและลืมมันไปซะ”?”.. แน่นอนว่ามาตรฐานอุตสาหกรรมสำหรับการตรวจสอบ k8 นั้นถือเป็นมาตรฐานมานานแล้ว โพรมีธีอุส + กราฟาน่ารวมกัน และเนื่องจากโซลูชันสำเร็จรูปสำหรับสแต็กนี้ มีชุดเครื่องมือหลากหลายประเภทจำนวนมาก: prometheus-operator, ชุดแดชบอร์ด kubernetes-mixin, grafana-kubernetes-app

ปลั๊กอิน grafana-kubernetes-app ดูเหมือนจะเป็นตัวเลือกที่น่าสนใจที่สุดสำหรับเรา แต่ไม่ได้รับการสนับสนุนมานานกว่าหนึ่งปี และยิ่งไปกว่านั้น ไม่สามารถทำงานร่วมกับ node-exporter และ kube-state-metrics เวอร์ชันใหม่ได้ และเมื่อถึงจุดหนึ่ง เราก็ตัดสินใจว่า “เราไม่ควรตัดสินใจเองหรือ?”

แนวคิดใดที่เราตัดสินใจนำไปใช้ในปลั๊กอินของเรา:

  • การแสดงภาพ "แผนผังแอปพลิเคชัน": การนำเสนอแอปพลิเคชันในคลัสเตอร์ที่สะดวก จัดกลุ่มตามเนมสเปซ การใช้งาน...;
  • การแสดงภาพการเชื่อมต่อ เช่น "การปรับใช้ - บริการ (+พอร์ต)"
  • การแสดงภาพการกระจายแอปพลิเคชันคลัสเตอร์ข้ามโหนดคลัสเตอร์
  • การรวบรวมตัวชี้วัดและข้อมูลจากหลายแหล่ง: เซิร์ฟเวอร์ Prometheus และ k8s api
  • การตรวจสอบทั้งส่วนของโครงสร้างพื้นฐาน (การใช้เวลา CPU หน่วยความจำ ระบบย่อยของดิสก์ เครือข่าย) และตรรกะของแอปพลิเคชัน - พ็อดสถานะสุขภาพ จำนวนเรพลิกาที่มีอยู่ ข้อมูลเกี่ยวกับการผ่านการทดสอบความสด/ความพร้อม

ส่วนที่ 1: “ปลั๊กอิน Grafana” คืออะไร

จากมุมมองทางเทคนิค ปลั๊กอินสำหรับ Grafana คือตัวควบคุมเชิงมุมซึ่งจัดเก็บไว้ในไดเร็กทอรีข้อมูล Grafana (/var/grafana/ปลั๊กอิน/ /dist/module.js) และสามารถโหลดเป็นโมดูล SystemJS ได้ นอกจากนี้ ในไดเร็กทอรีนี้ควรมีไฟล์ Plugin.json ที่มีข้อมูลเมตาทั้งหมดเกี่ยวกับปลั๊กอินของคุณ เช่น ชื่อ เวอร์ชัน ประเภทปลั๊กอิน ลิงก์ไปยังพื้นที่เก็บข้อมูล/ไซต์/ใบอนุญาต การขึ้นต่อกัน และอื่นๆ

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่
module.ts

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่
Plugin.json

ดังที่คุณเห็นในภาพหน้าจอ เราได้ระบุ Plugin.type = app แล้ว เนื่องจากปลั๊กอินสำหรับ Grafana มีสามประเภท:

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

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่
ตัวอย่างการพึ่งพาปลั๊กอินที่มี type=app.

คุณสามารถใช้ทั้ง JavaScript และ TypeScript เป็นภาษาการเขียนโปรแกรม (เราเลือกไว้) การเตรียมการสำหรับปลั๊กอิน Hello-World ทุกประเภทที่คุณสามารถทำได้ ค้นหาลิงก์: พื้นที่เก็บข้อมูลนี้มีแพ็กเริ่มต้นจำนวนมาก (มีแม้กระทั่งตัวอย่างทดลองของปลั๊กอินใน React) พร้อมตัวสร้างที่ติดตั้งและกำหนดค่าไว้ล่วงหน้า

ส่วนที่ 2: การเตรียมสภาพแวดล้อมในท้องถิ่น

ในการทำงานกับปลั๊กอิน โดยธรรมชาติแล้ว เราจำเป็นต้องมีคลัสเตอร์ kubernetes พร้อมด้วยเครื่องมือที่ติดตั้งไว้ล่วงหน้าทั้งหมด: prometheus, node-exporter, kube-state-metrics, grafana สภาพแวดล้อมควรได้รับการตั้งค่าอย่างรวดเร็ว ง่ายดาย และเป็นธรรมชาติ และเพื่อให้แน่ใจว่ามีการรีโหลดอย่างรวดเร็ว ควรติดตั้งไดเร็กทอรีข้อมูล Grafana โดยตรงจากเครื่องของนักพัฒนา

ในความเห็นของเรา วิธีที่สะดวกที่สุดในการทำงานกับ kubernetes ในเครื่องคือ มินิคุเบะ. ขั้นตอนต่อไปคือการติดตั้งชุด Prometheus + Grafana โดยใช้ตัวดำเนินการโพร ใน บทความนี้ กระบวนการติดตั้ง prometheus-operator บน minikube มีการอธิบายโดยละเอียด หากต้องการเปิดใช้งานการคงอยู่ คุณต้องตั้งค่าพารามิเตอร์ ความพากเพียร: จริง ในไฟล์charts/grafana/values.yaml ให้เพิ่ม PV และ PVC ของคุณเอง แล้วระบุในพารามิเตอร์ Peristence.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 ทั่วไป ซึ่งอธิบายตัวสร้าง ตัวทำลาย วิธีการอัปเดตและการสลับการมองเห็น แต่ละคลาสอธิบายความสัมพันธ์แบบซ้อนกับเอนทิตีอื่น เช่น รายการพ็อดสำหรับเอนทิตีประเภทการปรับใช้

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: ประวัติความเป็นมาของภาพใหญ่

ในบล็อกสำหรับแต่ละเพจ เราต้องระบุชื่อเพจ (จากนั้นจะถูกแปลงเป็นทากซึ่งเพจนี้จะสามารถเข้าถึงได้) ชื่อของส่วนประกอบที่รับผิดชอบในการดำเนินการของหน้านี้ (รายการส่วนประกอบจะถูกส่งออกไปยัง module.ts) ระบุบทบาทของผู้ใช้ที่ทำงานกับเพจนี้และการตั้งค่าการนำทางสำหรับแถบด้านข้าง

ในองค์ประกอบที่รับผิดชอบการทำงานของเพจเราต้องตั้งค่า templateUrl โดยส่งเส้นทางไปยังไฟล์ html พร้อมมาร์กอัปไปที่นั่น ภายในคอนโทรลเลอร์ เราสามารถเข้าถึงบริการเชิงมุมที่สำคัญได้มากถึง 2 บริการผ่านการฉีดการขึ้นต่อกัน:

  • backendSrv - บริการที่ให้การโต้ตอบกับเซิร์ฟเวอร์ Grafana API
  • datasourceSrv - บริการที่ให้การโต้ตอบภายในเครื่องกับแหล่งข้อมูลทั้งหมดที่ติดตั้งใน Grafana ของคุณ (เช่น เมธอด .getAll() - ส่งคืนรายการแหล่งข้อมูลที่ติดตั้งทั้งหมด .get( ) - ส่งคืนออบเจ็กต์อินสแตนซ์ของแหล่งข้อมูลเฉพาะ

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

ส่วนที่ 4: แหล่งข้อมูล

จากมุมมองของ Grafana แหล่งข้อมูลนั้นเป็นปลั๊กอินเดียวกันกับปลั๊กอินอื่นๆ ทั้งหมด: มีจุดเริ่มต้น module.js เป็นของตัวเอง มีไฟล์ที่มีข้อมูลเมตา Plugin.json เมื่อพัฒนาปลั๊กอินด้วย type = app เราสามารถโต้ตอบกับทั้งแหล่งข้อมูลที่มีอยู่ (เช่น แหล่งข้อมูล prometheus) และแหล่งข้อมูลของเราเอง ซึ่งเราสามารถจัดเก็บโดยตรงในไดเร็กทอรีปลั๊กอิน (dist/datasource/*) หรือติดตั้งเป็นการขึ้นต่อกัน ในกรณีของเรา แหล่งข้อมูลจะมาพร้อมกับโค้ดปลั๊กอิน นอกจากนี้ จำเป็นต้องมีเทมเพลต config.html และตัวควบคุม ConfigCtrl ซึ่งจะใช้สำหรับหน้าการกำหนดค่าอินสแตนซ์แหล่งข้อมูลและตัวควบคุมแหล่งข้อมูล ซึ่งใช้ตรรกะของแหล่งข้อมูลของคุณ

ในปลั๊กอิน KubeGraf จากมุมมองของอินเทอร์เฟซผู้ใช้ แหล่งข้อมูลคืออินสแตนซ์ของคลัสเตอร์ kubernetes ที่ใช้ความสามารถต่อไปนี้ (มีซอร์สโค้ดให้ใช้งาน) ลิงค์):

  • รวบรวมข้อมูลจากเซิร์ฟเวอร์ k8s api (รับรายการเนมสเปซ การปรับใช้...)
  • คำขอพร็อกซีไปยังแหล่งข้อมูล prometheus (ซึ่งถูกเลือกในการตั้งค่าปลั๊กอินสำหรับแต่ละคลัสเตอร์เฉพาะ) และการจัดรูปแบบการตอบสนองเพื่อใช้ข้อมูลทั้งในเพจแบบคงที่และในแดชบอร์ด
  • อัปเดตข้อมูลบนหน้าปลั๊กอินแบบคงที่ (พร้อมอัตราการรีเฟรชที่ตั้งไว้)
  • ประมวลผลแบบสอบถามเพื่อสร้างแผ่นเทมเพลตใน 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"};
       })
}

ในความเห็นของเรา จุดที่น่าสนใจอีกจุดหนึ่งคือการใช้กลไกการตรวจสอบสิทธิ์และการอนุญาตสำหรับแหล่งข้อมูล โดยทั่วไปแล้ว เราสามารถใช้ datasourceHttpSettings คอมโพเนนต์ Grafana ในตัวเพื่อกำหนดค่าการเข้าถึงแหล่งข้อมูลสุดท้ายได้นอกกรอบ เมื่อใช้ส่วนประกอบนี้ เราสามารถกำหนดค่าการเข้าถึงแหล่งข้อมูล http ได้โดยการระบุ URL และการตั้งค่าการรับรองความถูกต้อง/การอนุญาตพื้นฐาน: รหัสผ่านเข้าสู่ระบบ หรือ client-cert/client-key เพื่อที่จะใช้ความสามารถในการกำหนดค่าการเข้าถึงโดยใช้โทเค็นผู้ถือ (มาตรฐานโดยพฤตินัยสำหรับ k8s) เราต้องทำการปรับแต่งเล็กน้อย

เพื่อแก้ไขปัญหานี้ คุณสามารถใช้กลไก Grafana “Plugin Routes” ในตัวได้ (รายละเอียดเพิ่มเติมที่ หน้าเอกสารอย่างเป็นทางการ). ในการตั้งค่าแหล่งข้อมูลของเรา เราสามารถประกาศชุดกฎการกำหนดเส้นทางที่จะถูกประมวลผลโดยพร็อกซีเซิร์ฟเวอร์ Grafana ตัวอย่างเช่น สำหรับตำแหน่งข้อมูลแต่ละจุด คุณสามารถตั้งค่าส่วนหัวหรือ URL ที่เป็นไปได้ของการสร้างเทมเพลต ข้อมูลที่สามารถนำมาจากช่อง jsonData และ SecureJsonData (สำหรับการจัดเก็บรหัสผ่านหรือโทเค็นในรูปแบบที่เข้ารหัส) ในตัวอย่างของเรา ข้อความค้นหาเช่น /__พรอกซี/api/v1/เนมสเปซ จะถูกพร็อกซีไปที่ URL ของแบบฟอร์ม
/api/v8/namespaces พร้อมการอนุญาต: ส่วนหัวของผู้ถือ

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

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

ตอนที่ 5: ปล่อย

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

เมื่อคุณเขียนปลั๊กอิน Grafana ของคุณเองแล้ว คุณจะต้องเผยแพร่ต่อสาธารณะโดยธรรมชาติ ใน Grafana นี่คือไลบรารีของปลั๊กอินที่มีอยู่ที่นี่ grafana.com/grafana/ปลั๊กอิน

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

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

โดยที่ version คือเวอร์ชันของปลั๊กอินของคุณ url คือลิงก์ไปยังพื้นที่เก็บข้อมูล และ Commit คือแฮชของการคอมมิตซึ่งปลั๊กอินเวอร์ชันใดเวอร์ชันหนึ่งจะพร้อมใช้งาน

และที่ผลลัพธ์คุณจะเห็นภาพที่ยอดเยี่ยมเช่น:

การพัฒนาปลั๊กอินสำหรับ Grafana: ประวัติความเป็นมาของภาพใหญ่

ข้อมูลจะถูกดึงโดยอัตโนมัติจากไฟล์ Readme.md, Changelog.md และไฟล์ Plugin.json พร้อมคำอธิบายปลั๊กอิน

ตอนที่ 6: แทนที่จะเป็นข้อสรุป

เราไม่ได้หยุดพัฒนาปลั๊กอินของเราหลังการเปิดตัว และตอนนี้เรากำลังดำเนินการตรวจสอบการใช้ทรัพยากรของโหนดคลัสเตอร์อย่างถูกต้อง แนะนำคุณสมบัติใหม่เพื่อปรับปรุง UX และยังได้รับผลตอบรับจำนวนมากที่ได้รับหลังจากติดตั้งปลั๊กอินทั้งจากลูกค้าของเราและจากผู้คนบน GitHub (หากคุณออก ปัญหาของคุณหรือคำขอดึงฉันจะมีความสุขมาก :)

เราหวังว่าบทความนี้จะช่วยให้คุณเข้าใจเครื่องมือที่ยอดเยี่ยมเช่น Grafana และอาจเขียนปลั๊กอินของคุณเองได้

ขอบคุณ!)

ที่มา: will.com

เพิ่มความคิดเห็น