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

【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

IT未経験者必見 USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。

「フリーランスエンジニア」

近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。

「成功する人とそうでない人の違いは何か?」

私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。

比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。

多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、

note記事3000いいね超えの殿堂記事 今すぐ読む

エンベーダー編集部

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

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

関連記事