运维知识
悠悠
2026年11月12日

Prometheus 数据只放本地,磁盘坏了怎么办?用 Thanos 备份到 S3,这几个坑别踩

Prometheus 跑得好好的,监控图也一直有数据,我最担心的却是它脚下那块磁盘。

本地数据保留 15 天,查最近的故障没问题。可一旦磁盘损坏、机器误删,或者过了保留期才有人来追历史问题,Prometheus 自己已经拿不出那段数据了。把保留时间改成一年?磁盘、扩容和迁移又成了新问题。

这篇聊一个比较常见的做法:让 Thanos Sidecar 把 Prometheus 生成的 TSDB block 上传到 Amazon S3。我会把配置、权限、验收和恢复验证放在一起讲。这里是一套基于官方文档的部署示例,桶名、机器标签都用占位示例;没有实际部署记录的地方,我不会写成“线上已经跑通”。

先说清楚:它上传的不是实时数据

这套链路大致是这样:

Exporter → Prometheus → 本地 TSDB block → Thanos Sidecar → S3
                                                    ↓
S3 → Thanos Store Gateway → Thanos Query → Grafana 查询历史数据

Prometheus 继续负责抓取和保存近期数据,Sidecar 跟它部署在一起。Prometheus 通常每 2 小时生成一个 TSDB block,Sidecar 上传的是已经生成的 block。

这里有个非常容易误解的地方:当前正在写入的 head 数据和 WAL,不会被 Sidecar 实时同步到 S3。 刚装好就去桶里找最近一分钟的数据,找不到是正常的。机器在一个 block 生成前损坏,最近约 2 小时的数据可能还没上传。网络中断时,上传也会延后。

所以我不会把“用了 S3”理解成 Prometheus 从此可以不要持久磁盘。Thanos Sidecar 文档也明确建议保留 Prometheus 的持久存储。S3解决的是历史 block 的长期存放,不是零数据丢失的实时复制。

我会先把 S3 桶和权限收拾好

下面以 AWS 常规区域 ap-southeast-1 为例,假设桶名为 example-thanos-metrics-prod。实际部署时换成自己的桶名和区域。

桶要提前创建,保持阻止公开访问,按团队要求开启服务端加密。我也会考虑开启版本控制或跨区域复制,但不会把它们当成“恢复验证”的替代品。Thanos 后续会压缩、标记和删除旧 block;S3 里有对象,不等于任意时间点都能完整恢复。

权限尽量按组件分开。Sidecar 的工作是上传 block,通常不需要删除整个桶里的数据。给运行它的 IAM 角色限定到目标桶,例如:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::example-thanos-metrics-prod"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::example-thanos-metrics-prod/*"
    }
  ]
}

这是示例权限,具体还要结合桶策略和加密方式检查。若使用 SSE-KMS,运行组件的角色还需要相应 KMS 权限。后面要运行 Compactor,它需要处理旧 block,权限范围与 Sidecar 不一样,最好单独授予。

我更倾向于用 EC2 实例角色等临时凭据方式,而不是把 access_key、secret_key 写进配置文件。Thanos 的 S3 配置文档支持使用 AWS 凭据链;如果组件跑在容器里,还得确认容器内部确实能拿到对应角色凭据,不能只在宿主机上测通 AWS CLI 就算完事。

S3 配置文件 /etc/thanos/bucket.yml 可以这样写:

type: S3
config:
  bucket: example-thanos-metrics-prod
  endpoint: s3.ap-southeast-1.amazonaws.com
  region: ap-southeast-1
  aws_sdk_auth: true

这份文件里没有静态密钥,但仍要控制文件权限,并确认 Sidecar 进程能读取。选定 Thanos 版本后,按该版本文档核对配置字段;生产环境不要不经测试就跟着 latest 升级。

Prometheus 这里有两个参数不能漏

假设 Prometheus 已经在 Linux 主机上运行,数据目录是 /var/lib/prometheus。我会先给它设置稳定且唯一的外部标签:

