亚马逊AWS官方博客

使用 Thanos 扩展 Prometheus 高可用监控架构

架构描述

Prometheus 是一款开源的监控和报警工具,专为容器化和云原生架构的设计,提供性能指标采集、储存时序数据和功能强大的查询语言 PromQL,并可视化呈现监控指标与生成报警信息。客户普遍采用其用于 Kubernetes 的监控体系建设。Amazon 也在 2021 年 9 月正式发布了托管的 Prometheus 服务(Amazon Managed Service for Prometheus – AMP)简化客户部署和使用。并且在 2023 年 11 月针对 EKS 发布了托管的 Prometheus 服务的无代理采集功能(新闻稿),进一步方便客户无需提前规划,从而可以开箱即用的使用 Prometheus 的相关组件。

截止本文发布之日,在亚马逊云科技中国区域暂时没有发布托管的 Prometheus 服务。因此针对中国客户,部署 Prometheus 监控平台的最佳实践指导可以帮助客户快速使用 Prometheus,从而将精力专注于业务需求。

独立的 Kubernetes 集群通常使用 Prometheus Operator 部署所有相关组件(包括 Alert Manager、Grafana 等)。这种独立部署的监控架构优点是部署方便,数据持久化使用 EBS 也可以满足大部分场景下查询性能的要求。但缺点也显而易见,即考虑到 EBS 成本,无法保存长时间的历史数据。而且当客户环境中集群数量较多,对监控平台自身的可用性和可靠性要求较高,同时希望提供全局查询时,基于多个 Prometheus 数据源的报表开发管理和维护的工作量也随之增加。

Thanos 是一套开源组件,构建在 Prometheus 之上,用以解决 Prometheus 在多集群环境下的高可用性、可扩展性限制。针对历史性能数据分析,或者使用 Prometheus 进行成本分析的场景都会依赖于较长时间的历史数据。Thanos 主要通过接收并存储 Prometheus 的多集群数据副本,并提供单一数据源供全局查询和一致性数据访问接口的方式,实现了对于 Prometheus 的可靠性、一致性和可用性保障,从而解决了 Prometheus 单集群在存储、查询历史数据和备份等方面的扩展性挑战。

在讨论基于 Thanos 的各种 Prometheus 监控架构之前,我们先了解下 Thanos 及其常用的组件,更多详细信息可以参考 thanos.io

  • Sidecar(边车):运行在 Prometheus 的 Pod 中,读取其数据以供查询并上传到对象存储(例如:AWS S3)。
  • Store(存储网关):用于从对象存储上查询数据。
  • Compactor(压缩器):对存储在对象存储中的数据进行压缩、聚合历史数据以减小采样精度以便长久保留。
  • Receiver(接收器):接收来自 Prometheus 远程写入日志的数据,并将其上传到对象存储。
  • Ruler(规则器):针对 Thanos 中的数据评估记录和警报规则。
  • Query(查询器):实现 Prometheus 的 v1 API,查询并汇总来自底层组件的数据。将所有数据源添加为 Query 的 Endpoint,包括 Sidecar、 Store、 Receiver 等。
  • Query Frontend(查询前端):实现 Prometheus 的 v1 API,将其代理给查询器,同时缓存响应,并可以拆分查询以提高性能。

第一种监控架构:

  • 被监控集群(Observee)部署 Prometheus 且启用 Thanos 的 Sidecar 方式将监控的历史数据定期归档到 S3,通过部署 Thanos Store 组件查询历史数据;
  • 集中监控集群(Observer)除了部署 Thanos 组件之外,将统一部署 Grafana 作为 Dashboard 展示。

第二种监控架构:

  • 被监控集群(Observee)除了启用 Thanos Sidecar 之外,还启用了 Prometheus 的 Remote Write 功能,将未归档的数据以 WAL 方式远程传输到部署在集中监控集群(Observer)上的 Thanos Receiver,以保证数据的冗余度。 Thanos Receiver 同样可以将历史监控数据归档到 S3 上,且支持被 Thanos Query 直接查询,同时避免直接查询 Sidecar 而给被监控集群带来额外的性能损耗。

第三种监控架构:

  • 在多集群监控场景下,一般会在每个被监控集群(Observee)部署独立的 Prometheus 组件。Prometheus 提供 Agent Mode 针对这样的场景可以最小化资源占用,直接启用 Remote Write 功能将监控数据集中保存,且可以使用除 Stateful 之外的其他 Deployment,本地存储需求低(除非远程 Endpoint 不可用时,本地缓存数据以重试)。
  • 针对此类架构另一个可选方案是使用 AWS Distro for OpenTelemetry(ADOT),参见博客

