跳到主要内容

生产实践与排障

系列收官篇。前面七篇把功能跑通了,这篇把「跑稳」补齐:生产部署清单、高可用、备份迁移、安全基线、升级注意,最后是一份排障手册。出问题的时候直接从「性能与排障」一节翻起。

环境说明

文中示例基于 Grafana 10/11/12(OSS 版),配置用 grafana.ini 写法。容器部署时换算成环境变量:节名加键名全大写、GF_ 前缀,如 [security] admin_password 对应 GF_SECURITY_ADMIN_PASSWORD。

生产部署清单​

数据库换掉 SQLite(必做)​

默认 SQLite,数据存在 /var/lib/grafana/grafana.db,单机玩耍可以,生产不行:并发写性能差、撑不起多实例、备份手段原始。换 PostgreSQL:

[database]
type = postgres
host = pgsql.internal:5432
name = grafana
user = grafana
password = ${GRAFANA_DB_PASSWORD}
ssl_mode = require
max_open_conn = 20

MySQL 也行(type = mysql,host 写成 tcp(127.0.0.1:3306) 形式),建库时字符集指定 utf8mb4,不然存中文仪表盘标题和注释迟早踩编码坑。密码别明文落盘,像上面一样用环境变量注入。

换库不会自动迁移数据

改完 database 配置重启,Grafana 会在新库上初始化一套空表——旧仪表盘、用户、数据源全留在旧 SQLite 里,不会自己搬。已有数据的实例换库前先做导出迁移;全新部署第一天就上 PG,别给将来留迁移作业。

反向代理与域名​

Grafana 一般藏在 nginx 后面。Grafana 侧两个配置:

[server]
domain = grafana.example.com
root_url = https://grafana.example.com/

[security]
cookie_secure = true
cookie_samesite = lax
  • root_url:Grafana 对外生成链接(告警通知里的仪表盘链接、邀请邮件)都用它。配错的典型症状:告警里点出来的链接是 localhost。
  • cookie_secure = true:只在 HTTPS 下发送 cookie。用 HTTP 访问时千万别开,否则 cookie 发不出来,登录成功立刻被弹回登录页(排障一节细讲)。

nginx 侧是常规反代,记得带 WebSocket 相关的 header(Grafana Live 的实时推送要用):

location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

HTTPS 证书终止在 nginx 这层就行(certbot 或内部 CA),Grafana 本体继续跑 HTTP。

高可用​

Grafana 本体无状态,状态全在数据库里,高可用方案很朴素:多实例 + 共享数据库 + 负载均衡,不需要特殊的集群配置。

  • 数据库换成 PG/MySQL 之后,session 和登录 token 天然共享,请求落到哪台实例都一样,LB 不用配会话保持。
  • 仪表盘、数据源等配置写库即共享,任意实例上的变更其他实例立刻可见。
  • 告警走内置 Alertmanager 的集群模式:多实例之间用 gossip 同步通知状态,[unified_alerting] ha_peers 填其他实例的地址,同一条告警只发一次。告警链路的完整配置见告警与通知一篇。
  • 唯一要人工对齐的是插件:插件文件在本地磁盘,每台实例装同一套插件、同一个版本。容器部署把插件打进镜像最省事。
HA 的边界

这套方案解决的是「某个 Grafana 进程挂了服务不断」。数据库本身的高可用(PG 主备、MySQL 主从)是另一层的事,别指望 Grafana 替你管。

备份与迁移​

先盘清楚家当在哪:

内容位置备份方式
仪表盘、用户、数据源、告警规则数据库(PG/MySQL)或 grafana.dbpg_dump / mysqldump;SQLite 用 .backup 命令
provisioning 配置/etc/grafana/provisioning/进 git,随仓库备份
主配置grafana.ini 与环境变量(含密钥)进配置管理,密钥单独存
插件/var/lib/grafana/plugins可不备,记录插件清单和版本,恢复时重装

SQLite 直接 cp 文件有风险(写入过程中拷出坏文件),用 sqlite3 的在线备份命令:

sqlite3 /var/lib/grafana/grafana.db ".backup '/backup/grafana-$(date +%F).db'"

迁移到新机器的顺序:装同版本 Grafana → 恢复数据库 → 放 provisioning 和 grafana.ini → 按清单装插件 → 启动验证 → 再考虑升级版本。迁移和升级别放在同一次操作里,出了问题分不清是谁的锅。

备份不演练等于没有备份

每季度挑一次,把备份真的恢复到测试环境:点几个仪表盘、查一条告警、登录一个账号。备份脚本跑了三年、恢复时发现文件是坏的,这种事故在运维圈不算新闻。

安全基线​

上线前对着这份清单过一遍:

  • 默认口令:admin/admin 首次登录会强制改,但容器环境常被环境变量固化——用 GF_SECURITY_ADMIN_PASSWORD 显式设置强口令,顺手用 GF_SECURITY_ADMIN_USER 把 admin 改成不易猜的名字。
  • 关匿名访问:[auth.anonymous] enabled = false。默认就是关的,做 iframe 嵌入时开过的话记得评估暴露面(见上一篇)。
  • 限制注册:[users] allow_sign_up = false,否则任何人都能注册进来看默认 Org。
  • 换 secret_key:[security] secret_key 用于加密数据库里的数据源密码,换成随机值。注意:已有数据源的情况下换 key,老密码全部解不开、要重新录入——所以第一天就换好。
  • 安全响应头:strict_transport_security = true(上了 HTTPS 再开);x_content_type_options、x_xss_protection 默认已开,确认没被人关掉。
  • 关 gravatar:[users] disable_gravatar = true,头像请求不外发,内网环境顺手关掉。
  • 组织隔离:多团队共用时按上一篇的 Org/Folder 权限划清边界,别让默认 Org 变成公共广场。
