1. ホーム
  2. 記事一覧
  3. TerraformでAWS RDS/Auroraの時限起動を設定し、コストを削減

2023.10.28

TerraformでAWS RDS/Auroraの時限起動を設定し、コストを削減

この記事の目的

この記事では、AWSのデータベースサービスであるRDSとAuroraについて簡単に触れた後、なぜコスト削減が大事なのか、そしてそのためにどうやってTerraformを使うのかを紹介していきます。

AWS RDS/Auroraって何?

簡単に言うと、AWSの中でデータベースを動かすためのサービスです。Auroraはその中でも特に高速で、MySQLやPostgreSQLと互換性があります。

コスト削減って大事?

結論から言うと、めちゃくちゃ大事です。データベースを24時間稼働させるのはコストがかかるし、実はそんなにずっと動かしておく必要はないんです。そこで、無駄な時間にデータベースを止めてコストを減らす方法を考えました。

Terraformって何するの?

Terraformは、クラウドの設定をコードで書いて管理するツール。このツールを使えば、データベースの時限起動などの設定を簡単にできます。下記の記事で大体のことがわかります。この記事では、Terraformの導入が済んでいる前提でコードを紹介していきます。

https://envader.plus/article/136

AWS RDS/Auroraのコスト構造

AWS RDSとAuroraのコストはいくつかの要素に分かれています。それぞれの要素を理解することで、無駄なコストを削減するヒントを見つけることができます。

時間単位の課金について

AWS RDSとAuroraは、インスタンスを起動している時間に応じて課金されます。つまり、インスタンスが動いている時間だけ料金がかかります。夜間や休日など、利用者が少ない時間帯にインスタンスを停止することでコストを節約することができます。ただし、Aurora v2のクラスターは、現在のところ停止する機能が提供されていないため、この点には注意が必要です。

ストレージやデータ転送のコスト

データベースのストレージサイズやI/O、データのバックアップにもコストがかかります。また、データベースと他のサービスやアプリケーションとの間でのデータ転送量にも料金が発生します。不要なデータの削除や、転送量の最適化を行うことで、こちらのコストも削減できます。

どの部分でコスト削減が可能か

時限起動

前述の通り、利用者が少ない時間帯にデータベースを停止することで、時間単位の課金を節約。ただし、Aurora v2のクラスターは停止ができない点を考慮する必要があります。

データ管理

古いデータや不要なデータを定期的に削除することで、ストレージコストを削減。

最適なインスタンスタイプの選択

使用するデータベースのワークロードに合わせて、最もコストパフォーマンスの良いインスタンスタイプを選択することで、無駄なコストを避けることができます。

この記事ではタイトルの通りインスタンスの時限起動をTerraformを使用して実現します。

Terraformで作成するメリット

Terraformはクラウドインフラストラクチャのプロビジョニングと管理のためのツールとして、多くのエンジニアから支持を受けています。それにはいくつかの明確なメリットがあります。

1. コードベースの管理

TerraformはInfrastructure as Code (IaC) のアプローチを採用しています。これにより、インフラの構成をコードとして明示的に記述できるため、再現性とトレーサビリティが高まります。

2. プラットフォーム非依存

TerraformはAWSだけでなく、多くのクラウドプロバイダーやサービスに対応しています。これにより、複数のクラウド環境での構成を一貫して管理することができます。

3. 状態の管理

Terraformはインフラの状態を管理する機能を持っています。これにより、現在のインフラの状態とコードで記述された状態との差分を簡単に確認でき、意図しない変更を防ぐことができます。

この他にもメリットはありますが、リソースをコードで管理するにあたり上記のメリットだけでも十分であることがわかります。

Terraformのコード

variables.tf

次の変数をvariables.tfに記述し準備します。

aurora_schedule_target {}
rds_schedule_target {}

terraform.tfvars

次の変数をterraform.tfvarsに記述します。

aurora_schedule_target = {
    aurora-instance = ["cron(00 08 ? * MON-FRI *)", "cron(00 20 ? * MON-FRI *)"],
}

rds_chedule_target = {
    rds-instance = ["cron(00 08 ? * MON-FRI *)", "cron(00 20 ? * MON-FRI *)"],
}

