IBM Cloud LogsをSchematics(Terraform)で作ってみた

# はじめに

LogDNAベースのIBM Log AnalysisそしてIBM Cloud Activity TrackerのEOSが2025年3月30日ということで、いよいよ差し迫ってきました。
しかし、真新しいサービスであるIBM Cloud Logsを使い始めるには多少の準備が必要になりますので、このサービスの利用を取り急ぎ始めるにあたって最低限実施しておくべき設定一式を、Terraformでサクッと作成できるようなコードを準備してみることにしました。

# 注意（2024/10/27追記)

既存の環境で、プラットフォームログをLog Analysisに送信する設定をしている場合、この手順を実施しても、送信は開始されません。そして、既存の設定と、新しいログルーテイングについて、プラットフォームログについては共存出来なさそうなので、適切なタイミングで、既存の設定を削除してください。

また、新しいログルーティングの設定によって、Log Analysisにプラットフォームログを送信するようにした場合は、ログのsourceが変化する場合がありそうなので、ビューやアラートの設定の見直しが必要なのも要注意です。
例えば、Code Engineのジョブ実行のログ出力はこのように変化しました。（前半が新しいログルーティングによるもの、後半はその設定を削除して、元のプラットフォームログの設定を有効にしたもの）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307720/5557bc3f-45b6-0405-a56e-0d0021f12455.png)


# 確認した環境

+ Schematics (Terraform v1.5.7)
    + ibm-cloud/ibm v1.70.1

# やりたいこと

Activity Trackerと、プラットフォームログをIBM Cloud Logsで見られるようにするには、以下の設定等が必要になります。これらを一瞬？で作成します。

+ 許可
    + LogsからICOSへのWriter役割付与
    + Logs RoutingからLogsへのSender役割付与
    + Activity Tracker Event RoutingからLogsへのSender役割付与
+ ICOSバケット
    + データ保存用とメトリクス保存用をLogsインスタンス別に作成
+ Logsインスタンス
    + Platform log用とActivity Tracker用の2インスタンス作成
    + 先に作成したデータ保存用とメトリクス保存用のICOSバケットを割り当て
+ Activity Trackerイベント・ルーティング
    + ターゲット
        + 送信元として全てを指定
    + 経路
        + 上で作成したターゲットをActivity Tracker用のLogsに転送
    + 設定
        + メタデータの場所、デフォルト・ターゲットを設定
+ Platform Logのルーティング

# Terraformコード

まず、いつものを用意します。

```Terraform:provider.tf
provider "ibm" {
  ibmcloud_api_key = var.ibmcloud_api_key
  region           = var.region
}
```

```Terraform:versions.tf
terraform {
  required_version = ">= 1.0.0, < 2.0.0"
  required_providers {
    ibm = {
      source  = "IBM-Cloud/ibm"
      version = ">= 1.12.0"
    }
  }
}
```

次に変数関連のファイルを用意します。APIキーは、terraform plan/apply実行前に、`export TF_VAR_ibmcloud_api_key=****`で指定します。リージョン、リソースグループ名及びICOSインスタンス名のところは環境に合わせて書き換えてください。


```Terraform:variables.tf
# 作成先リージョン
variable "region" {
  type    = string
  default = "jp-tok"
}
# 既存のリソースグループ名
variable "resource_group" {
  type = string
}
# 既存のICOSインスタンス名
variable "icos_instance" {
  type = string
}

# API Key
variable "ibmcloud_api_key" {
  type = string
}
```

```Terraform:terraform.tfvars
# 作成先リージョン
region = "jp-tok"

# 既存のICOSインスタンス名
icos_instance = "****"

# 既存のリソースグループ名
resource_group = "****"
```

そして「やりたいこと」を順に実現するTerraformのコードが以下です。