安全基线落成配置模板

以上每一项都对应 ini 配置或 GF_ 环境变量,全部写进部署模板(compose 文件、helm values、ansible 变量),别手工在 UI 上点——点出来的基线没法审计、没法复制,下次部署就忘了。

升级注意​

  • 跨大版本先读官方升级指南:每个大版本的 What's New 和 Breaking Changes 值得花十分钟。尤其 10 → 11:AngularJS 面板支持在 Grafana 11 正式移除,用了老 angular 插件的面板升级后直接不渲染——升级前先盘点插件清单和面板类型。
  • 插件兼容性:插件和 Grafana 版本有匹配关系,升级后过老的插件可能不加载。升级后第一件事看 Administration → Plugins 有没有报错。
  • 先测试环境:把生产备份恢复到测试实例,升级测试实例,点一遍核心仪表盘,再动生产。数据库迁移是单向的——升级后旧版本读不了新库,回滚只能靠恢复备份,没有降级按钮。
  • 逐大版本升:从 9 到 12 别一把梭,9 → 10 → 11 → 12 逐版本来,每步验证。小版本之间(11.x 系列)一般直接上最新补丁版。

性能与排障​

大仪表盘打开卡​

症状:某个大盘加载十几秒,浏览器风扇起飞。三个元凶按出现概率排:

  1. 面板太多:一个仪表盘上百个 panel,打开时同时发出上百条查询,浏览器和 Grafana 一起喘不过气。按主题拆成多个仪表盘,用 dashboard link 串起来。
  2. 单查询太重:大范围 + 高基数指标的 rate 查询,一条查好几秒。Prometheus 侧用 recording rules 预聚合(思路见长期存储与高可用一篇),面板直接查预聚合结果。
  3. 默认时间范围太大:默认 24h 甚至 7d,每次打开先扫一大段。默认范围调小到 1h 或 6h,需要看长趋势再手动拉。

顺手的手段:用变量与模板按主机、服务过滤,避免一次查全量;数据源层面的 query cache 打开。

数据源查询超时​

报错长这样:面板上 504 Gateway Timeout,或 Post "http://...": context deadline exceeded。超时是一根传导链,任何一环先到都会截断请求:

浏览器 → nginx(proxy_read_timeout 默认 60s)→ Grafana(dataproxy timeout 默认 30s)→ 数据源自身超时

顺着链排查:

  1. Grafana 日志里找带 timeout 的 error 记录,确认是 Grafana 主动断的([dataproxy] timeout 到点)还是被数据源断的。
  2. 查询真的慢(Prometheus 算不动)就优化查询或上预聚合,光调大超时是把问题往后推。
  3. 确属合理的慢查询(报表类),调大 [dataproxy] timeout 的同时调大 nginx 的 proxy_read_timeout——只调一头,另一头照样截断。

登录循环​

症状:账号密码正确,登录成功,下一秒又弹回登录页,无限循环。九成是 cookie 的事:

  • cookie_secure = true 但用 HTTP 访问:浏览器拒绝在非 HTTPS 下收 secure cookie,登录态写不进去。改回 false,或者上 HTTPS。
  • root_url / domain 与实际访问地址不符:比如配了域名但大家用 IP 访问,cookie 的 domain 对不上。统一访问入口,或者把配置改成实际用的地址。
  • cookie_samesite 与嵌入冲突:Grafana 嵌在别的系统里、跨站跳转登录的场景,lax 会拦跨站 cookie,需要 none + secure + HTTPS 三件套。

日志在哪看​

  • 容器:标准输出,docker logs grafana 或 kubectl logs,接进日志系统即可。
  • 包安装:journalctl -u grafana-server;文件日志在 /var/log/grafana/grafana.log([log] mode = console file 控制输出目标)。
  • 排查时临时提级别:[log] level = debug,查完调回 info——debug 量很大,别长期开。

顺手记一条救急的:admin 密码忘了,在服务器上用 CLI 重置:

grafana-cli admin reset-admin-password 'NewStrongPass123'

容器里 docker exec 进去执行;这条命令直接操作数据库,多实例部署时任选一台执行即可。

小结​

收官篇把 Grafana 从「能用」推进到「敢上生产」:数据库换 PG/MySQL 是一切后续动作的地基;HA 靠多实例加共享库,告警走 Alertmanager 集群模式;备份盯住数据库、provisioning、配置三件事,并定期演练恢复;安全基线落成配置模板;升级先读变更说明、先测试环境、别跨级跳。

回顾全系列八篇:从安装部署与界面认识起步,接数据源、搭出第一块仪表盘;变量与模板把仪表盘参数化,一套面板顶十套用;告警与通知把「出了事通知谁」的链路跑通;上一篇分享与权限解决「给团队用」;本篇解决「跑得稳」。八篇走完,Grafana 这一侧的路就铺完了——剩下的是接回 Prometheus 那一侧(采集、PromQL、长期存储),把整条可观测链路在自己的环境里真正转起来。