global:
  scrape_interval: 15s
  external_labels:
    cluster: prod-a
    replica: prom-01

external_labels 会跟随上传的 block,用来标识数据来自哪套 Prometheus。多实例场景尤其要认真设计:不同实例不能意外使用完全相同的标签组合,同一实例重启后也别随手换标签。标签弄乱了,后续 Compactor 分组和历史查询都会麻烦。

启用 Sidecar 上传时,Prometheus 的启动参数还要包含:

--storage.tsdb.path=/var/lib/prometheus
--storage.tsdb.min-block-duration=2h
--storage.tsdb.max-block-duration=2h
--storage.tsdb.retention.time=15d
--web.enable-admin-api

把最小和最大 block 时长都设为 2h,是为了关闭 Prometheus 对这些本地 block 的进一步压缩,让 Sidecar 上传后由 Thanos Compactor 负责对象存储中的压缩。这个要求在 Thanos 官方文档里标得很重,不能只加 Sidecar、漏了 Prometheus 参数。

15d 只是示例本地保留时间,不是 S3 的保留时间。官方建议本地保留时间不要低于最小 block 时长的三倍;以 2 小时 block 计算,至少要给上传故障留出 6 小时缓冲。我不会把本地保留期压到刚好 6 小时,S3 网络或权限出点小问题,就可能来不及补传。

--web.enable-admin-api 也要注意安全边界。Prometheus API 不应因为接 Sidecar 就暴露到公网。在同一台机器部署时,可以让它监听受控地址,并通过防火墙或内部网络限制访问。已有 Grafana、采集或代理依赖 Prometheus 地址的环境,改监听配置前先确认影响。

改完配置,用 promtool check config 检查 YAML,重启 Prometheus 后再查看实际启动参数和运行日志。不要只盯着配置文件:文件写对了,服务没重启,实际运行的还是旧参数。

Sidecar 跑起来,别只看进程在不在

下载与你的系统架构匹配的 Thanos 官方发行版,固定版本,确认 thanos --version 后再启动 Sidecar。示例命令如下:

thanos sidecar \
  --tsdb.path=/var/lib/prometheus \
  --prometheus.url=http://127.0.0.1:9090 \
  --objstore.config-file=/etc/thanos/bucket.yml \
  --http-address=127.0.0.1:10902 \
  --grpc-address=127.0.0.1:10901

这里假设 Sidecar 与 Prometheus 在同一台机器上。--tsdb.path 必须指向同一个 Prometheus 数据目录;服务账号还要有合适的目录权限,Sidecar 需要维护自己的上传状态文件。生产环境用 systemd 或现有编排平台托管,不要靠一个 SSH 窗口长期挂着。

启动后,我会按这个顺序看:

  1. Sidecar 日志里能否连接 Prometheus、读到外部标签;
  2. 是否出现 S3 认证、区域、端点或网络错误;
  3. Prometheus 数据目录里是否已经产生完整的 TSDB block;
  4. 第一个新 block 形成后,Sidecar 是否记录上传成功;
  5. S3 桶里是否出现以 block ID 命名的目录及其 meta.json、index、chunks 等内容。

也可以用 Thanos 自带工具列出桶中的 block:

thanos tools bucket ls \
  --objstore.config-file=/etc/thanos/bucket.yml

一台全新启动的 Prometheus,刚过几分钟时没有 block 可上传,先别把“桶还是空的”当故障。反过来,桶里出现一个目录也不代表持续备份正常。我会继续观察下一轮 block,确认上传不是只成功了一次,并监控 Sidecar 最近一次成功上传的时间与错误日志。

还有一种情况容易漏:Prometheus 已经运行很久,目录里有大量过去压缩过的历史 block。Sidecar 默认上传未压缩的 block,旧历史不一定会自动全进 S3。Thanos 提供一次性迁移用的 --shipper.upload-compacted,但它需要在关闭 Prometheus 本地压缩的前提下使用;现有数据量大时,应先评估时间、重复和重叠风险,再按官方流程迁移,不能在生产上随手加个参数碰碰运气。

