用Terraform部署NewRelic

323 阅读4分钟

NewRelic与Terraform的部署

NewRelic是一个强大而流行的基于云的平台,它可以帮助用户通过预先建立的仪表盘和分析模型来监控其服务的性能。不幸的是,通过控制台管理多个项目的NewRelic资源是非常耗时的。

在这篇文章中,我将介绍一种基础设施即代码(IaC) 的方法,它使用Terraform代码来管理NewRelic仪表盘和警报。更具体地说,我将用Terraform的HashiCorp配置语言(HCL)定义所有的NewRelic资源,然后使用Terraform命令来配置或更新NewRelic。我将介绍一个例子,创建一个仪表盘,监控三个AWS lambdas的调用次数、响应时间和错误率。我还会让NewRelic发送一个电子邮件提醒。

1.开始使用

1.1 通过API keys UI创建用户密钥

首先,我们将得到一个用于访问REST API端点的密钥,以及NewRelic账户ID。这些都可以从NewRelic UI中获得。

在这种情况下,你可以看到密钥值以 "NRAK-"开头。为了保护隐私,我隐藏了密钥的其余部分,以及账户ID,但你可以用你自己的来代替。

1.2 通过Terraform定义NewRelic资源

1.2.1 定义NewRelic提供者

接下来我们要用用户密钥和账户ID来配置Terraform。

terraform {
  # Require Terraform version 0.13.x (recommended)
  required_version = "~> 0.13.0"

  # Require the latest 2.x version of the New Relic provider
  required_providers {
    newrelic = {
      source  = "newrelic/newrelic"
      version = "~> 2.21"
    }
  }
}

provider "newrelic" {
  account_id = <NewRelic Account ID>
  api_key = <NewRelic User Key>
  region = "US"
}

其中<NewRelic Account ID><NewRelic User Key> 是我们在上一步中获得的值。

1.2.2 定义NewRelic仪表板

现在我们将实际设置仪表板,它被命名为demo-dev 。三个lambdas被命名为demo-identity-dev,demo-webhook-devdemo-invalidate-dev 。前缀 "demo"是这个例子中特有的命名空间标识符。

我们将假设这些lambda函数已经在AWS中配置好了,并且正确地配置为向NewRelic发布数据(参见NewReliclambda instrumentation setupdocumentation以了解更多信息)。

下一步,我们将使用Terraform动态块,这是一种创建资源和查询的便捷方式,具有特定的命名惯例。在这个块中,我们将使用NewRelic的网格系统--它有12列宽--来并排布置三个NewRelic仪表盘部件。

resource "newrelic_one_dashboard" "service_dashboard" {
    name = "demo-dev"
    dynamic page {
        for_each = ["identity", "webhook", "invalidate"]

        content {
            name = page.value

            widget_markdown {
                title = "${page.value} API"
                text = "# ${page.value} API"
                row = 1
                column = 1
                width = 12
                height = 1
            }

            widget_line {
                title = "Total API Invocations [${page.value}]"
                row = 2
                column = 1
                width = 4

                nrql_query {
                    query       = "SELECT count(*) as 'Invocations' FROM AwsLambdaInvocation WHERE (entityName = 'demo-${page.value}-dev') SINCE 1 DAYS AGO TIMESERIES EXTRAPOLATE"
                }
            }

            widget_billboard {
                title = "Lambda response time (percentile) [${page.value}]"
                row = 2
                column = 5
                width = 4

                nrql_query {
                    query       = "SELECT percentile(cwDuration, 50) as 'ms (p50)', percentile(cwDuration, 90) as 'ms (p90)', percentile(cwDuration, 99) as 'ms (p99)' FROM AwsLambdaInvocation WHERE (entityName = 'demo-${page.value}-dev') SINCE 1 DAYS AGO"
                }
            }

            widget_line {
                title = "Call Error (percentage) [${page.value}]"
                row = 2
                column = 9
                width = 4
                height = 3

                nrql_query {
                    query       = "SELECT percentage(count(*), WHERE error IS true) as 'Error rate (%)' FROM AwsLambdaInvocation WHERE (entityName = 'demo-${page.value}-dev') SINCE 1 DAYS AGO TIMESERIES EXTRAPOLATE"
                }
            }
        }
    }
}

下面是生成的仪表盘,我在上面画了一个网格列和行的大致轮廓。

你可以看到第一行是仪表盘的标题,第二行被分成三个部分,每个部分有四个单元格宽,包含一个单独的部件。

1.2.3 定义NewRelic警报和通知通道

接下来,我们将转到警报上。为了使警报正常工作,我们需要设置一个NewRelic策略、警报通道和警报条件。策略承载了所有相关的警报条件。在这种情况下,我们将使用资源的for_each 参数,为每个lambda函数中出现的任何错误尖峰创建警报。

resource "newrelic_alert_policy" "service_alert_policy" {
  name = "demo-dev"
}

# Creates an email alert channel.
resource "newrelic_alert_channel" "email_channel" {
  name = "email-demo-dev@test.com"
  type = "email"

  config {
    recipients              = <notification email address>
    include_json_attachment = "1"
  }
}

resource "newrelic_alert_policy_channel" "service_alert_policy_channel" {
  policy_id   = newrelic_alert_policy.service_alert_policy.id
  channel_ids = [newrelic_alert_channel.email_channel.id]
}

resource "newrelic_nrql_alert_condition" "service_alert_error_rate" {
  for_each = toset(["identity", "webhook", "invalidate"])

  policy_id                    = newrelic_alert_policy.service_alert_policy.id
  type                         = "static"
  name                         = "${each.value} Error Spike [dev]"
  description                  = "Alert ${each.value} lambda function errors [dev]"
  enabled                      = true
  value_function               = "sum"
  violation_time_limit_seconds = 3600

  fill_option          = "static"
  fill_value           = 0

  critical {
    operator              = "above"
    threshold             = 5
    threshold_duration    = 900
    threshold_occurrences = "AT_LEAST_ONCE"
  }

  nrql {
    query             = "SELECT count(*) FROM AwsLambdaInvocationError WHERE (entityName = 'demo-${each.value}-dev') EXTRAPOLATE"
    evaluation_offset = 3
  }
} 

1.3 通过Terraform命令提供

在创建terraform资源定义文件后,我们可以运行 [terraform init](https://www.terraform.io/docs/cli/commands/init.html), [terraform plan](https://www.terraform.io/docs/cli/commands/plan.html)[terraform apply](https://www.terraform.io/docs/cli/commands/apply.html)的顺序来配置或更新NewRelic中的资源。这个过程的输出在NewRelic控制台会是这样的。

我已经强调了确认我们使用正确的用户密钥的部分。

2 结论

在这篇文章中,我介绍了一种通过Terraform设置NewRelic监控资源的有效方法。这种IaC技术是向部署应用基础设施迈出的又一步,无需人工干预。此外,它是代码的事实意味着变化可以与底层应用程序的版本保持同步。不幸的是,Terraform不支持对NewRelic资源的引用(例如,在使用AWS资源时,这些资源可能非常有用)。尽管如此,Terraform已经被证明是自动配置我们的监控和警报基础设施的一个伟大工具。