はじめに
この記事では全体の構成と、
実際にハマった4つのポイントを紹介します。
Google Cloudで監視を作るのが初めての人でも、
この記事の順番どおりに進めれば
同じ構成を再現できるように書いています。
全体像:監視は4つの経路でできている
[ログ] Google Cloud Logging → Google Cloud Pub/Sub → New Relic
[メトリクス] New Relic が Google Cloud のAPIを定期的に読み取る
[アラート] New Relic のNRQL条件で、しきい値を超えたら検知
[通知] New Relic のワークフロー → PagerDuty
| 経路 | 向き | Terraformの主なリソース |
|---|---|---|
| ログ | Google Cloud → New Relicへ送る | google_logging_project_sink / google_pubsub_topic |
| メトリクス | New Relicが取りに来る | google_project_iam_member / newrelic_cloud_gcp_link_account |
| アラート | New Relic内で判定 | newrelic_nrql_alert_condition |
| 通知 | New Relic → 外部 | newrelic_workflow ほか |
ログは「こちらから送る」、
メトリクスは「向こうが取りに来る」という、
向きの違いを最初に押さえておくと混乱しません。
① ログ:シンクに権限を付けないと届かない
郵便ポスト(シンク)を置いても、
配送センター(Google Cloud Pub/Sub)に
受け取りの許可を出さないと荷物は届かない、というイメージです。
Google Cloud Loggingのシンクで対象のログを絞り込み、
Google Cloud Pub/Subのトピックへ流します。
ここで必要なのが、シンク専用の書き込み用アカウント
(writer identity)に、トピックへの発行権限を付けることです。
resource "google_logging_project_sink" "to_newrelic" {
name = "${var.prefix}-sink-newrelic-01"
destination = "pubsub.googleapis.com/${google_pubsub_topic.newrelic_logs.id}"
filter = var.log_filter
unique_writer_identity = true
}
# シンクの writer identity に発行権限を付ける(これを忘れるとログが届かない)
resource "google_pubsub_topic_iam_member" "sink_publisher" {
topic = google_pubsub_topic.newrelic_logs.id
role = "roles/pubsub.publisher"
member = google_logging_project_sink.to_newrelic.writer_identity
}
トピックからNew Relicへ届ける方法は2通りあります。
| 方式 | 向いている場面 | 注意点 |
|---|---|---|
| プッシュ配信のサブスクリプション | ログ量が少ない・まず動かしたい | 設定が数行で済む |
| Google Cloud Dataflowのジョブ | ログ量が多い | ジョブの起動にライセンスキーが要る |
今回はまずプッシュ配信で動かし、
ログ量が増えたらGoogle Cloud Dataflowへ切り替える方針にしました。
なお、Google Cloud DataflowのジョブをTerraformで管理すると、
ライセンスキーがtfstateに平文で残ります。
そのためジョブの起動だけはTerraformの管理外とし、
手順書に残す運用にしました。
# 取り込み用URLが設定されたときだけ、プッシュ用サブスクリプションを作る
resource "google_pubsub_subscription" "newrelic_logs_push" {
count = var.newrelic_logs_ingest_url != "" ? 1 : 0
name = "${var.prefix}-sub-newrelic-logs-push-01"
topic = google_pubsub_topic.newrelic_logs.id
push_config {
push_endpoint = var.newrelic_logs_ingest_url
}
}
ただし、取り込み用URLにライセンスキーを含める形式の場合は、
プッシュ配信のサブスクリプションでもキーがtfstateに残ります。
tfstateの保存先は閲覧できる人を絞り、
キーを含むtfvarsはGitに含めないようにしておきましょう。
② メトリクス:New Relicに「見学パス」を渡す
工場見学の人に、見るだけのパスと、
入館手続き用のパスの2枚を渡すイメージです。
メトリクスはNew Relic側がGoogle CloudのAPIを定期的に読み取ります。
そのため、New Relicのサービスアカウントに閲覧の権限を付け、
監視対象のプロジェクトとしてNew Relicに登録します。
resource "google_project_iam_member" "newrelic_viewer" {
project = var.project_id
role = "roles/viewer"
member = "serviceAccount:${var.newrelic_gcp_service_account}"
}
resource "google_project_iam_member" "newrelic_service_usage_consumer" {
project = var.project_id
role = "roles/serviceusage.serviceUsageConsumer"
member = "serviceAccount:${var.newrelic_gcp_service_account}"
}
# New Relic側の「Add a GCP project」に相当
resource "newrelic_cloud_gcp_link_account" "this" {
name = "${var.prefix}-gcp"
project_id = var.project_id
}
Google Cloud側の権限付与と、New Relic側の登録を
同じTerraformで管理できるので、
環境を増やすときも同じコードで済みます。
③ アラート:AWSのメトリクス名はGoogle Cloudには存在しない
日本の家電のリモコンで、
海外製のテレビを操作しようとしていたような状態です。
監視項目の一覧を作る際、別案件の一覧を流用した結果、
AWS Lambdaや生成AI系サービス向けのメトリクス名が残っていました。
当然、Google Cloud Runにはそのメトリクスはありません。
New Relicの公式ドキュメントを確認すると、
Google Cloud Runで取れるのは、レイテンシや
課金対象のインスタンス時間など、限られた項目でした。
また、連携方式(サービスアカウント方式/Workload Identity連携方式)によって、
取れるメトリクスの種類も変わります。
当初4項目あった監視条件のうち、2項目は対応するメトリクスが存在しませんでした。
最終的には、実在する2項目(レイテンシ・課金対象のインスタンス時間)に絞って
監視条件を作り直しました。
もう1つのハマりどころは、NRQLのWHERE句に使う属性名です。
ドキュメントの名前と実データの名前が一致しないことがあるため、
条件を書く前に実データで確認しました。
-- まず実データにどんな属性があるかを確認する
SELECT keyset() FROM GcpRunRevisionSample SINCE 1 hour ago
条件はTerraformの for_each でまとめて管理し、
項目の追加や削除はtfvarsの編集だけで済むようにしました。
resource "newrelic_nrql_alert_condition" "cloudrun" {
for_each = var.cloudrun_map_data
policy_id = newrelic_alert_policy.alert_policy.id
type = "static"
name = "${each.value.name} [CloudRun] ${each.value.category}"
aggregation_window = 60 # 1分間隔で評価
nrql {
query = each.value.nrql_query
}
critical {
operator = each.value.operator
threshold = each.value.threshold
threshold_duration = 300 # 5分継続で発報
threshold_occurrences = each.value.threshold_occurrences
}
}
④ 通知:条件を作っただけでは誰にも届かない
火災報知器を付けても、
消防署への回線をつながないと誰も駆けつけない、というイメージです。
アラート条件を作ると、New Relic上ではissueが発生します。
ただし通知先を別途設定しないと、どこにも連絡は飛びません。
現在のNew Relicでは、次の3つのリソースを組み合わせて
通知経路を作ります。
| リソース | 役割 |
|---|---|
newrelic_notification_destination |
送り先(PagerDutyなど)と認証情報 |
newrelic_notification_channel |
送るメッセージの中身 |
newrelic_workflow |
どのポリシーのissueを、どのチャネルへ流すか |
以前よく使われていた newrelic_alert_channel は非推奨のため、
新しく作るならこちらの構成を選びます。
また、PagerDutyの統合キーがまだ手元にない段階でも、
アラート条件だけ先に反映したい場面がありました。
そこで count を使い、
キーが空のうちは通知系のリソースを作らないようにしています。
locals {
notification_enabled = var.pagerduty_service_key != "" ? 1 : 0
}
resource "newrelic_workflow" "pagerduty" {
count = local.notification_enabled
account_id = var.nr_account_id
name = "${var.project_name}-wf-prd"
issues_filter {
name = "policy-filter"
type = "FILTER"
predicate {
attribute = "labels.policyIds"
operator = "EXACTLY_MATCHES"
values = [newrelic_alert_policy.alert_policy.id]
}
}
destination {
channel_id = newrelic_notification_channel.pagerduty[0].id
}
}
これから作る人向け:再現チェックリスト
同じ構成を作るときは、次の順番で進めると手戻りがありません。
| 順番 | 作業 | できたかの確認方法 |
|---|---|---|
| 1 | 監視したい項目を、公式ドキュメントのメトリクス一覧と突き合わせる | 全項目に対応するメトリクス名がある |
| 2 | シンク・トピック・writer identityの権限・プッシュ配信を作る | New Relicで SELECT count(*) FROM Log が0件でない |
| 3 | New Relicのサービスアカウントに権限を付け、プロジェクトを登録する | New RelicのGoogle Cloud連携画面にプロジェクトが表示される |
| 4 | SELECT keyset() で属性名を確かめてから、NRQL条件を書く |
条件のクエリで値が返ってくる |
| 5 | destination・channel・workflowで通知経路を作る | テスト通知が送り先に届く |
| 6 | キーを含むtfvarsとtfstateの扱いを確認する | tfvarsがGitの管理外、tfstateの閲覧者が限定されている |
各手順の右端の列が埋まれば、
監視は「作った」ではなく「動いている」と言える状態です。
まとめ
| # | ハマりどころ | 対策 |
|---|---|---|
| ① | シンクを作ってもログが届かない | writer identityにトピックへの発行権限を付ける |
| ② | ライセンスキーがtfstateに残る | ジョブ起動はTerraformの管理外にし、それでも残る分はtfstateの閲覧権限を絞って守る |
| ③ | 存在しないメトリクスで条件を書いていた | 公式ドキュメントと実データ(keyset())で先に確認する |
| ④ | 条件だけ作って通知が飛ばない | destination・channel・workflowの3点セットで経路を作る |
監視は「作って終わり」ではなく、
「本当に届くか」「本当にそのデータがあるか」を
確かめるところまでが仕事でした。
まずは自分の環境で SELECT keyset() を1回実行して、
どんな属性が取れているかを見てみてください。
参考資料
- New Relic 公式ドキュメント「Google Cloud Run monitoring integration」
https://docs.newrelic.com/docs/infrastructure/google-cloud-platform-integrations/gcp-integrations-list/google-cloud-run-monitoring-integration/ - New Relic 公式ドキュメント「Introduction to Google Cloud Platform integrations」
https://docs.newrelic.com/docs/infrastructure/google-cloud-platform-integrations/get-started/connect-google-cloud-platform-services-new-relic/ - Google Cloud 公式ドキュメント「Push subscriptions」
https://cloud.google.com/pubsub/docs/push - Terraform Registry「newrelic_workflow」
https://registry.terraform.io/providers/newrelic/newrelic/latest/docs/resources/workflow