Observability — Prometheus ו-Grafana משותפים
Prometheus: גילוי Pods ו-relabel ל-namespace
Section titled “Prometheus: גילוי Pods ו-relabel ל-namespace”ה-Pods של האפליקציה חושפים פורט metrics אבל אין להם Service לפורט הזה, ולכן Prometheus מגלה אותם ישירות דרך ה-API (role: pod).
scrapeConfigs: trident: enabled: true kubernetes_sd_configs: - role: pod namespaces: {names: [<NS>]} # list every environment namespace relabel_configs: - {source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_part_of], regex: trident, action: keep} - {source_labels: [__meta_kubernetes_pod_container_port_name], regex: ops|http, action: keep} - {source_labels: [__meta_kubernetes_namespace], target_label: namespace} - {source_labels: [__meta_kubernetes_pod_label_trident_dev_service], target_label: service} - {source_labels: [__meta_kubernetes_pod_name], target_label: pod}# TRIDENT: namespaces trident-dev, trident-staging, trident-prod- שתי פעולות
keep: רק Pods עם labelapp.kubernetes.io/part-of=trident, ורק container port ששמוopsאוhttp. כל השאר נזרק. - השורה
__meta_kubernetes_namespace → namespaceהיא מה שמאפשר ל-dashboard לבחור סביבה. בלעדיה אין הבדל בין dev ל-prod. - נקודות בשם label הופכות ל-
_ב-__meta_kubernetes_pod_label_*(trident.dev/serviceהופך ל-trident_dev_service). - גילוי דורש RBAC:
rbac: {create: true}ו-serviceAccounts: {server: {create: true}}ב-values של ה-chart.
לוודא שה-label קיים
Section titled “לוודא שה-label קיים”kubectl -n <NS> get svc # find the Prometheus Service namekubectl -n <NS> port-forward svc/prometheus 9090:9090בטרמינל שני (או בדפדפן, http://localhost:9090, שאילתה count by (namespace) (up)):
curl -s 'http://localhost:9090/api/v1/query' --data-urlencode 'query=count by (namespace) (up)'איך מוודאים: data.result מכיל רשומה לכל namespace של סביבה, כל אחת עם ערך גדול מ-0. חסרה סביבה = היא לא נסרקת (label, פורט, RBAC או Pods לא רצים). ה-<NS> בפקודה הראשונה הוא ה-namespace של ה-stack (ב-TRIDENT: trident-observability).
אותו דבר ב-UI של Prometheus: Status → Targets (כל target ו-State), ו-Graph לשאילתה.
Grafana: admin מ-Secret קיים
Section titled “Grafana: admin מ-Secret קיים”ה-chart לא יוצר סיסמה. הוא קורא Secret שה-bootstrap יוצר מראש (prepare-observability.sh: namespace + Secret ה-admin + Secret ה-TLS).
admin: existingSecret: <SECRET> userKey: admin-user passwordKey: admin-passwordingress: enabled: true ingressClassName: nginx path: / pathType: Prefix hosts: [<HOST>] tls: [{secretName: <SECRET>, hosts: [<HOST>]}]# TRIDENT: admin Secret trident-grafana-admin; TLS Secret trident-tls; host grafana.trident.test- ב-Secret ה-keys חייבים להיות בדיוק
userKey/passwordKey. הערכים באים מקבציcredentials/מקומיים, לא מ-Git. - ה-
<HOST>מופיע פעמיים (hostsו-tls.hosts): שנה את שניהם. הוסף אותו ל-/etc/hostsעל<VM_IP>. - ה-Secret של ה-TLS צריך להיות באותו namespace כמו ה-Ingress.
- ראה kubernetes/networking ו-kubernetes/secrets.
kubectl -n <NS> get secret <SECRET> -o jsonpath='{.data.admin-user}' | base64 -d; echokubectl -n <NS> get ingressאיך מוודאים: שם המשתמש מודפס, וה-Ingress מציג את ה-<HOST>. הרצת ה-script היא bash/templates.
Application observability אדום: סדר ההכנה
Section titled “Application observability אדום: סדר ההכנה”bash bootstrap/prepare-observability.sh # creates namespace + Secrets, safe to run twicekubectl get ns <NS>kubectl -n <NS> get secret <SECRET> -o jsonpath='{.data}' | jq 'keys'איך מוודאים: ה-namespace קיים, ו-keys מציג את שמות המפתחות בלבד (admin-user, admin-password; בלי ערכים). אז sync ידני, וה-App הופך Synced/Healthy. סקריפט מלא: bash/templates.
$${...} ב-datasources שמוגדרים ב-values
Section titled “$${...} ב-datasources שמוגדרים ב-values”Grafana ו-Helm כל אחד מפרש ${...}. בתוך datasources, ערך כמו ${__value.raw} שייך ל-Grafana (לא למשתנה סביבה), ולכן כותבים אותו כפול-דולר כדי שיישאר מילולי:
datasources: datasources.yaml: apiVersion: 1 datasources: - name: Prometheus uid: prometheus type: prometheus access: proxy url: http://prometheus:9090 isDefault: true - name: Loki uid: loki type: loki url: http://loki:3100 jsonData: derivedFields: - {name: TraceID, datasourceUid: tempo, url: '$${__value.raw}'}איך מוודאים: ב-Grafana, Connections → Data sources → Prometheus → Save & test. מופיע Successful. אם ה-URL של trace ריק, בדוק שה-$$ לא נשאר $.
dashboard דרך kustomize
Section titled “dashboard דרך kustomize”תיקייה ב-gitops עם kustomization.yaml שהופך את ה-JSON ל-ConfigMap; ה-Application מוסיף אותה כ-source (path בלבד, בלי מפתח kustomize:), ו-Grafana טוען אותה:
apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationnamespace: <NS>configMapGenerator: - name: trident-naval-picture files: [<FILE>] options: {disableNameSuffixHash: true}# TRIDENT: <FILE> = trident-naval-picture.json (the dashboard JSON next to this file)שם ה-ConfigMap (כאן trident-naval-picture) חייב להיות זהה למה ש-values של Grafana מצביעים עליו:
dashboardProviders: dashboardproviders.yaml: apiVersion: 1 providers: - {name: TRIDENT, orgId: 1, folder: TRIDENT, type: file, options: {path: /var/lib/grafana/dashboards/trident}}dashboardsConfigMaps: trident: trident-naval-picturedisableNameSuffixHash: trueחיוני: בלי זה שם ה-ConfigMap מקבל hash, וה-dashboardsConfigMapsלא ימצא אותו.- ה-source של התיקייה הוא ב-
gitopsולא ב-templates: ראה המלכודת.
kubectl kustomize <FILE>איך מוודאים: כאן <FILE> הוא נתיב התיקייה שמכילה kustomization.yaml. הפלט הוא ConfigMap בשם הנכון ועם ה-JSON בתוכו.
תקלות נפוצות
Section titled “תקלות נפוצות”| סימפטום | סיבה | בדיקה |
|---|---|---|
| ה-dashboard ריק או מערבב סביבות | relabel הוריד את namespace, או השורה חסרה | count by (namespace) (up) |
| אין targets בכלל | typo ב-label (part_of במקום part-of ב-regex source) או בשם הפורט | Status → Targets; kubectl -n <NS> get pods --show-labels |
| רק חלק מהסביבות | namespaces.names חסר סביבה, או Pods לא רצים | אותה שאילתה |
Targets ב-403/ריקים | אין RBAC לגילוי Pods | rbac.create: true ב-values |
Application observability אדום | namespace או Secret חסרים | kubectl get ns; הרץ את prepare-observability.sh |
Grafana לא עולה, secret not found | Secret ה-admin לא קיים באותו namespace | kubectl -n <NS> get secret |
סימפטומים כלליים: debugging/symptoms.
Loki, Tempo, Alloy (SHOULD)
Section titled “Loki, Tempo, Alloy (SHOULD)”לוגים (Loki), traces (Tempo) ואיסוף (Alloy) הם חלק מ-SHOULD. ה-sources שלהם נשארים מוערים ב-observability.yaml עד שמפעילים אותם: אותה צורה כמו Prometheus (chart מ-templates ב-<TAG>, values ב-$values/observability/<SERVICE>/values.yaml). ה-datasources שלהם ב-Grafana כבר מוגדרים ובלתי מזיקים עד שהם קיימים.
כלל label: מזהים ייחודיים (trace_id, request_id) לעולם לא הופכים ל-labels של Prometheus.