定義

aurora-instance: Aurora インスタンスの ARN rds-instance: RDS インスタンスの ARN

スケジュール

cron(00 08 ? * MON-FRI *): 月曜日から金曜日の午前 8 時に起動 cron(00 20 ? * MON-FRI *):月曜日から金曜日の午後 8 時に停止

説明

Aurora インスタンスと RDS インスタンスの両方を、月曜日から金曜日の午前 8 時に起動して、午後 8 時に停止するように設定しています。

Auroraインスタンスの停止と起動

イベントブリッジのスケジューラ機能を使用します。

aurora-scheduler.tf

# ==============================
# = Aurora Auto Scheduler
# ==============================

# スケジュールに基づいてAuroraクラスターを起動する設定
resource "aws_scheduler_schedule" "aurora-start" {
  for_each    = var.aurora_schedule_target              # 起動スケジュールのターゲット情報
  name        = "${each.key}-scheduled-start"           # スケジュールの名前
  description = "Scheduled start action for Aurora ${each.key}"  # スケジュールの説明
  group_name  = "default"                               # スケジュールのグループ名

  flexible_time_window {
    mode = "OFF"  # フレックスタイムウィンドウは使用しない
  }

  schedule_expression          = each.value.0          # 起動するスケジュールの式
  schedule_expression_timezone = "Asia/Tokyo"          # タイムゾーンの指定

  # スケジュールのターゲット情報
  target {
    arn      = "arn:aws:scheduler:::aws-sdk:rds:startDBCluster"  # RDSのクラスターを起動する操作のARN
    role_arn = data.aws_iam_role.scheduler_role.arn              # スケジュール操作のIAMロールのARN

    input = jsonencode({
      DbClusterIdentifier = "${each.key}"  # 起動するクラスターの識別子
    })

    # リトライポリシーの設定
    retry_policy {
      maximum_event_age_in_seconds = 600   # リトライする最大のイベントの経過時間:10分
      maximum_retry_attempts       = 10    # リトライの最大回数
    }
  }
}

# スケジュールに基づいてAuroraクラスターを停止する設定
resource "aws_scheduler_schedule" "aurora-stop" {
  for_each    = var.aurora_schedule_target              # 停止スケジュールのターゲット情報
  name        = "${each.key}-scheduled-stop"            # スケジュールの名前
  ddescription = "Scheduled stop action for Aurora ${each.key}"  # スケジュールの説明
  group_name  = "default"                               # スケジュールのグループ名

  flexible_time_window {
    mode = "OFF"  # フレックスタイムウィンドウは使用しない
  }

  schedule_expression          = each.value.1          # 停止するスケジュールのcron式
  schedule_expression_timezone = "Asia/Tokyo"          # タイムゾーンの指定

  # スケジュールのターゲット情報
  target {
    arn      = "arn:aws:scheduler:::aws-sdk:rds:stopDBCluster"   # RDSのクラスターを停止する操作のARN
    role_arn = data.aws_iam_role.scheduler_role.arn              # スケジュール操作のIAMロールのARN

    input = jsonencode({
      DbClusterIdentifier = "${each.key}"  # 停止するクラスターの識別子
    })

    # リトライポリシーの設定
    retry_policy {
      maximum_event_age_in_seconds = 600   # リトライする最大のイベントの経過時間:10分
      maximum_retry_attempts       = 10    # リトライの最大回数
    }
  }
}

RDSインスタンスの停止と起動

こちらもイベントブリッジのスケジューラ機能を使用します。

rds-scheduler.tf

# ==============================
# = RDS Auto Scheduler
# ==============================

