💰

Cloud SQL を夜間自動停止してコストを削減してみた

2024/12/03に公開

この記事は、Magic Moment Advent Calendar 2024 2日目の記事です。

こんにちは、 Magic Moment で QAE をやっている yano です。

今年は Cloud Infra におけるコスト最適化や節約を実施することが多かった一年でした。

インフラコスト削減施策の一環で、本番環境ではない環境で利用している Cloud SQL インスタンスは夜間停止することを実施しました。

そこで本記事では、コスト削減のために Cloud Scheduler だけを用いて簡単に Cloud SQL インスタンスを自動停止する方法を紹介します。

コスト削減効果

まず、Cloud SQL インスタンスを夜間停止することによって得られるコスト削減効果について説明します。

Cloud SQL の料金において主にコストに影響のあるものは、CPU とメモリの料金、そしてストレージの料金になります。

この中でもインスタンスの停止によってコストカットできる箇所は、CPU とメモリの料金です。停止してもストレージが消えるわけではないのでストレージにかかる料金はカットできません。

そこで CPU とメモリの料金に関してのみコスト削減効果を考えます。例えば毎日24時間起動していた場合の月額(31日分)の費用は次のように計算できます。

(0.0702 * {vCPU の数} + 0.0119 * {メモリのギガ数}) * 24(hour) * 31(day)

次に月曜日~金曜日までの平日で、毎日8時~23時までの15時間稼働にした場合の月額(22日分)の費用は次のように計算できます。

(0.0702 * {vCPU の数} + 0.0119 * {メモリのギガ数}) * 15(hour) * 22(day)

上記想定で考えると同等の CPU とメモリの利用料金に関しては月額で約 56% 削減した価格となり、通常の半額以下で利用することが可能になります。

コスト削減率[%] = \left(1-\frac{15 \times 22}{24 \times 31} \right) \times 100 \fallingdotseq 56

停止と再起動する方法

コスト上でのメリットが分かったところで具体的なやり方を説明します。

公式ドキュメントに記載ある中で Cloud SQL Admin API を利用します。

PATCH https://sqladmin.googleapis.com/sql/v1beta4/projects/{project-id}/instances/{instance-id}

上記 API で activationPolicy を NEVER と ALWAYS に切り替えるリクエストを Cloud Scheduler から定期的に実行するだけで Cloud SQL インスタンスの停止と再起動が実現できます。

Terraform での実装方法

やり方を決めたら実装します。必要なものは停止用 Cloud Scheduler、起動用 Cloud Scheduler、そして Cloud Scheduler で使用するサービスアカウントです。

Terraform での実装サンプルは次のようになります。

## 停止用 Cloud Scheduler
resource "google_cloud_scheduler_job" "cloud_sql_stop" {
  provider         = google-beta
  name             = "Stop-Cloud-SQL-Instance"
  description      = "Stop Cloud SQL Instance"
  schedule         = "0 23 * * 1-5"
  time_zone        = "Asia/Tokyo"
  attempt_deadline = "30s"
  paused           = false

  http_target {
    http_method = "PATCH"
    uri         = "https://sqladmin.googleapis.com/sql/v1beta4/projects/${local.project}/instances/${instance-idを渡す}"
    headers = {
      Content-Type = "application/json"
    }
    body = base64encode(jsonencode({
      "settings" = {
        "activationPolicy" = "NEVER",
      }
    }))

    oauth_token {
      service_account_email = google_service_account.cloudsql_scheduler.email
    }
  }
}

## 起動用 Cloud Scheduler
resource "google_cloud_scheduler_job" "cloud_sql_start" {
  provider         = google-beta
  name             = "Start-Cloud-SQL-Instance"
  description      = "Start Cloud SQL Instance"
  schedule         = "0 8 * * 1-5"
  time_zone        = "Asia/Tokyo"
  attempt_deadline = "30s"
  paused           = false

  http_target {
    http_method = "PATCH"
    uri         = "https://sqladmin.googleapis.com/sql/v1beta4/projects/${local.project}/instances/${instance-idを渡す}"
    headers = {
      Content-Type = "application/json"
    }
    body = base64encode(jsonencode({
      "settings" = {
        "activationPolicy" = "ALWAYS",
      }
    }))

    oauth_token {
      service_account_email = google_service_account.cloudsql_scheduler.email
    }
  }
}

## Cloud Scheduler で使用するサービスアカウント
resource "google_service_account" "cloudsql_scheduler" {
  provider     = google-beta
  account_id   = "cloudsql-scheduler"
  display_name = "Cloud SQL Scheduler service account"
  description  = "Cloud SQL Scheduler service account"
}

## サービスアカウントに権限を付与
resource "google_project_iam_member" "cloudsql_scheduler" {
  for_each = {
    "cloudschedulerServiceAgent" = "roles/cloudscheduler.serviceAgent",
    "cloudsqlEditor"             = "roles/cloudsql.editor"
  }

  project = local.project
  role    = each.value
  member  = google_service_account.cloudsql_scheduler.member
}

Apply 後には、次のような Cloud Scheduler が作られていると思うので、実際にインスタンスの停止と起動ができるか 強制実行 のボタンから動作確認を行うことができます。

scheduler

最後に

今回の方法で簡単に Cloud SQL インスタンスを夜間自動停止して、コスト削減できました。

課題点としては Cloud Scheduler で cron ジョブを実行しているだけなので、祝日の判定ができない点にあります。

祝日での非稼働日にもインスタンスが起動してコストがかかってしまう点にはご注意ください。

次回のアドベントカレンダーは kurihara さん の「そうだ、エディタを変えよう 〜ZedでLSPを使用する〜」です。
お楽しみに!

Discussion