第 12/19 天
引言
在上一篇文章中,我们通过 kube-prometheus-stack 完成了 Prometheus 的部署,并利用 ServiceMonitor 实现了对 K8s 集群各项指标的自动采集。然而,Prometheus 本身只是一个时序数据库和数据采集引擎——它存储了海量的监控数据,却不擅长将这些数据以直观、美观的方式呈现出来。这正是 Grafana 的用武之地。
Grafana 是目前开源领域最流行的可视化平台之一,支持数十种数据源(Prometheus、InfluxDB、Elasticsearch、Loki 等),拥有庞大的社区仪表板生态。在本篇文章中,我们将在已有的 kube-prometheus-stack 基础上,深入实践 Grafana 看板的搭建:既会导入 K8s 社区标准面板快速获得集群全局视图,又会从零创建自定义业务看板,将 Prometheus 指标转化为对研发和运维真正有价值的洞察。

核心概念
Grafana 架构与数据流
Grafana 的核心工作流可以概括为三个层次:
- 数据源(DataSource):Grafana 不自己存储数据,而是通过配置数据源连接后端存储引擎。在我们的场景中,数据源就是 kube-prometheus-stack 部署的 Prometheus 实例。
- 仪表板(Dashboard):由多个面板(Panel)组成,每个面板绑定一个查询表达式(如 PromQL),以折线图、仪表盘、表格、热力图等形式渲染数据。
- 变量(Variables):仪表板级别的参数化机制,支持通过下拉框切换 namespace、pod、node 等维度,实现一个看板覆盖多场景的复用能力。
kube-prometheus-stack 内置的 Grafana
在前一天的部署中,kube-prometheus-stack Helm Chart 已经自动集成了 Grafana 组件。我们可以通过以下方式获取 Grafana 的访问凭据:
# 获取 Grafana 初始管理员密码(存储在 Secret 中)
kubectl get secret -n monitoring kube-prometheus-stack-grafana
-o jsonpath="{.data.admin-password}" | base64 -d ; echo
# 获取 Grafana Service 信息
kubectl get svc -n monitoring | grep grafana
# 通过端口转发本地访问(生产环境建议配置 Ingress)
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80
打开浏览器访问 http://localhost:3000,使用用户名 admin 和上面获取的密码即可登录。此时,Prometheus 数据源已经被 kube-prometheus-stack 自动注入并配置好,无需手动添加。
实战步骤
一、导入 K8s 社区标准面板
Grafana 社区维护了大量高质量的 K8s 监控仪表板,我们可以直接通过 Dashboard ID 导入,而不必从零搭建。以下是几个经典面板:
| 面板名称 | Dashboard ID | 适用场景 |
|---|---|---|
| Kubernetes Cluster Monitoring | 315 | 集群全局资源概览 |
| Kubernetes Pods | 6417 | Pod 级别 CPU/内存详情 |
| Node Exporter Full | 1860 | 节点主机层指标全貌 |
| CoreDNS | 15762 | DNS 解析性能监控 |
方式一:通过 Web UI 导入
- 登录 Grafana → 左侧菜单点击 Dashboards → Import
- 在 “Import via grafana.com” 输入框中填入 Dashboard ID(如
315) - 点击 Load,选择 Prometheus 数据源
- 点击 Import 完成导入
方式二:通过 Grafana API 批量导入
在生产环境中,我们通常希望将看板配置纳入版本管理,实现可重复部署。可以通过 API 脚本化导入:
#!/bin/bash
GRAFANA_URL="http://localhost:3000"
GRAFANA_USER="admin"
GRAFANA_PASS="$(kubectl get secret -n monitoring kube-prometheus-stack-grafana -o jsonpath='{.data.admin-password}' | base64 -d)"
# 定义要导入的面板 ID 列表
DASHBOARD_IDS=(315 6417 1860 15762)
for ID in "${DASHBOARD_IDS[@]}"; do
echo "Importing dashboard $ID…"
# 从 grafana.com 下载面板 JSON
DASHBOARD_JSON=$(curl -sL "https://grafana.com/api/dashboards/${ID}/revisions/latest/download")
# 构造 API 请求体
PAYLOAD=$(jq -n –argjson db "$DASHBOARD_JSON" '{dashboard: $db, overwrite: true}')
# 通过 Grafana HTTP API 导入
curl -s -X POST "${GRAFANA_URL}/api/dashboards/db"
-u "${GRAFANA_USER}:${GRAFANA_PASS}"
-H "Content-Type: application/json"
-d "$PAYLOAD" | jq -r '.title + " => " + (.status // "unknown")'
done
提示:将上述脚本保存为
import-dashboards.sh,后续集群重建时一键恢复所有标准面板。
二、配置 Helm Values 持久化看板
除了手动导入,更推荐的做法是通过 Helm Values 让看板在部署时自动加载。kube-prometheus-stack 的 grafana.dashboards 字段支持定义 ConfigMap 引用的面板:
# values-grafana-dashboards.yaml
grafana:
adminPassword: "ChangeMeInProduction!"
persistence:
enabled: true
size: 10Gi
storageClassName: "local-path"
# 通过 ConfigMap 预置自定义看板
dashboardProviders:
dashboardproviders.yaml:
apiVersion: 1
providers:
– name: 'custom'
orgId: 1
folder: 'DevOps Custom'
type: file
disableDeletion: false
editable: true
options:
path: /var/lib/grafana/dashboards/custom
dashboards:
custom:
k8s-overview:
gnetId: 315
revision: 1
datasource: Prometheus
k8s-pods:
gnetId: 6417
revision: 1
datasource: Prometheus
# 额外数据源(如需接入 Loki 日志)
additionalDataSources:
– name: Loki
type: loki
url: http://loki-gateway.monitoring.svc.cluster.local:80
access: proxy
isDefault: false
应用配置:
helm upgrade kube-prometheus-stack prometheus-community/kube-prometheus-stack
-n monitoring
-f values-grafana-dashboards.yaml
–reuse-values
三、从零创建自定义业务看板
标准面板覆盖的是基础设施层指标。在实际业务中,我们往往需要监控应用维度的自定义指标——比如 API 请求量、错误率、P99 延迟等。接下来我们从零创建一个业务看板。
3.1 定义看板变量
进入 Grafana → Dashboards → New → New Dashboard,首先配置变量以实现多 namespace 切换:
- 变量名
namespace,类型 Query,数据源选 Prometheus - 查询表达式:
label_values(kube_pod_info, namespace) - 变量名
pod,类型 Query,查询表达式:label_values(kube_pod_info{namespace=~"$namespace"}, pod)
这样面板的 PromQL 就可以引用 $namespace 和 $pod 实现动态过滤。
3.2 核心业务面板 PromQL
以下是一个典型的微服务业务看板需要覆盖的查询:
# 1. API 请求速率(QPS)— 按状态码分类
sum(rate(http_requests_total{namespace="$namespace", pod=~"$pod"}[5m])) by (status_code)
# 2. 错误率(5xx 占比)
sum(rate(http_requests_total{namespace="$namespace", status_code=~"5.."}[5m]))
/
sum(rate(http_requests_total{namespace="$namespace"}[5m])) * 100
# 3. P99 延迟(使用直方图分位数)
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{namespace="$namespace"}[5m])) by (le)
)
# 4. Pod CPU 使用率(相对于 Limit)
sum(rate(container_cpu_usage_seconds_total{namespace="$namespace", container!=""}[5m])) by (pod)
/
sum(kube_pod_container_resource_limits{resource="cpu", namespace="$namespace"}) by (pod) * 100
# 5. Pod 内存使用量
sum(container_memory_working_set_bytes{namespace="$namespace", container!=""}) by (pod)
3.3 面板布局建议
一个好的业务看板应该遵循”从宏观到微观”的布局原则:
- 顶部行(Row):关键 SLI 指标概览——QPS、错误率、P99 延迟,使用 Stat 面板或 Gauge 面板,配阈值着色
- 第二行:请求量趋势折线图(按状态码分系列),叠加错误率百分比曲线
- 第三行:延迟分布热力图(使用 Heatmap 面板展示 P50/P95/P99 分位)
- 底部行:Pod 资源使用明细表格,列出 CPU/内存使用率、重启次数
3.4 导出看板 JSON 纳入 GitOps
看板配置完成后,点击 Dashboard 右上角 Share → Export → View JSON,将 JSON 内容复制保存到 Git 仓库:
# 在 GitOps 配置仓库中
mkdir -p manifests/grafana-dashboards/business-api
# 将导出的 JSON 保存为以下文件
# manifests/grafana-dashboards/business-api/business-overview.json
# 创建 ConfigMap 将看板挂载到 Grafana
cat > manifests/grafana-dashboards/business-api-configmap.yaml << 'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-dashboard-business
namespace: monitoring
labels:
grafana_dashboard: "1"
data:
business-overview.json: |
{
"title": "Business API Overview",
"schemaVersion": 39,
"templating": { … }
}
EOF
通过给 ConfigMap 打上 grafana_dashboard: "1" 标签,kube-prometheus-stack 中的 Grafana Sidecar 会自动发现并加载该看板,无需重启 Pod。当 Argo CD 同步该 ConfigMap 后,新看板即可在 Grafana 中自动出现——这就是 GitOps 管理监控看板的完整闭环。
常见问题
Q1:Grafana 面板显示 “No data” 怎么排查?
依次检查:(1) 数据源是否正确选择 Prometheus;(2) 在 Prometheus Web UI 中直接执行该 PromQL 确认有数据返回;(3) 检查时间范围选择器是否设置了过短的时间窗口;(4) 确认变量值已正确选择(namespace/pod 不为空);(5) 检查 ServiceMonitor 的 labelSelector 是否匹配到目标 Pod。
Q2:自定义业务指标在 Prometheus 中找不到?
如果业务应用通过 /metrics 暴露了自定义指标但没有被采集,需要检查:(1) Pod 是否有正确的 annotation(prometheus.io/scrape: "true"、prometheus.io/port: "8080");(2) 是否创建了对应的 ServiceMonitor 资源;(3) ServiceMonitor 的 namespaceSelector 和 selector.matchLabels 是否正确匹配。可以通过 kubectl get servicemonitor -A 查看已注册的采集规则。
Q3:Grafana 密码修改后如何持久化?
通过 Helm Values 的 grafana.adminPassword 字段配置后,需要执行 helm upgrade 并删除 Grafana Pod 触发重建(密码在首次启动时写入 Secret 后不再随 Pod 重启改变)。如果希望以后修改密码不丢失,建议配置 grafana.persistence.enabled: true 使用 PVC 持久化 /var/lib/grafana 目录。
Q4:看板变量下拉框加载缓慢?
当集群规模较大时,label_values 查询可能返回大量标签值导致加载缓慢。优化方式:(1) 在查询中使用 =~ 正则过滤范围,如 label_values(kube_pod_info{namespace=~"prod-.*", namespace);(2) 在变量配置中启用 “Multi-value” 并限制 “Include All option”;(3) 在 Prometheus 配置中对高基数标签进行 metric_relabel_configs 裁剪。
总结
今天我们围绕 Grafana 看板搭建展开了系统性的实战:首先通过 Dashboard ID 快速导入 K8s 社区标准面板,获得了集群资源、Pod、节点、DNS 等多维度的开箱即用视图;随后通过 Helm Values 实现了看板配置的持久化和自动化加载;最后从零构建了一个业务级看板,覆盖了 API QPS、错误率、P99 延迟等核心 SLI 指标,并将看板 JSON 纳入 GitOps 管理。
关键要点回顾:
- 标准面板优先:社区已提供了大量经过验证的 K8s 看板,导入即可用,避免重复造轮子
- 变量是灵魂:合理使用
$namespace、$pod等变量,让一个看板覆盖多场景 - GitOps 管理看板:将看板 JSON 存入 Git 仓库,通过 ConfigMap + Sidecar 自动同步,实现配置即代码
- 业务指标分层:基础设施指标用标准面板,应用业务指标用自定义面板,两者互补形成完整可观测性视图
有了 Prometheus 采集和 Grafana 可视化,我们已经能看到集群的实时状态。但”看到”只是第一步——当指标异常时,我们需要被主动告知。这正是明天告警体系要解决的问题。
下期预告
第 13 天:告警规则与 Alertmanager:钉钉/邮件通知渠道配置
我们将配置 Prometheus 告警规则(如 Pod CrashLoopBackOff、节点 NotReady、CPU 超阈值等),部署 Alertmanager 并打通钉钉机器人和邮件通知渠道,让异常第一时间触达运维人员。
系列大纲
- 全链路架构总览:从代码提交到灰度发布的完整管道设计
- K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
- Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
- GitLab CE 自托管部署:代码仓库与项目管理平台
- GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
- GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
- Harbor 镜像版本管理与 Tag 策略配置
- Argo CD 部署与 GitOps 配置仓库创建
- CI 与 CD 联动:从代码提交到部署的全自动闭环
- SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成
- Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
- Grafana 看板搭建:K8s 标准面板与自定义业务看板(今天)
- 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
- Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
- 金丝雀发布实战:setWeight 流量分割与 pause 步骤
- AnalysisTemplate 指标分析与自动回滚机制
- 全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程
- 生产化加固要点:Harbor/GitLab/Argo CD/SonarQube 高可用方案
- 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签

















暂无评论内容