# スケジュールに基づいてRDSクラスターを起動する設定
resource "aws_scheduler_schedule" "rds-start" {
  for_each    = var.rds_schedule_target                 # 起動スケジュールのターゲット情報
  name        = "${each.key}-scheduled-start"           # スケジュールの名前
  description = "Scheduled start action for RDS ${each.key}"  # スケジュールの説明
  group_name  = "default"                               # スケジュールのグループ名

  flexible_time_window {
    mode = "OFF"  # フレックスタイムウィンドウは使用しない
  }

  schedule_expression          = each.value.0          # 起動するスケジュールの式
  schedule_expression_timezone = "Asia/Tokyo"          # タイムゾーンの指定

  # スケジュールのターゲット情報
  target {
    arn      = "arn:aws:scheduler:::aws-sdk:rds:startDBCluster"  # RDSのクラスターを起動する操作のARN
    role_arn = data.aws_iam_role.scheduler_role.arn              # スケジュール操作のIAMロールのARN

    input = jsonencode({
      DbClusterIdentifier = "${each.key}"  # 起動するクラスターの識別子
    })

    # リトライポリシーの設定
    retry_policy {
      maximum_event_age_in_seconds = 600   # リトライする最大のイベントの経過時間:10分
      maximum_retry_attempts       = 10    # リトライの最大回数
    }
  }
}

# スケジュールに基づいてRDSクラスターを停止する設定
resource "aws_scheduler_schedule" "rds-stop" {
  for_each    = var.rds_schedule_target                 # 停止スケジュールのターゲット情報
  name        = "${each.key}-scheduled-stop"            # スケジュールの名前
  ddescription = "Scheduled stop action for RDS ${each.key}"  # スケジュールの説明
  group_name  = "default"                               # スケジュールのグループ名

  flexible_time_window {
    mode = "OFF"  # フレックスタイムウィンドウは使用しない
  }

  schedule_expression          = each.value.1          # 停止するスケジュールのcron式
  schedule_expression_timezone = "Asia/Tokyo"          # タイムゾーンの指定

  # スケジュールのターゲット情報
  target {
    arn      = "arn:aws:scheduler:::aws-sdk:rds:stopDBCluster"   # RDSのクラスターを停止する操作のARN
    role_arn = data.aws_iam_role.scheduler_role.arn              # スケジュール操作のIAMロールのARN

    input = jsonencode({
      DbClusterIdentifier = "${each.key}"  # 停止するクラスターの識別子
    })

    # リトライポリシーの設定
    retry_policy {
      maximum_event_age_in_seconds = 600   # リトライする最大のイベントの経過時間:10分
      maximum_retry_attempts       = 10    # リトライの最大回数
    }
  }
}

これらのファイルを作成し、terraform init, terraform plan terraform applyすることでRDSとAuroraの時限稼働が実現できます。

インスタンスの時限稼働で得られるコスト削減効果

730時間使用

db.m5.large インスタンスのオンデマンド料金は、1時間あたり 0.235USD です。そのため、月に730時間使用する場合は、以下のようになります。

730 時間 * $0.235/時間 = $174.05

平日のみ使用

平日の朝8時から夜20時までしか起動しない場合は、以下のようになります。

平日のみ使用時間 = 24時間 * 5日 = 120時間 コスト = 120時間 * $0.235/時間 = $28.20

コスト削減効果

平日の朝8時から夜20時までしか起動しないパターンでは、730時間使用する場合と比較して、以下のようになります。

コスト削減効果 = $174.05 - $46.52 = $127.53 つまり、平日の朝8時から夜20時までしか起動しないパターンでは、730時間使用する場合と比較して、約 73% のコスト削減効果が期待できます。

まとめ

AWS RDS/Aurora の時限稼働は、EventBridgeのschedulerを使用することにより利用頻度の低いデータベースを平日の夜間や休日に停止することで、コスト削減を実現できます。

Terraform を使用してEbentBridgeを設定すると、以下のメリットがあります。

  • 複数のインスタンスに対して一括で設定を変更できる
  • インスタンスの追加や削除に合わせて、設定を自動的に更新できる
  • 本番環境への適用は慎重に検討する必要がありますが、開発環境やステージング環境への導入は積極的に検討すると良いでしょう。

具体的には、以下のようになります。

  • Terraform で時限起動を設定することで、複数のインスタンスに対して一括で設定を変更できるため、運用性が向上します。
  • 時限起動を活用することで、平日の夜間や休日に停止することで、コスト削減を実現できます。
  • 本番環境への適用は、データベースの可用性やパフォーマンスへの影響、運用体制の変更などの観点から慎重に検討する必要があります。

エンベーダー編集部

エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

関連記事