亚马逊AWS官方博客

基于 Grafana 实现云资源成本及使用量的可视化分析

前言

上云对于很多用户来讲已经不再是技术远景或者趋势,而是成为必不可少的战略选择。随着应用及其它负载不断迁移到云上,业务的增长和拓展带来云上成本支出的增长,如何有效的跟踪、分析和管理云上成本越来越重要。

亚马逊云科技提供了多个服务帮助用户可视化管理云上支出,例如 Amazon Cost Explorer、Amazon Budgets 等。同时,Cost and Usage Report(CUR)报告可提供按天甚至按小时的云上资源的支出和使用数据。在本篇博客中,我们将演示如何使用 CUR,结合 Amazon Athena 和开源版 Grafana 搭建定制化的仪表盘,可视化地展示成本支出。

基于 CUR,可以定制化不同的仪表盘来为客户提供不同视角的成本可视化信息。例如,客户 CFO 更关注成本支出趋势,适合构建全局的汇聚分析仪表盘;客户研发或运维部门,需要了解细颗粒度的具体服务支出,是否有未充分利用的资源,按自定义标签维度(如部门、项目)来查看成本使用情况,适合构建更细化的仪表盘,通过可视化分析来确认成本优化的方向。

架构图

下图展示了基于 CUR 报告数据,以及结合 Grafana 构建成本及用量可视化的整体架构。按天或按小时来创建 CUR 报告并存放在 Amazon S3 存储桶中,通过 Amazon Athena 来分析和查询 CUR,并在 Grafana 中进行可视化呈现。

Amazon Athena 是一种交互式查询服务,让您可以轻松使用标准 SQL 语言来分析 Amazon S3 中的数据。Amazon Athena 属于无服务器服务,因此不需要管理基础设施,且您仅需为您运行的查询付费。

Grafana 是一个开源的测量数据分析和可视化工具,用于查询并可视化展示采集的数据。Grafana 提供了丰富的可视化展示方式,通过面板来展示可视化指标,拥有丰富的仪表盘插件,帮助我们快速的搭建动态更新的仪表盘。

安装 Grafana

安装 Grafana 可以参考以下文档:

https://grafana.com/docs/grafana/latest/setup-grafana/installation/

在 Amazon EC2 上安装 Grafana 的步骤如下:

1. 为操作系统添加 Grafana 的 yum 仓库

sudo nano /etc/yum.repos.d/grafana.repo

2. 在 grafana.repo 文件中填入下面的内容

[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt

3. 安装开源版的 Grafana

sudo yum install grafana

4. 启动 Grafana 服务

sudo systemctl start grafana-server

5. 检查 Grafana 服务状态

sudo systemctl status grafana-server

6. 运行如下命令确保 Grafana 服务开机自启动

sudo systemctl enable grafana-server.service

7. 访问 http://{Amazon EC2 IP}:3000 验证 Grafana 是否安装成功

安装 Amazon Athena 插件

通过 Grafana GUI 界面安装

在 Grafana Configuration 中选择插件 Plugins,搜索 Amazon 或 Athena,选择 Amazon Athena 安装即可。

通过命令行安装

参考 Grafana 文档安装 Amazon Athena 插件:https://grafana.com/grafana/plugins/grafana-athena-datasource/

登录 Grafana 服务所在的 Amazon EC2 运行安装 Amazon Athena 插件命令,然后重启 Grafana 服务。

sudo grafana-cli plugins install grafana-athena-datasource
sudo systemctl restart grafana-server

打开 Grafana plug-in 面板,验证 Amazon Athena 插件是否安装成功。

创建和设置成本和使用情况报告 Cost and Usage Reports (CUR)

创建一个新的 Amazon S3 存储桶 demo-cur-report 来存储 CUR 数据,并按照截图的配置创建 CUR,预计 24 小时之内,第一份报表数据将会同步到 Amazon S3 存储桶。


为了简化和自动化 Amazon Athena 的配置,当 CUR 数据第一次同步到 Amazon S3 存储桶 demo-cur-report 后,会生成一份 CloudFormation 模版,运行此 CloudFormation 模版将会自动配置 CUR 与 Amazon Athena 的集成,CloudFormation 模版的默认路径如下:

s3://demo-cur-report/grafana/demo-cur-report/crawler-cfn.yml

CloudFormation 运行成功后,登录 Amazon Athena 控制台,可以看到新创建的 Database 和 Tables。

Amazon Athena 支持使用工作组 workgroups 来分隔用户、团队、应用程序或工作负载,对每个查询或整个工作组可以处理的数据量设置限制,并跟踪成本,本方案为 Grafana 创建专有的工作组。

首选创建一个新的 Amazon S3 存储桶 grafana-athena-query-results,然后在 Amazon Athena 的控制台创建新的工作组 grafana,选择 grafana-athena-query-results 存储桶来保存查询结果。

配置 Amazon Athena 数据源

配置 Grafana 的 Amazon Athena 数据源之前,需要为数据源创建相应的 IAM policy,以下 IAM policy 仅供参考,这里建议尽可能根据实际情况创建最小权限的 IAM policy。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AthenaQueryAccess",
            "Effect": "Allow",
            "Action": [
                "athena:ListDatabases",
                "athena:ListDataCatalogs",
                "athena:ListWorkGroups",
                "athena:GetDatabase",
                "athena:GetDataCatalog",
                "athena:GetQueryExecution",
                "athena:GetQueryResults",
                "athena:GetTableMetadata",
                "athena:GetWorkGroup",
                "athena:ListTableMetadata",
                "athena:StartQueryExecution",
                "athena:StopQueryExecution"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "GlueReadAccess",
            "Effect": "Allow",
            "Action": [
                "glue:GetDatabase",
                "glue:GetDatabases",
                "glue:GetTable",
                "glue:GetTables",
                "glue:GetPartition",
                "glue:GetPartitions",
                "glue:BatchGetPartition"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "AthenaQueryResultAccess",
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:ListMultipartUploadParts",
                "s3:AbortMultipartUpload",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws-cn:s3:::grafana-athena-query-results",
                "arn:aws-cn:s3:::grafana-athena-query-results/*"
            ]
        },
        {
            "Sid": "AthenaS3Access",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws-cn:s3:::demo-cur-report",
                "arn:aws-cn:s3:::demo-cur-report/*"
            ]
        }
    ]
}