第四种监控架构:

  • 在已经发布了托管的 Prometheus 服务的 AWS 区域,直接使用 AMP 作为集中监控数据持久化,提供最好的性能和最低的维护成本(参考文档)。每个被监控集群可以使用无代理采集功能(新闻稿),进一步方便客户无需提前规划,从而可以开箱即用的使用 Prometheus 的相关组件。

以下总结了各种 Prometheus 监控架构所适合的场景:

优点 缺点 适用场景
第一种监控架构 架构简单只有一份监控数据,最小化存储成本和其他资源开销 通过 Sidecar 查询实时监控数据时,将给被监控集群带来额外性能损耗 适合绝大部分生产环境,尤其在亚马逊中国区域没有托管 Prometheus 服务,此类架构是客户首选。
第二种监控架构 直接从 Thanos Receiver 查询实时性能数据,对被监控集群没有额外性能损耗 架构复杂,每个集群对应一组 Thanos Receiver,建议配置副本数量和资源等与源集群的 Prometheus 副本数量和资源相同监控数据冗余,可以使用 Compactor 对数据进行压缩、聚合历史数据以减少存储成本 在 Thanos 0.19 版本之前,Sidecar 还没有实现 StoreAPI 时,只能通过 Receiver 查询最新的性能数据。适合需要多副本监控数据的特殊场景。
第三种监控架构 架构简单,使用 Agent Mode 几乎无状态 某些组件将无法在 Agent Mode 下启用,例如:Sidecar、Alert、Rules (参见文档 最大程度减少对于被监控集群的资源占用,可以使用 Prometheus 的 Agent Mode,另一个可选方案是使用 AWS Distro for OpenTelemetry(ADOT)。
第四种监控架构 架构简单,资源占用少免维护 托管 Prometheus 服务的成本计算,参考文档 在支持托管 Prometheus 服务的亚马逊区域文档可以直接使用,实现完全开箱即用,同时避免管理 Thanos 组件,只需要部署 Grafana 即可。

部署步骤

本实验包含前三种监控架构的部署,读者可以有选择的进行验证。按照之前架构图中标明的集群编号:

  • ekscluster1 对应第一种监控架构,通过 Terraform 脚本中同名目录创建。作为集中监控集群,所有的 Thanos 组件也将部署在该集群中;
  • ekscluster2 对应第二种监控架构,通过 Terraform 脚本中同名目录创建。作为被监控集群,读者可以按需创建。
  • ekscluster3 对应第三种监控架构,通过 Terraform 脚本中同名目录创建。作为被监控集群,读者可以按需创建。

Prometheus Operator 提供 Kubernetes 原生部署和管理 Prometheus 及相关监控组件的功能。该项目的目的是简化和自动配置 Kubernetes 集群基于 Prometheus 的监控堆栈。本实验基于 Prometheus Operator 部署作为基础,并通过 values.yaml 参数文件定制。 同样 Thanos 的组件采用了 Bitnami Thanos Chart 部署,并通过 values.yaml 参数文件定制。本实验中将使用 Terraform 自动创建资源,包括所需要的 IAM role 等对象,在部署之前确保运行 Terraform 有足够权限创建相关资源。

  1. 本实验中使用了预设的子域名用于简化服务之间的访问和对外暴露。需要提前在 Route53 中创建该子域名(复制链接中的函数并粘贴到命令行)。
    PARENT_DOMAIN_NAME=eks0103.aws.panlm.xyz
    create-hosted-zone -n ${PARENT_DOMAIN_NAME}
    
  2. 然后在上游 Route53 中创建对应的 NS 记录(复制链接中的函数并粘贴到命令行),确保有上游 Route53 相应的权限。
    PARENT_DOMAIN_NAME=eks0103.aws.panlm.xyz
    NS="copy NS records from previous output and paste here"
    create-ns-record -n $PARENT_DOMAIN_NAME -s "$NS" # double quote is mandortory
    
  3. 创建本实验的目录,后续将在此路径下克隆 2 个 REPO,分别用于创建 EKS 集群的 Terraform 代码和 Thanos 配置示例。
    LAB_HOME=~/environment/lab-thanos
    mkdir -p ${LAB_HOME}
    
  4. 先获取 Thanos 配置模板,Thanos 相关组件通过 Terraform 自动化部署在被监控集群(ekscluster1),目录说明如下:
    • prometheus:包含针对 Prometheus Operator 的定制 Values;
    • s3-config:提供 Thanos 组件访问 S3 的相关配置信息,这些配置将会被创建成 Kubernetes 的 Secret;
    • thanos-values:包含针对 Bitnami Thanos Chart 的定制 Values;
    • thanos-yaml:包含自建 Thanos 使用的相关 Yaml 定义文件。我们将在下一章节展开描述。
      cd ${LAB_HOME}
      git clone https://github.com/panlm/thanos-example.git
      cd thanos-example
      
  5. 使用下面参数进行创建本实验使用的配置文件,位于 POC 目录下。子域名thanos 对应下一步中的 environment_name
    CLUSTER_NAME_1=ekscluster1
    CLUSTER_NAME_2=ekscluster2
    CLUSTER_NAME_3=ekscluster3
    ENVIRONMENT_NAME=thanos
    DOMAIN_NAME=${ENVIRONMENT_NAME}.${PARENT_DOMAIN_NAME} # this domain will be created by terraform
    THANOS_BUCKET_NAME=thanos-store-$(TZ=EAT-8 date +%Y%m%d-%H%M%S)
    AWS_DEFAULT_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
    export CLUSTER_NAME_1 CLUSTER_NAME_2 CLUSTER_NAME_3 DOMAIN_NAME THANOS_BUCKET_NAME AWS_DEFAULT_REGION
    
    aws s3 mb s3://${THANOS_BUCKET_NAME}
    
    mkdir POC
    cd POC-template
    find ./ -type d -name "[a-z]*" -exec mkdir ../POC/{} \;
    
    find ./ -type f -name "*" |while read filename ; do
      cat $filename |envsubst '$CLUSTER_NAME_1 $CLUSTER_NAME_2 $CLUSTER_NAME_3 $DOMAIN_NAME $THANOS_BUCKET_NAME $AWS_DEFAULT_REGION' > ../POC/$filename
    done
    
  6. 获取 Terraform 代码开始创建环境。Terraform 先创建实验使用的专用网络环境,然后在专用网络环境中创建 EKS 集群,随后判断 POC 路径下存在相关 Prometheus 定制 Values 文件和 Thanos 定制 Value 文件,并通过 Helm 进行部署。目录说明如下:
    • environment 目录:创建实验公用的 VPC 等资源;
    • ekscluster1 目录:创建目录同名 EKS 集群,对应第一种监控架构图中所有组件;
    • ekscluster2 目录:创建目录同名 EKS 集群,对应第二种监控架构图中红色集群及组件(可选);
    • ekscluster3 目录:创建目录同名 EKS 集群,对应第三种监控架构图中黄色集群及组件(可选)。
      cd ${LAB_HOME}
      git clone https://github.com/panlm/eks-blueprints-clusters.git
      cd eks-blueprints-clusters/multi-cluster-thanos
      
  7. 修改 terraform.tfvars 配置如下:
    aws_region          = "us-east-2"
    environment_name    = "thanos" # sub-domain will be created by terraform
    cluster_version     = "1.27"
    hosted_zone_name    = "eks0103.aws.panlm.xyz" # your existing hosted zone
    eks_admin_role_name = "" # Additional role admin in the cluster 
    
  8. 创建独立的环境用于本实验,包括 VPC,Secret,环境特定的子域名等。
    cd environment
    terraform init
    terraform apply -auto-approve
    
  9. 创建集群 ekscluster1(目录名即为 EKS 集群名),并根据命令行输出保存 kubeconfig 配置。创建集群后将自动检查 thanos-example/POC 路径下相关文件存在,安装 Prometheus 和 Thanos 组件。
    cd ../ekscluster1
    terraform init
    terraform apply -auto-approve
    
  10. 按照第9步操作分别进入其他两个目录创建 ekscluster2 和 ekscluster3,对应另外第二、三种监控架构。操作可以通过其他命令行窗口同时进行。

Thanos 相关配置

方便大家了解 Thanos 的配置和工作原理,简要说明下 thanos-example/thanos-yaml 目录下的相关配置,方便按需修改并重用。更多参考 Github

Store

Thanos Store 组件将用于访问对象存储桶中的历史数据,每个 Store 对应一个被监控集群。它主要充当 API 网关,因此不需要大量本地磁盘空间。它在启动时加入 Thanos 集群,并公布它可以访问的数据。它在本地磁盘上保留了少量关于所有远程块的信息,并与存储桶保持同步。一般来说,这些数据可以在重启时安全删除,但代价是启动时间增加。

  • 例如,在 thanos-store-cluster1-statefulSet.yaml 中,指定了已有的 Secret 文件
            - name: OBJSTORE_CONFIG
              valueFrom:
                secretKeyRef:
                  name: thanos-s3-config-ekscluster1
                  key: objstore.yml
    
  • 相应的 Secret 文件会包含以下参数,指定历史数据在对象存储桶中的位置
    type: S3
    prefix: "ekscluster1"
    config:
        bucket: "thanos-store-name"
        endpoint: "s3.us-east-2.amazonaws.com"
        region: "us-east-2"
        sts_endpoint: "https://sts.amazonaws.com"
    

Query 和 Query Frontend

Query Frontend 组件对外提供与 Prometheus 兼容的 API,可以直接作为 Prometheus 类型的数据源添加到 Grafana 中;Query 组件是无状态且可以横向扩展,对外提供 Prometheus 兼容的 API 供外部工具查询,例如 Grafana,本实验中 Query Frontend 实现将查询分片(Split),使用 Query 组件提供查询的横向扩展能力。

  • query-frontend-deployment 文件中指定了如下分割查询的参数(默认值 24 小时),将一个跨度较大的查询分割成跨度较短的查询,除了能更好的利用 Query 组件的横向扩展实现并行查询 之外,也能防止较大的查询引发 Query 组件出现内存不足(OOM)的问题。
            - --query-range.split-interval=4h
            - --labels.split-interval=4h
    
  • 对外域名定义在 query-frontend-service 文件中,可以通过浏览器访问,直接执行 PromSQL。
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-type: "external"
        service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
        external-dns.alpha.kubernetes.io/hostname: thanos-query-frontend.yourdomainname
    
  • query-deployment文件中指定了 Query 组件查询目标端点,包括 Sidecar,Receiver,Store 等,除了 Sidecar,需要跨集群访问,本实验中使用了定制域名之外,其他组件均部署在集中监控集群上,因此可以直接使用 kubernetes 资源命名规范直接访问。
            # for store
            - --endpoint=dnssrv+_grpc._tcp.thanos-store-cluster1.thanos.svc.cluster.local
            - --endpoint=dnssrv+_grpc._tcp.thanos-store-cluster2.thanos.svc.cluster.local
            - --endpoint=dnssrv+_grpc._tcp.thanos-store-cluster3.thanos.svc.cluster.local
            # for sidecar
            - --endpoint=thanos-sidecar-ekscluster1.thanos.yourdomainname:10901
            - --endpoint=thanos-sidecar-ekscluster2.thanos.yourdomainname:10901
            # - --endpoint=thanos-sidecar-${CLUSTER_NAME_1}.${DOMAIN_NAME}:10901
            # for receive
            - --endpoint=dnssrv+_grpc._tcp.thanos-receive-cluster2.thanos.svc.cluster.local
            - --endpoint=dnssrv+_grpc._tcp.thanos-receive-cluster3.thanos.svc.cluster.local
    

Receiver

  • 部署独立的 Thanos Receiver 组件,分别对应 ekscluster2 和 ekscluster3。建议分配 Receiver 组件的资源和数量需要和被监控集群中 Prometheus 采集组件的资源和数量相当。
  • 同样在 Receiver 的配置中会指定对象存储桶的配置,在收到远程集群的 Remote Write 数据之后,Receiver 会保存数据到对象存储桶中,且使用自己的标签组以区分数据。
            - --label=replica="$(NAME)"
            - --label=receive="true"
            - --label=cluster="ekscluster2"
            - --label=cluster_name="ekscluster2"
            - --label=origin_prometheus="ekscluster2"

定制 Grafana

使用 Prometheus Operator 部署 Grafana 会自带一些常用的 Dashboard,我们可以进行简单配置实现多集群数据查询。

查看多集群 Dashboard

  • 访问 Grafana 服务,域名可以通过 thanos-example/POC/prometheus/values-ekscluster1-1.yaml 查看
    • 本实验部署成功后 Grafana URL为: http://grafana.thanos.eks0103.aws.panlm.xyz/
  • 修改 Grafana 默认用户名密码 admin/prom-operator
  • 添加 Thanos Query Frontend 作为 Prometheus  类型的数据源
    • 左上角依次选择 Menu – Connections – Data Sources – Add New Data Source
    • 选择 Prometheus 类型的数据源
      • 名称字段填 thanoslab,并设置为默认
      • Prometheus server URL 字段填入 Kubernetes 内部域名:http://thanoslab-query-frontend.thanos.svc.cluster.local:9090   (或者上文提到的 Query Frontend Service 绑定的域名访问)
      • 保存并测试,显示查询成功后即可开始使用
    • 查看预置的 Dashboard:Kubernetes / Compute Resources / Multi-Cluster

查看其他 Dashboard

通过简单修改即可将其他预置 dashboard 修改为支持多集群查询:

  • 打开预置的 Dashboard:Kubernetes / Compute Resources / Namespace (Pods)
  • 点击齿轮图标进入 Dashboard Settings 界面
  • 在 Variable 中找到 cluster 变量,按照下面截图修改
    • Show on dashboard 设置为 Label and value
    • Data source 设置为 thanoslab
  • 点击 Apply 保存变量修改
  • 点击 Save As 保存 Dashboard 即可

查看 Thanos Query Frontend 数据源接口

  • 访问 Query Frontend 服务,域名可以通过 thanos-example/POC/thanos-values/thanoslab-query.yaml 查看
    • 本实验部署成功后 Query Frontend URL 为:http://thanoslab-query-frontend.thanos.eks0103.aws.panlm.xyz:9090/
  • 在 Query Frontend 的 Stores 页面可以查看到所有 Endpoint 状态
    • Receiver 表中,Min Time 有值表示 Prometheus 使用 Remote Write 将数据写入 Receiver 成功
    • Prometheus 中收到性能指标数据以 WAL 形式保存在内存并持久化到磁盘,启用 Sidecar 后,自动将 min-block-durationmax-block-duration 设置成 2小时且无法更改,即每个数据块文件保存2小时的性能指标。同时 Prometheus 设置 retention 时间和 retentionSize 大小,未到 retention 前,Sidecar 表中,Min Time 将显示为 -,到 retention 后,数据由 Sidecar 写入 S3,此时会显示最早数据的时间戳
    • Store 表中,Min Time 有值表示数据被写入 S3,且显示最早数据的时间戳
  • 数据通过 Label 标注来源的集群名称以及采集数据的 Pod 名称
  • 本实验在 Prometheus 中设置了 3 个额外的 ExternalLabel,包括 clustercluster_nameorigin_prometheus

清理环境

  • 按照下面步骤清理集群相关内容
    cd ${LAB_HOME}
    cd eks-blueprints-clusters/multi-cluster-thanos
    for i in ekscluster1 ekscluster2 ekscluster3 ; do
      cd $i
      ../tear-down.sh 
      cd ..
      sh tear-down-ebs-$i.sh 
    done
    

结论

Prometheus 是一款开源的监控和报警工具,专为容器化和云原生架构的设计。客户普遍采用其用于 Kubernetes 的监控体系建设。Thanos 是一套开源组件,构建在 Prometheus 之上,用以解决 Prometheus 在多集群大规模环境下的高可用性、可扩展性限制。当需要做历史性能数据分析,或者使用 Prometheus 进行成本分析的场景都会依赖于较长时间的历史数据。Thanos 主要通过接收并存储 Prometheus 的多集群数据副本,并提供全局查询和一致性数据访问接口的方式,实现了对于 Prometheus 的可靠性、一致性和可用性保障,从而解决了 Prometheus 单集群在存储、查询历史数据和备份等方面的扩展性挑战。

在亚马逊中国区域没有托管 Prometheus 服务,第一种监控架构是客户首选;在支持托管 Prometheus 服务的亚马逊区域建议直接使用托管服务,避免投入额外的管理成本。

参考链接

本篇作者

潘雷鸣

亚马逊云科技解决方案架构师。负责基于云计算方案架构的咨询和设计,同时致力于容器相关服务在国内的应用和推广。在加入亚马逊云科技之前,拥有多年外企售前经验,在传统网络架构的性能和安全方面有丰富的实践经验。

肖冰

亚马逊云科技解决方案架构师,负责基于 AWS 的云计算方案的咨询与架构设计。在应用现代化改造,Serverless,云迁移,大数据等方向具有丰富的实践经验。在加入 AWS 之前,曾就职于 EMC、微软,西云数据、腾讯等科技公司,拥有丰富的公有云领域的架构优化和技术支持经验。