📝

Cloud Functions + Cloud Scheduler で Cloud SQL のデータを定期削除する

2022/11/08に公開

はじめに

GCP の Cloud SQL にはストレージの自動増量機能があるため、ストレージ不足を気にしなくて良いのがとても便利です。一方で、一旦ストレージが増量されると減らすことができないので、コストが気になります。そこで、古いデータを自動で定期削除する方法を試してみたので、共有したいと思います。

構成


今回は以下のような仕組みで、データの定期削除を行います。

  • Cloud SQL のインスタンスに対してクエリを実行する関数を Cloud Functions に作成する
  • ソースコードを GitHub のリポジトリから取得して Cloud Functions にデプロイするように Cloud Build を構成し、関数を作成・更新する
  • 定期的に関数を実行するように Cloud Scheduler を設定する

設定ファイル等のディレクトリ構成は以下のようにしました。Cloud Build のトリガー作成と Cloud Scheduler のジョブ作成については、Terraform でコード化する方法も併せて紹介します。

.
├── cloudBuild
│   └── cloudbuild.yaml
├── cloudFunctions
│   └── mysql
│       ├── mysql_execute_query.js
│       ├── mysql_tbl_delete.sql
│       └── package.json
└── infra
    ├── cloud_build.tf
    ├── cloud_scheduler.tf
    ├── cloud_sql.tf
    ├── main.tf
    └── variables.tf

Cloud Functions で実行する処理を作成する

まずは、Cloud Functions で実行する処理を作成します。利用できる言語は、Node.js、Python、Go、Java、.NET、Ruby、PHPから選べますが、今回は Node.js 16 で書きました。クエリが書かれているSQLファイルを読み込んだ後、Cloud SQLインスタンスに接続し、クエリを実行するという流れになっています。

mysql_execute_query.js
const mysql = require('mysql');

exports.executeQuery = (req, res) => {
  const connection = mysql.createConnection({
    socketPath: "/cloudsql/" + process.env.connectionName, // SQLインスタンス接続名
    user: process.env.dbUser, // ログインユーザ名
    password: process.env.dbPassword, // ログインパスワード
    database: process.env.dbName, // データベース名
    multipleStatements: true // 複数クエリの実行を許可する
  });

  // SQL文の読み込み
  const fs = require('fs');
  let sql = fs.readFileSync(process.env.sqlFileName, 'utf-8');

  // Cloud SQLに接続
  connection.connect();
  
  // クエリ実行
  connection.query(sql, (err, results) => {
    if (err) {
      console.error(err);
      res.status(500).send(err);
    } else {
      console.log(JSON.stringify(results))
      res.send(JSON.stringify(results));
    }
  });
  
  // 接続終了
  connection.end();
};
package.json
{
  "version": "0.0.3",
  "dependencies": {
    "mysql": "latest"
  }
}
mysql_tbl_delete.sql
# テーブルから3ヶ月より前のデータを削除する
DELETE FROM TEST_TABLE WHERE DELI_DTE < (CURRENT_DATE() - INTERVAL 3 MONTH);

Cloud Build 構成ファイルを作成する

ソースコードを作成したら、次にビルド構成ファイルを作成します。公式ドキュメントに分かりやすい解説がのっていますので、参考にして書いていきます。

構成ファイルには、関数名やソースコードに関する情報、環境変数、何をトリガーにするかなどを設定します。今回は Cloud Scheduler で関数を実行させるため、HTTPトリガーを選択しています。

cloudbuild.yaml
steps:
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    args:
      - gcloud
      - functions
      - deploy
      - mysql-tbl-delete
      - --region=<region>
      # HTTPトリガー
      - --trigger-http
      # 関数のソースコードのパス
      - --source=./cloudFunctions/mysql
      # 関数で使用される言語ランタイム
      - --runtime=nodejs16
      # エントリーポイント
      - --entry-point=executeQuery
      # 環境変数
      - '--set-env-vars'
      - connectionName=<projectID>:<region>:<sqlInstanceName>
      - '--set-env-vars'
      - dbUser=testuser
      - '--set-env-vars'
      - dbName=testdb
      - '--set-env-vars'
      - sqlFileName=mysql_tbl_delete.sql
      # Secret Manager から取得する環境変数
      - 'set-secrets'
      - 'dbPassword=testdb_password:1'

Terraform 設定ファイルを作成する

関数のソースコードとビルド構成ファイルが準備できたので、次に、Cloud Build と Cloud Scheduler の設定ファイルを作成します。

Cloud Build のトリガー作成

Terraform の公式ドキュメントを参考に作成します。

権限の設定では、Cloud Build から Cloud Functions にデプロイすることを許可するため、Cloud Functions 開発者のロールを有効化します。トリガー設定では、ビルド構成ファイルを指定したり、トリガーイベントを設定します。以下では、「GitHubの指定リポジトリの指定ブランチにpushする」をトリガーイベントにしていますが、プルリクエストをトリガーにしたり、自動でデプロイされると困る場合は、手動呼び出しに設定することも可能です。

cloud_build.tf
// 権限の設定
resource "google_project_iam_member" "cloudbuild_iam" {
  project = var.project
  for_each = toset([
    "roles/cloudfunctions.developer",
    "roles/iam.serviceAccountUser"
  ])
  role    = each.key
  member  = "serviceAccount:${var.project}@cloudbuild.gserviceaccount.com"
}

// トリガー(MySQLの定期削除)
resource "google_cloudbuild_trigger" "mysql-tbl-delete" {
  location = var.region
  name     = "mysql-tbl-delete"

  // Cloud Build構成ファイル
  filename = "cloudBuild/cloudbuild.yaml"

  // トリガーイベント
  github {
    owner = "ownerName"
    name  = "repositoryName"
    // 指定ブランチにpushをトリガーにする
    push {
      branch = "^${var.github_branch}$"
    }
  }
  // フィルタ
  included_files = ["cloudFunctions/mysql/**"]
}

Cloud Scheduler のジョブ作成

こちらも Terraform の公式ドキュメントを参考に作成します。Cloud Scheduler のジョブの作成はとてもシンプルで、実行スケジュールとターゲットとなる Cloud Functions のトリガーURL を設定するだけです。

cloud_scheduler.tf
resource "google_cloud_scheduler_job" "mysql-tbl-delete" {
  name             = "mysql-tbl-delete"
  schedule         = "15 1 1 * *"
  time_zone        = "Asia/Tokyo"

  # HTTPターゲット
  http_target {
    http_method = "GET"
    uri         = "https://${var.region}-${var.project}.cloudfunctions.net/mysql-tbl-delete"
  }
}

まとめ

今回は、Cloud SQL のデータを定期削除する方法を試してみましたが、意外と簡単に設定できることが分かりました!

レスキューナウテックブログ

Discussion