登录 Grafana 页面,为 CUR 创建 Amazon Athena 数据源,在 Authentication Provider 选项中提供了多种验证方式,这里我们选择 SDK 模式。首先在 IAM 控制台创建一个新的服务角色如 grafana-athena-role,将上一步创建的 IAM Policy 附加到新建的服务角色中。然后登录 Amazon EC2 控制台,选择之前安装 Grafana 的 Amazon EC2 实例,再选择 Action→Security→Modify IAM Role,为 Grafana 的 Amazon EC2 实例设置新的角色。


上一步完成后,请参考如下截图配置 Amazon Athena 数据源。

Amazon Athena 数据源设置好后,可以运行以下 SQL 进行测试。

SELECT * FROM demo_cur_report LIMIT 100;

在 Grafana 中创建基于 CUR 数据源的仪表盘

CUR 提供了非常详细的账单数据,用户可以根据自身需求在 Grafana 中创建任何形式的仪表盘,此外 Amazon Athena 插件也提供了一个默认的仪表盘(Athena Cost and Usage Report),用户可以在 Amazon Athena DataSources 页面进行导入。

点击 Import 按钮进行导入后,进入 Grafana 的 Dashboard 页面,就可以看到新导入的 CUR 仪表盘,此仪表盘按照月度为单位,展现了不同维度的图表。

导入自定义仪表盘

除了上述 Grafana Amazon Athena 插件内置的默认仪表盘外,我们还可以导入仪表盘。具体步骤可参照下图。

1. 在导航栏选择 Dashboards- Import

2. 导入仪表盘支持三种方式:

3. 编辑并确认仪表盘名称及 UID