```Terraform:main.tf
# IBM Cloud Logs からICOSへのWriter役割の付与
resource "ibm_iam_authorization_policy" "policy_logs_icos" {
  source_service_name = "logs"
  target_service_name = "cloud-object-storage"
  roles               = ["Writer"]
}

# Logs RoutingからIBM Cloud LogsへのSender役割の付与
resource "ibm_iam_authorization_policy" "policy_logsrouter_logs" {
  source_service_name = "logs-router"
  target_service_name = "logs"
  roles               = ["Sender"]
}

# Activity Tracker Event RoutingからIBM Cloud LogsへのSender役割の付与
resource "ibm_iam_authorization_policy" "policy_atracker_logs" {
  source_service_name = "atracker"
  target_service_name = "logs"
  roles               = ["Sender"]
}

# ICOSインスタンスは既存のものを参照
data "ibm_resource_instance" "icos_instance" {
  name = var.icos_instance
}
# リソースグループ指定
data "ibm_resource_group" "resource_group" {
  name = var.resource_group
}

# ICOSバケット作成
resource "ibm_cos_bucket" "logs_data_at" {
  bucket_name          = "logs-data-at-sample-test"
  resource_instance_id = data.ibm_resource_instance.icos_instance.id
  region_location      = var.region
  storage_class        = "smart"
}
resource "ibm_cos_bucket" "logs_metric_at" {
  bucket_name          = "logs-metric-at-sample-test"
  resource_instance_id = data.ibm_resource_instance.icos_instance.id
  region_location      = var.region
  storage_class        = "smart"
}
resource "ibm_cos_bucket" "logs_data_pf" {
  bucket_name          = "logs-data-pf-sample-test"
  resource_instance_id = data.ibm_resource_instance.icos_instance.id
  region_location      = var.region
  storage_class        = "smart"
}
resource "ibm_cos_bucket" "logs_metric_pf" {
  bucket_name          = "logs-metric-pf-sample-test"
  resource_instance_id = data.ibm_resource_instance.icos_instance.id
  region_location      = var.region
  storage_class        = "smart"
}

# Activity Tracker用IBM Cloud Logs
resource "ibm_resource_instance" "logs_instance_at" {
  depends_on = [ibm_cos_bucket.logs_data_at, ibm_cos_bucket.logs_metric_at]

  name              = "logs-atracker-sample-test"
  service           = "logs"
  plan              = "standard"
  location          = var.region
  resource_group_id = data.ibm_resource_group.resource_group.id

  parameters = {
    retention_period        = "7" # 保存期間日数
    logs_bucket_crn         = ibm_cos_bucket.logs_data_at.crn
    logs_bucket_endpoint    = ibm_cos_bucket.logs_data_at.s3_endpoint_direct
    metrics_bucket_crn      = ibm_cos_bucket.logs_metric_at.crn
    metrics_bucket_endpoint = ibm_cos_bucket.logs_metric_at.s3_endpoint_direct
  }
}

# Platform Log用IBM Cloud Logs
resource "ibm_resource_instance" "logs_instance_pf" {
  depends_on = [ibm_cos_bucket.logs_data_pf, ibm_cos_bucket.logs_metric_pf]

  name              = "logs-platform-sample-test"
  service           = "logs"
  plan              = "standard"
  location          = var.region
  resource_group_id = data.ibm_resource_group.resource_group.id

  parameters = {
    retention_period        = "7" # 保存期間日数
    logs_bucket_crn         = ibm_cos_bucket.logs_data_pf.crn
    logs_bucket_endpoint    = ibm_cos_bucket.logs_data_pf.s3_endpoint_direct
    metrics_bucket_crn      = ibm_cos_bucket.logs_metric_pf.crn
    metrics_bucket_endpoint = ibm_cos_bucket.logs_metric_pf.s3_endpoint_direct
  }
}

# Activity Trackerイベント・ルーティング - ターゲット
resource "ibm_atracker_target" "atracker_cloudlogs_target" {
  cloudlogs_endpoint {
    target_crn = ibm_resource_instance.logs_instance_at.crn
  }
  name        = "logs-target"
  target_type = "cloud_logs"
  region      = var.region
}

# Activity Trackerイベント・ルーティング - 経路
resource "ibm_atracker_route" "atracker_route_logs" {
  depends_on = [ibm_atracker_target.atracker_cloudlogs_target]

  name = "logs-route"
  rules {
    target_ids = [ibm_atracker_target.atracker_cloudlogs_target.id]
    locations  = ["*", "global"] # すべてのイベント (ワイルドカード)と、プラットフォーム・イベント (グローバル)
  }
  lifecycle {
    # Recommended to ensure that if a target ID is removed here and destroyed in a plan, this is updated first
    create_before_destroy = true
  }
}

# Activity Trackerイベント・ルーティング・アカウント設定
resource "ibm_atracker_settings" "atracker_settings" {
  depends_on = [ibm_atracker_target.atracker_cloudlogs_target]

  default_targets = [ibm_atracker_target.atracker_cloudlogs_target.id] # デフォルト・ターゲット

  metadata_region_primary   = "jp-tok" # メタデータの場所 - 1 次メタデータ領域
  metadata_region_backup    = "jp-osa" # メタデータの場所 - メタデータ領域のバックアップ
  private_api_endpoint_only = false    # パブリック・エンドポイント

  # Optional but recommended lifecycle flag to ensure target delete order is correct
  lifecycle {
    create_before_destroy = true
  }
}

# Platform Logのルーティング
resource "ibm_logs_router_tenant" "logs_router_tenant_instance" {
  depends_on = [ ibm_resource_instance.logs_instance_pf ]

  name   = "logs-router-tenant"
  region = var.region
  targets {
    log_sink_crn = ibm_resource_instance.logs_instance_pf.id
    name         = "logs-target"
    parameters {
      host = ibm_resource_instance.logs_instance_pf.extensions.external_ingress_private
      port = 443
    }
  }
}
```

# 実行

Terraform CLIで実行する場合、環境を初期化したのち、まずはplanを実行してエラーがないことを確認し、applyを実行します。

```
$ terraform init
$ export TF_VAR_ibmcloud_api_key=***********
$ terraform plan -var-file=terraform.tfvars
$ terraform apply -var-file=terraform.tfvars
```

詳細な手順は割愛しますが、Schematicsからも同様に実行出来ることを確認しています。

# 結果

必要な許可設定が行われたのち、最低限の設定がされたPlatform log用とActivity Tracker用の2インスタンスが作成されると思います。

保存期間を7日間から変更したい場合はibm_resource_instanceリソース内の`retention_period`を変更してください。他に変更したくなりそうなところにはコメントをつけておいたので、参考にしてみてください。

また、コードにあるパラメータは一部ですので、リソースごとに可能な詳細な設定は、[公式ガイド](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs)を参照ください。

# まとめ

IBM Cloudアカウントを作成するたび、最低限必要になるインスタンスや設定をひとまとめにコード化しておくと便利かと思いますので、その参考になれば幸いです。