S3 有数据了,还要安排 Compactor

只让 Sidecar 不断上传,S3 中的小 block 会越来越多。Thanos Compactor 负责压缩、降采样,也负责按策略处理对象存储中的数据保留期。示例启动方式:

thanos compact \
  --data-dir=/var/lib/thanos/compact \
  --objstore.config-file=/etc/thanos/bucket.yml \
  --wait \
  --http-address=127.0.0.1:10903

Compactor 要有可用的本地工作磁盘,它会下载 block、处理后再上传。更要紧的是:同一条 block 数据流不能同时让多个 Compactor 随意处理。 官方文档要求按单实例原则部署,扩容也要先做好明确的分片规划。

默认情况下,Thanos 对对象存储中的数据不设置过期时间。这是符合“长期留存”目标的,但 S3 账单会持续增长。要设保留期,应评估原始数据、5 分钟降采样数据和 1 小时降采样数据分别保留多久,再用 Compactor 的 --retention.resolution-* 参数管理。

别直接给桶配置一条“对象超过 90 天就删除”的通用 S3 生命周期规则。一个 TSDB block 是多文件组成的,按单个对象年龄删文件,可能留下不完整的 block。涉及删除和保留期时,先按 Thanos 的 block 生命周期设计,再安排独立的备份保护策略。

真正的验收,是从 S3 把历史数据查出来

这是我认为整套方案里最不能省的一步。上传成功是写入验收,历史查询成功才开始证明数据可用。

Thanos Store Gateway 负责读取 S3 中的历史 block,Thanos Query 提供兼容 Prometheus 的查询入口。可以在受控测试环境启动:

thanos store \
  --data-dir=/var/lib/thanos/store \
  --objstore.config-file=/etc/thanos/bucket.yml \
  --grpc-address=127.0.0.1:10911 \
  --http-address=127.0.0.1:10912

再让 Query 只连接这个 Store Gateway:

thanos query \
  --endpoint=127.0.0.1:10911 \
  --http-address=127.0.0.1:10904

选择一个已上传 block 覆盖的历史时间点,通过 Query 的 Prometheus API 查询一条已知指标,对照原 Prometheus 当时的值。这里只连 Store Gateway,是为了确认结果来自 S3,而不是不小心又从正在运行的 Prometheus 读到了本地数据。

这还不是“整机灾难恢复演练”。Thanos 保存的是指标 block,不会替你备份 Prometheus 配置、抓取目标、告警规则、Grafana 仪表盘,更不会实时保存尚未形成 block 的 WAL。真正要回答“Prometheus 那台机器没了能否恢复业务监控”,还得把配置备份、S3 保护、重建步骤和查询验证一起演练。

写到这里,我对这套方案的判断很简单:Sidecar 负责把历史 block 送上 S3;持久磁盘守住最近一段尚未上传的数据;Compactor 管长期数据;Store Gateway 和 Query 负责证明历史数据读得回来。 少了最后的验证,“备份成功”四个字还是说得太早。

如果你正在给 Prometheus 做长期留存,建议先拿一套非核心实例走通上传、查询和恢复验证,再逐步接入生产。文章对你有帮助,欢迎点赞、转发给正在维护监控平台的同事,也欢迎关注 @运维躬行录。后面我会继续写监控存储、告警和故障排查里那些容易被忽略的细节。

公众号:耕云躬行录
个人博客:躬行笔记

参考文档:Thanos Sidecar · Thanos 对象存储配置 · Thanos Compactor · Thanos Store Gateway · Thanos Query

文章目录

博主介绍

热爱技术的云计算运维工程师,Python全栈工程师,分享开发经验与生活感悟。
欢迎关注我的微信公众号@运维躬行录,领取海量学习资料

微信二维码