生产实践与排障
系列收官篇。前面七篇把功能跑通了,这篇把「跑稳」补齐:生产部署清单、高可用、备份迁移、安全基线、升级注意,最后是一份排障手册。出问题的时候直接从「性能与排障」一节翻起。
文中示例基于 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填其他实例的地址,同一条告警只发一次。告警链路的完整配置见告警与通知一篇。 - 唯一要人工对齐的是插件:插件文件在本地磁盘,每台实例装同一套插件、同一个版本。容器部署把插件打进镜像最省事。
这套方案解决的是「某个 Grafana 进程挂了服务不断」。数据库本身的高可用(PG 主备、MySQL 主从)是另一层的事,别指望 Grafana 替你管。
备份与迁移
先盘清楚家当在哪:
| 内容 | 位置 | 备份方式 |
|---|---|---|
| 仪表盘、用户、数据源、告警规则 | 数据库(PG/MySQL)或 grafana.db | pg_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 系列)一般直接上最新补丁版。
性能与排障
大仪表盘打开卡
症状:某个大盘加载十几秒,浏览器风扇起飞。三个元凶按出现概率排:
- 面板太多:一个仪表盘上百个 panel,打开时同时发出上百条查询,浏览器和 Grafana 一起喘不过气。按主题拆成多个仪表盘,用 dashboard link 串起来。
- 单查询太重:大范围 + 高基数指标的 rate 查询,一条查好几秒。Prometheus 侧用 recording rules 预聚合(思路见长期存储与高可用一篇),面板直接查预聚合结果。
- 默认时间范围太大:默认 24h 甚至 7d,每次打开先扫一大段。默认范围调小到 1h 或 6h,需要看长趋势再手动拉。
顺手的手段:用变量与模板按主机、服务过滤,避免一次查全量;数据源层面的 query cache 打开。
数据源查询超时
报错长这样:面板上 504 Gateway Timeout,或 Post "http://...": context deadline exceeded。超时是一根传导链,任何一环先到都会截断请求:
浏览器 → nginx(proxy_read_timeout 默认 60s)→ Grafana(dataproxy timeout 默认 30s)→ 数据源自身超时
顺着链排查:
- Grafana 日志里找带 timeout 的 error 记录,确认是 Grafana 主动断的(
[dataproxy] timeout到点)还是被数据源断的。 - 查询真的慢(Prometheus 算不动)就优化查询或上预聚合,光调大超时是把问题往后推。
- 确属合理的慢查询(报表类),调大
[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、长期存储),把整条可观测链路在自己的环境里真正转起来。