AWS の負荷試験を terraform モジュールにまとめてみた

表題の通り、[AWS での負荷試験](https://aws.amazon.com/jp/solutions/implementations/distributed-load-testing-on-aws/) を terraform モジュールにまとめてみました。

リンク先の手順でブラウザポチポチして作成できますが、モジュールにしておいた方が新しく作るときの負担が少ないかなと思って。

## ディレクトリ構成

[root.tf](#roottf) （モジュールの呼び出し元）
load_test/
  ├ [main.tf](#maintf)
  ├ [sam.tf](#samtf)
  └ [variables.tf](#variablestf)

エンドポイントやユーザー名をファイルに書き出したりもしましたが、あまり必要なかったので省略しました。
イベントのサンプル（ヘッダー、ボディのサンプル）を用意しておくとラクできそう。

公式が出している sam 用のテンプレートをダウンロードして使うだけなので、構成はシンプルです。

## 呼び出し元の記述

ヴァージニアリージョンが負荷試験に使用できるリソースが多い（東京と比べると桁違い[^1]）ので、ヴァージニア用のプロバイダーを使っています。

元にしたプロジェクトは cloudfront 用の SSL 証明書をヴァージニアリージョンで作るので、それ用のプロバイダーを使いまわす形で書いています。

### root.tf

既存のものに対して、`module "load_test"` のところを追加しただけの格好です。

```tf
provider "aws" {
  profile = var.aws_profile
  region  = var.aws_region
  default_tags {
    tags = {
      BillingGroup = "sample-dev"
    }
  }
}

provider "aws" {
  alias   = "virginia"
  profile = var.aws_profile
  region  = "us-east-1"
  default_tags {
    tags = {
      BillingGroup = "sample-dev"
    }
  }
}

terraform {
  required_version = ">= 1.1.7"
  required_providers {
    aws = {
      source                = "hashicorp/aws"
      version               = "5.23.1"
      configuration_aliases = [aws.virginia]
    }

    # 中略
    
  }
}

module "load_test" {
  providers = {
    aws.virginia = aws.virginia
  }

  source           = "../../load_test"

  service_name     = var.service_name
  stage_prefix     = var.stage_prefix
  maintenance_mail = var.maintenance_mail
}
```

## モジュールの中身

### main.tf

ヴァージニアリージョンを使う都合で `aws.virginia` のところが必須だった気がします。

```tf
terraform {
  required_version = ">= 1.1.7"
  required_providers {
    aws = {
      source                = "hashicorp/aws"
      version               = ">=5.4.0"
      configuration_aliases = [aws.virginia]
    }

    # 中略

  }
}
```

ルートで virginia のプロバイダーを作っていない場合はここで作っても良いですね。

### variables.tf

ルートから適当に指定すればよい変数ですが、`admin_name` はログインに使う...はず...(うろ覚え)

```tf
variable "service_name" {
  type = string
}

variable "stage_prefix" {
  type = string
}

variable "email" {
  type = string
}

locals {
  admin_name = "admin-loadtest"
}
```

### sam.tf

公式が出しているテンプレートのURLを指定して、パラメータを設定するだけです。
固定値のパラメータはブラウザから作った時のデフォルト値を入れています。

```tf
resource "aws_cloudformation_stack" "sam" {
  provider      = aws.virginia
  name          = "${var.service_name}-${var.stage_prefix}-load-test"
  # make from template provided by aws
  template_url  = "https://s3.amazonaws.com/solutions-reference/distributed-load-testing-on-aws/latest/distributed-load-testing-on-aws.template"
  capabilities  = ["CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]

  parameters    = {
    AdminName : local.admin_name,
    AdminEmail : var.email,
    EgressCidr : "0.0.0.0/0",
    ExistingSubnetA : "",
    ExistingSubnetB : "",
    ExistingVPCId : "",
    SubnetACidrBlock : "192.168.0.0/20",
    SubnetBCidrBlock : "192.168.16.0/20",
    VpcCidrBlock : "192.168.0.0/16",
  }
}
```

## デプロイ

`terraform apply` に適宜引数を付けて実行しましょう。

デプロイされると、モジュールに渡したメールアドレスに対して、ログインリンクと一時パスワードが送られてきます。後は画面の流れに沿って負荷試験をしましょう。

## おわりに

当然ながらテストに使ったリソースは課金されます。

上記の設定では対象サイトを公開している前提ですが、パラメータをいじって非公開のサイトをターゲットにすることもできそうです。ただ、そうなると vpc と sam を同じリージョンにする必要がありそう。

[^1]: 東京が 3 タスクなのに対してヴァージニアは 2000 タスクでした（2023/10 頃）。