如果你第一次接触 Grafana,想改个端口、换掉默认数据库或者调整权限策略,大概率会和我当初一样:直接跑到安装目录里找到 defaults.ini,改完重启,然后发现配置纹丝不动,甚至服务直接起不来。这不是手误,而是 Grafana 的配置体系跟普通软件不太一样,它把默认配置和用户自定义配置分成了两层,外层还可以用环境变量和命令行参数继续覆盖。这篇文章就把 Grafana 的配置文件从头到尾捋一遍,包括 defaults.ini、custom.ini、环境变量的分工,常用配置段的作用,以及 provisioning 自动配置目录的用法。适合刚搭好 Grafana、想按自己需求调整面板的开发者参考,读完你至少不会再改错文件、也不会因为一个 secret_key 丢了导致数据源全部失效。
1. 先说清楚配置文件的边界:defaults.ini、custom.ini 与环境变量
1.1 defaults.ini 是出厂默认配置,不是给你直接改的
Grafana 安装好之后,安装目录下会有一个 defaults.ini,里面几乎涵盖了所有配置项的默认值。注意这个文件的作用是“给程序提供一个找不到任何自定义配置时也能启动的兜底”,而不是让你直接修改的入口。
为什么不建议直接改它?两个原因。第一,Grafana 升级时安装包会整体替换或更新 defaults.ini,你写在里面的自定义项会随着升级直接丢失,甚至因为新旧格式不兼容导致配置解析异常。第二,defaults.ini 的变更会影响你整个环境里所有实例的基线行为,排查问题时很难分清到底是你改的还是默认文件被带偏了。
你正确的方式是新建一个 custom.ini,然后在里面只写需要覆盖的配置项。很多新手问:“我没找到 custom.ini 怎么办?”很正常,安装包里通常只有 defaults.ini,custom.ini 需要你自己创建,或者从安装文档提供的样例复制一份。Debian/Ubuntu 的安装包会生成/etc/grafana/grafana.ini,这个文件本质上就是 custom.ini 的角色,只是名字不叫 custom.ini 而已。
1.2 custom.ini:用户自定义配置的真正入口
Grafana 的配置查找顺序是:先读取程序内置的默认值,然后读取 defaults.ini,再去读取位于指定位置的 custom.ini,最终以更靠后的配置为准。如果你没有显式指定 custom.ini 的路径,Grafana 会按编译时的默认路径去找,常见的包括:
- Linux 二进制包:
/etc/grafana/custom.ini或/etc/grafana/grafana.ini - Docker 镜像:
/etc/grafana/grafana.ini - Mac 开发环境:
/usr/local/etc/grafana/grafana.ini
实际部署时,很多团队习惯把 custom.ini 放到/etc/grafana/目录下,再用启动参数--config=/etc/grafana/custom.ini显式指定。这种做法有一个额外好处:当你同时维护多套 Grafana 实例(测试环境、预发环境、生产环境)时,可以用同一份安装包,通过指向不同的配置文件来区分环境,互不干扰。
custom.ini 的格式是标准的 INI 格式,用[section]分段,每个段下面放key = value。注释可以用;或者#开头。比如:
[server] ; 对外开放的端口 http_port = 8080 [database] type = postgres host = 127.0.0.1:5432注意,custom.ini 不需要把 defaults.ini 里的所有内容都复制过来,只写你要覆盖的项即可,没写到的全部走默认值。
1.3 环境变量是第三层覆盖,容器部署时最容易踩坑
除了文件配置,Grafana 还支持环境变量覆盖。规则很简单:环境变量名按照GF_+ 配置段名 + 配置项名的格式组合,全部转大写,中间用下划线分隔。例如:
GF_SERVER_HTTP_PORT对应[server] http_portGF_DATABASE_TYPE对应[database] typeGF_SECURITY_ADMIN_PASSWORD对应[security] admin_passwordGF_AUTH_ANONYMOUS_ENABLED对应[auth.anonymous] enabled
完整优先级从低到高是:程序内置默认值 < defaults.ini < custom.ini < 环境变量 < 命令行参数。也就是说,如果你在 custom.ini 里把端口改成了 8080,但环境中还设了GF_SERVER_HTTP_PORT=9090,最终生效的会是 9090。
这个机制在 Docker 和 Kubernetes 环境里非常常见,但也非常容易出问题。最典型的坑是:自定义配置写在 YAML 或编排文件的环境变量里,看起来和 custom.ini 是两套完全不同的值,对不上号。我还遇到过有人把GF_SERVER_HTTP_PORT拼成了GF_SERVER_PORT,程序没有任何报错,只是静默忽略了,结果排查了半天才发现环境变量名字根本没对上。
所以建议养成一个习惯:凡是容器部署,优先看环境变量;凡是传统二进制包部署,优先看 custom.ini。两边都有配置时,以环境变量为准,不要再纠结文件里写了什么。
2. 逐段拆解最常改的后端配置
2.1 server 段:端口、域名和对外访问地址
server 段是所有配置里改动频率最高的地方。最关键的几个参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
| http_port | 3000 | Grafana 的 HTTP 监听端口 |
| domain | localhost | 对外访问域名,用于生成票据、回调地址 |
| root_url | %(protocol)s://%(domain)s:%(http_port)s/ | 完整对外访问地址 |
| enforce_domain_redirect | false | 访问 IP 时是否强制跳转到 domain |
| static_root_path | public | 静态资源目录 |
root_url值得单独说。它不只是给浏览器跳转用的,Grafana 内部生成告警图片链接、嵌入面板地址、邮件通知链接时都会基于它。如果你把 Grafana 放在 Nginx 后面,用/grafana/这样的子路径对外提供服务,而不是独立的子域名,那 root_url 必须改成https://你的域名/grafana/,否则告警邮件里的链接点进去全是 404。
实际配置示例:
[server] http_port = 8080 domain = grafana.example.com root_url = https://grafana.example.com注意,改了 http_port 不代表原来的 3000 端口就自动失效,如果你忘了把别的服务的反向代理规则一起改,老的端口可能仍然在监听,只是没有日志,排查时很误导人。
2.2 database 段:默认 SQLite 和外部数据库怎么选
Grafana 默认使用内嵌 SQLite 存储用户、面板、数据源元数据。这个设计对个人使用和小团队非常友好,装完就能跑,不用额外装数据库。但生产环境下我一般不建议长期用 SQLite,原因有三个:
- 并发写入能力有限,多人同时保存面板时容易碰到数据库锁。
- 备份策略不灵活,直接拷贝文件虽然可行,但要非常小心写权限和 WAL 文件。
- Grafana 后期如果开了某些高流量功能,SQLite 会成为瓶颈。
system 我的建议是:监控规模超过几十台机器,或者团队超过几个人同时用 Grafana,就直接上 PostgreSQL。配置方式:
[database] type = postgres host = 127.0.0.1:5432 name = grafana user = grafana password = 你的密码 ssl_mode = requireMySQL 也可以用,type 改成 mysql 即可。这里要注意一个转换成本问题:从 SQLite 迁到 PostgreSQL,不是说改完配置重启就完事,你需要把旧数据迁移过去。官方提供了相关工具,但仍然建议在迁移前先完整备份,尤其是面板 JSON 和用户权限记录。我见过有人直接删掉 grafana.db,重启后发现所有面板和用户全没了,才想起来没导出,那是很痛的教训。
2.3 security 段:管理员密码、secret_key 和各种安全开关
security 段大概是用户最关心、也最容易一知半解的一段。先说 admin 账号:
[security] admin_user = admin admin_password = 首次登录密码这两个配置只在 Grafana 启动时读取,用于初始化内置管理员账号。重点来了:如果 Grafana 数据库里已经存在 admin 用户,你在 custom.ini 里改 admin_password 是不会生效的,因为数据库里的记录优先级更高。也就是说,线上修改管理员密码,正确的做法是登录后在 UI 里改,而不是改配置文件再重启。
再说 secret_key。这个东西非常非常重要,它用于加密数据源密码、告警通知、面板快照图片等敏感信息。默认值写在 defaults.ini 里,生产环境一定要换成自己的随机字符串。
为什么强调这个?我见过一个真实案例:某开发者在迁移 Grafana 时只拷贝了数据库文件到新机器,启动后用户能正常登录,但所有第三方数据源全部报错,提示密码解密失败。原因就是新机器上没有把旧环境的 secret_key 一起带过去,Grafana 用新密钥去解密旧的加密数据,自然全部失败。最后只能逐个数据源重新输入密码。如果你的数据源很多,这个工作量会让你怀疑人生。
配置方式:
[security] secret_key = 一串足够复杂的随机字符串2.4 auth 段:匿名访问、登录表单和其他认证方式
认证相关配置在 auth 开头或者 auth 单独段。要搞懂 Grafana 认证,你需要知道登录本身和认证方式是两件事。
如果你只想做一个对内展示的监控大屏,不想每个人都要登录才能看到面板,可以开启匿名访问:
[auth.anonymous] enabled = true org_name = Main Org. org_role = Viewer开启后未登录用户会以 Viewer 身份访问,只能看不能改。如果你连登录表单都不想显示,可以再加:
[auth.basic] disable_login_form = true注意,disable_login_form = true只是把登录界面表单隐藏,并不是取消认证。你仍然可以通过 API 或外部认证登录。如果设置了之后发现“既能匿名访问又能登录”,不用慌,这是符合预期的行为。
如果你在 UI 上明明看到匿名访问已经开启,但实际访问还是要登录,最可能是配置被环境变量覆盖了。检查一下有没有GF_AUTH_ANONYMOUS_ENABLED=false之类的设置,因为这个变量的优先级高于 custom.ini。每次改认证配置,我都会先看一圈环境变量再下结论,免得白折腾。
2.5 session、日志和数据保留的隐藏配置
除了上面这些,还有两个容易被忽略的配置段。第一个是[sessions],默认 session 存在内存里,重启后所有登录态失效,用户会被强制踢下线。如果你不想频繁重启导致全员重新登录,可以改成存数据库:
[sessions] provider = database第二个是[log]段。默认日志级别是 Info,排错时经常觉得日志不够细,可以先临时调到 Debug,复现问题后再改回来:
[log] level = DebugDebug 日志的信息量很大,包含每个请求的耗时和配置加载细节,新手排查配置问题很实用,但不建议生产长期开着,日志量会让磁盘吃不消。
3. provisioning 目录:让数据源和面板配置随代码走
3.1 为什么推荐用 provisioning 而不是 UI 手动配置
很多人装完 Grafana,习惯在界面上点“Add data source”加数据源,往里填 URL、账号密码,然后手动 Import 一个面板 JSON 文件。这种方式对单机使用没问题,但它有一个致命缺点:不可审计、不可回滚、不可版本化。
什么时候会难受?当你维护的不止一套 Grafana:测试环境一套、生产环境一套,每次改一个数据源都要在两个界面上重复操作,改完了也不知道谁改的、什么时候改的。如果你用 Docker 或 Kubernetes 部署,那更麻烦——容器一销毁重建,所有手动配置全部丢失,除非你卷外挂的整个数据目录都在。
Grafana 提供了一条更干净的路:provisioning。它在配置目录下启动时自动加载 YAML 文件,帮你创建数据源、面板、告警规则,甚至可以定义通知渠道。好处是文件可以直接放进 Git,和环境一起部署,可重复执行。
3.2 数据源自动配置:一个 datasources.yaml 就够
Grafana 默认会读取/etc/grafana/provisioning/datasources/下的 YAML 文件。一个最基本的 Prometheus 数据源配置长这样:
apiVersion: 1 datasources: - name: Prometheus type: prometheus access: proxy url: http://prometheus:9090 isDefault: true editable: false里面access: proxy表示浏览器请求先到 Grafana,由 Grafana 转发到 Prometheus,这样可以避免跨域问题和数据源地址暴露。如果access: direct,浏览器会直接访问数据源,一般用于网络能直连的场景。
还要注意editable: false。这个字段的意思是:在 UI 里,这个数据源不能编辑和删除。新手会觉得“那我以后想改怎么办?”你的改法就是改 YAML 文件再 reload,而不是在页面上改。这其实是一种保护,防止有人手滑把生产数据源改坏。
多个数据源就并列写多个:
datasources: - name: Prometheus-Prod type: prometheus url: http://prometheus-prod:9090 - name: MySQL type: mysql url: 127.0.0.1:3306 database: myapp user: grafana secureJsonData: password: 你的密码secureJsonData是专门用来放密码的地方,Grafana 会把它加密存储,不会明文暴露在 UI 配置接口里。这是我强烈推荐的结构。
3.3 面板自动配置:dashboards.yaml 与目录结构
面板自动配置比数据源稍复杂一点,核心是定义一个 provider。官方推荐在/etc/grafana/provisioning/dashboards/下放一个 YAML:
apiVersion: 1 providers: - name: 'default' orgId: 1 folder: '' type: file disableDeletion: false updateIntervalSeconds: 30 allowUiUpdates: false options: path: /etc/grafana/provisioning/dashboards foldersFromFilesStructure: true这段配置的意思很简单:把/etc/grafana/provisioning/dashboards目录下的 JSON 面板文件全部加载进来,每隔 30 秒扫描一次。面板文件需要在 Grafana 上手动导出 JSON,或者从社区下载,然后放进这个目录。
有几个细节要提醒:
allowUiUpdates: false表示面板改动只能通过改 JSON 文件来更新,UI 上做的修改保存后会提示“源由 provisioning 托管”,不会真正写入数据库。如果你希望后续还能在 UI 上临时微调,就把这个值改成 true。updateIntervalSeconds不设也可以,默认扫描间隔比较长。改成 30 秒便于快速验证,生产环境可以调大。- 如果两个 provider 指向同一个 folder 或同样的面板文件,会出现“面板配置来源冲突”的警告,启动日志里会明确写出来。
3.4 改了 provisioning 文件后怎么让配置生效
文件改完不会自动立刻加载,数据源和面板配置都有各自的重载机制。最省事的方法是重启 Grafana 服务。不想重启的话,可以用官方提供的管理 API:
curl -X POST http://localhost:3000/api/admin/provisioning/datasources/reload curl -X POST http://localhost:3000/api/admin/provisioning/dashboards/reload注意这两个接口都需要管理员权限,HTTP 请求要带登录 cookie 或 Bearer Token。如果只是修改面板目录下的 JSON 文件,不一定需要 reload,因为 provider 的更新间隔会自动扫描。数据源文件改动就必须 reload 或重启。
我个人的实践是:把 provisioning 目录挂进容器后,平时只改 YAML 和 JSON,全部靠 API reload 生效,几乎不用重启 Grafana。这样既快又不中断告警。
4. 改完配置,如何确认它真的生效了
4.1 用设置页核对实际激活值,而不是凭印象
这是排查配置问题最高效的一招:登录 Grafana 后,在左侧菜单进入“Server Admin”下的“Settings”,页面上会列出当前进程实际生效的所有配置项,包括哪些值来自配置文件、哪些来自环境变量、哪些是内置默认值。
比对着 custom.ini 猜要靠谱得多。比如你怀疑端口没生效,去设置页搜索http_port,看到的值才是程序真正在用的值。如果你在 custom.ini 里明明写了 8080,设置页却显示 3000,说明配置文件压根没被读取,或者启动命令指定了别的文件。
设置页还有一个价值是排查环境变量覆盖。页面上某个配置的值和你预期不一致时,你看它的来源提示,基本就能判断是哪一层把它改了。
4.2 从启动日志和进程参数反向确认
设置页需要能登录才能看。如果服务都起不来,或者你想在启动阶段就确认配置文件路径,有两条路:
第一,看启动日志。Grafana 启动时会在日志里输出配置相关信息和路径,比如:
logger=config msg="Loaded configuration from /etc/grafana/custom.ini"如果你设置了多个配置来源,它也会在日志里列出最终合并结果。
第二,看进程启动参数。Linux 环境下执行:
ps aux | grep grafana有--config参数就直接告诉你用的是哪个配置文件。如果你用的是 systemd,可以通过:
systemctl cat grafana-server查看到启动命令。有些系统默认就带了--config参数,你只看/etc/grafana/grafana.ini可能看得不是同一个文件,这就是很多人“改了不生效”的终极原因。
4.3 一个典型的“改了没生效”场景
我之前在一个模拟项目 X 的部署现场排查过一个问题:运维在 custom.ini 里开启了匿名访问,重启后访问 Grafana 仍然要求登录。排查链路是这样的:
- 先看设置页,发现
auth.anonymous段下enabled的值仍然为 false。 - 再看 custom.ini,文件里确实写着
enabled = true。 - 查看进程启动参数,发现 systemd 服务启动命令里带了
--config,指向另一个路径下的 grafana.ini。 - 打开那个文件,发现里面根本没有
[auth.anonymous]段,只有旧的 server 配置。
问题到这里就清楚了:系统执行的是两个配置文件,默认的/etc/grafana/grafana.ini是空的,而他们改的是另一个/opt/grafana/custom.ini,服务根本没读取这个文件。把设置合并到正确路径并重启后问题解决。
这个案例很基础,但特别有代表性。遇到“改了不生效”,第一反应不要是“Grafana 是不是有问题”,而是先回答三个问题:改的是哪个文件?服务读的是哪个文件?当前生效的值是什么?这三个问题能节省大量时间。
5. 场景化配置清单:开发测试和生产环境该各改什么
5.1 开发测试环境:怎么配置最省心
开发测试环境下,配置目标就是“少打扰、快速验证、不怕折腾”。我一般建议开匿名访问、隐藏登录表单、允许嵌入、日志开到 Debug,这样拉个临时面板就能直接丢到 iframe 里给同事看,不用反复登录。
[server] http_port = 3000 root_url = http://localhost:3000 [auth.anonymous] enabled = true org_role = Viewer [auth.basic] disable_login_form = true [security] allow_embedding = true [log] level = Debug数据库默认用 SQLite 就行,不折腾。如果你用 Docker 跑测试环境,记得把/var/lib/grafana和/etc/grafana/provisioning用卷挂出来,否则每次重建容器配置全没了。我见过同事因为忘了挂载数据目录,三天内重复配置了三次数据源,后来一眼看出就是卷少了。
5.2 生产环境:哪些项必须优先调整
生产环境跟开发测试的取舍完全不同,重点是稳定、安全、可审计。我整理了一个自己每次上线都会过一遍的检查项:
| 配置项 | 生产建议 | 原因 |
|---|---|---|
| database.type | PostgreSQL 或 MySQL | 避免 SQLite 并发瓶颈 |
| security.secret_key | 更改为独立随机字符串 | 避免加密数据不可恢复 |
| security.admin_password | 首次登录后强制改掉 | 默认密码是攻击入口 |
| server.domain / root_url | 与反向代理域名一致 | 保证告警链接和嵌入正常 |
| auth.anonymous | 默认关闭 | 避免监控数据对外泄露 |
| log.level | Info 或 Warn | 减少日志量 |
| sessions.provider | database | 重启不踢用户 |
| provisioning 目录 | 开启并纳入 Git | 可复现、可审计 |
还有一个容易被忽视的项:如果你通过 Nginx 或负载均衡提供 HTTPS,Grafana 自己没开 TLS,但也需要把相关请求协议标识配置好,否则 Grafana 生成的回调链接可能是http,导致登录跳转出问题。在 Nginx 中设置X-Forwarded-Proto后,Grafana 侧会相应处理。
[server] root_url = https://grafana.example.com router_logging = truesmtp段我也建议在生产环境尽早配置,否则面板告警发出去了,通知邮件却发不出来:
[smtp] enabled = true host = smtp.example.com:587 user = grafana@example.com password = 发件密码 from_address = grafana@example.com配置完别忘了测试一下:在 Grafana 的 Notification channels 里选一个测试邮件接收人,发一条 Test 通知,能收到再继续。
5.3 升级和回滚:配置文件的“后悔药”怎么留
最后聊一下运维里最容易出事的环节:版本升级。Grafana 每次升级都会更新自带的 defaults.ini,新增配置项、修改参数名是常有的事。如果你的 custom.ini 还写着老版本的配置项,Grafana 不会报错,它会静默忽略不认识的键值,结果就是某个功能行为悄悄变了,但你不一定能立刻发现。
所以升级前我必有三个动作:
- 备份整个配置目录,通常是
/etc/grafana,你可以用tar -czvf grafana-backup.tar.gz /etc/grafana。 - 如果用的是 SQLite,备份对应的数据文件,并确保 Grafana 已经停止,否则拷出来的数据库可能处于不一致状态。
- 在设置页把关键配置截图或导出,作为升级前后对比的基线。
万一升级后发现某个配置项不再生效,回滚的方法也很直接:停止服务,恢复之前的配置目录,换回旧版本二进制,再启动。不过要注意,Grafana 的数据库版本也在升级,如果数据文件已经被新版本改过了,直接用旧版本去读有可能报版本不兼容。所以数据库类的回滚最好在升级前完成,或者用导出面板 JSON 的方式恢复,而不是指望数据库能无损退版。
我自己做这类操作时,还会把面板 JSON 全部导出一份放到备份 tar 包里。因为面板是最难重建的资产,丢了比配置丢了更心疼。配置文件错了可以改回来,面板没了真要重新画半天。
这个内容后续还有一个很自然的扩展方向:当你的 Grafana 实例变多之后,配置文件本身会发展成“模板 + 变量替换”的管理方式,provisioning 配合版本管理工具就会变成基础设施的一部分。不过那是另一个话题了,先把这份配置文件手册吃透,至少你已经不会再在 defaults.ini 和 custom.ini 之间反复横跳了。