这里提供我们基于 Amazon CURE 仪表盘调整适配后的仪表盘模板(https://github.com/sundamu/cure-grafana-dashboard/blob/main/dashboard/GrafanaCUREDashboard.json)。按上述步骤导入即可。仪表盘效果如下图(演示账户 CUR 部分数据为空,显示 No data 是正常的)。



CUR 报表字段的解释及自定义仪表盘

Grafana 仪表盘展示结果基于 Amazon Athena 查询,如果您熟悉 SQL 查询语句,可以进一步在标准化仪表盘基础上定制化自己的仪表盘版本。

CUR 报告一共有 150 多个字段,相关字段的说明可参考下面的字段数据字典链接。

https://docs.amazonaws.cn/cur/latest/userguide/data-dictionary.html

参考 CUR Query Library 查询库在 Grafana 仪表盘中增加展示面板,在亚马逊云科技 Well-Architected Labs 中,提供了 CUR Query Library 查询库(https://www.wellarchitectedlabs.com/cost/300_labs/300_cur_queries/),针对不同的云服务查询提供了查询参考语句。比如您通过 Reserved Instances 预留实例来节省云上使用费用(预留实例与按需定价相比,对于长期稳定的负载可以带来显著的节约),希望在仪表盘中增加您账户中 Amazon EC2 预留实例的相关信息,包括实例类型、已使用数量等,可以在 Grafana 仪表盘中新增 panel,参考 CUR Query Library 中 Amazon EC2 Reserved Instance Coverage查询语句来进行查询。

Panel 面板是 Grafana 中基本的可视化构建块,每个面板都有一个查询编辑器。通过查询编辑器对数据源进行 SQL 语句查询,然后返回对应的可视化的数据,在仪表盘中展示。

在 Grafana 仪表盘中新增 panel 面板步骤:

  1. 点击仪表盘右上角 Add panel 按钮。
  2. 选择 Add a new panel。
  3. 输入 SQL 查询命令,点击 Run query 后会在结果展示区域显示查询结果。在右侧可定义 Panel 参数,包括选择热图、折线图、图表等功能。

以新增 Amazon EC2 预留实例信息面板为例,参考 CUR Query Library 查询库,将 ${table_name}替换为实际的表名称,${date_filter} 指定为您需要的时间段即可。

SELECT 
  bill_payer_account_id,
  line_item_usage_account_id,
  DATE_FORMAT((line_item_usage_start_date),'%Y-%m-%d') AS day_line_item_usage_start_date, 
  CASE 
    WHEN line_item_line_item_type IN ('Usage') THEN 'OnDemand'
    WHEN line_item_line_item_type IN ('Fee','RIFee','DiscountedUsage') THEN 'ReservedInstance' 
  END AS case_purchase_option,
  SPLIT_PART(SPLIT_PART(reservation_reservation_a_r_n,':',6),'/',2) AS split_reservation_reservation_a_r_n,
  SPLIT_PART(line_item_usage_type ,':',2) AS split_line_item_usage_type_instance_type,
  SPLIT_PART(SPLIT_PART(line_item_usage_type ,':',2), '.', 1) AS split_line_item_usage_type_instance_family,
  CASE product_region
    WHEN NULL THEN 'Global'
    WHEN '' THEN 'Global'
    ELSE product_region
  END AS case_product_region,
  line_item_line_item_type,
  SUM(TRY_CAST(line_item_usage_amount AS DOUBLE)) AS sum_line_item_usage_amount,
  SUM(TRY_CAST(reservation_unused_quantity AS DOUBLE)) AS sum_reservation_unused_quantity,
  SUM(TRY_CAST(line_item_normalized_usage_amount AS DOUBLE)) AS sum_line_item_normalized_usage_amount,
  SUM(TRY_CAST(reservation_unused_normalized_unit_quantity AS DOUBLE)) AS sum_reservation_unused_normalized_unit_quantity,
  SUM(CAST(reservation_effective_cost AS DECIMAL(16,8))) AS sum_reservation_effective_cost,
  SUM(CAST(line_item_unblended_cost AS DECIMAL(16,8))) AS sum_line_item_unblended_cost
FROM 
  ${table_name} 
WHERE 
  ${date_filter} 
  AND product_product_name = 'Amazon Elastic Compute Cloud'
  AND line_item_operation LIKE '%RunInstance%'
  AND line_item_line_item_type IN ('Usage','Fee','RIFee','DiscountedUsage')
  AND product_product_family NOT IN ('Data Transfer')
GROUP BY 
  bill_payer_account_id,
  line_item_usage_account_id,
  DATE_FORMAT((line_item_usage_start_date),'%Y-%m-%d'),
  4, -- refers to case_purchase_option
  SPLIT_PART(SPLIT_PART(reservation_reservation_a_r_n,':',6),'/',2),
  SPLIT_PART(line_item_usage_type ,':',2),
  SPLIT_PART(SPLIT_PART(line_item_usage_type ,':',2), '.', 1),
  8, -- refers to case_product_region
  line_item_line_item_type
ORDER BY 
  day_line_item_usage_start_date,
  split_line_item_usage_type_instance_type,
  sum_line_item_unblended_cost DESC;

参考资料

关于Amazon Cost and Usage Reports:

https://docs.amazonaws.cn/en_us/cur/latest/userguide/what-is-cur.html

本篇作者

孙大木

亚马逊云科技资深解决方案架构师,负责基于 AWS 云计算方案架构的咨询和设计,在国内推广 AWS 云平台技术和各种解决方案。

彭金冬

亚马逊云科技解决方案架构师,负责电信行业客户的架构设计和技术支持。拥有超过 10 年的电信行业工作经验,目前专注于推广云原生 5G MPN 解决方案。