AWS LambdaとEventbridgeでRDSのS3エクスポートを自動化する

こんにちは、クラウドソリューション事業部の本田です。今月もブログ書いていきます、よろしくお願いします。今回ですが、担当している案件でRDSのS3エクスポートを自動化する必要がありましたので、それを実現した内容をまとめていきます。

背景

GCPのBigQueryにRDSのデータをインポートする必要がありました。dumpを取得してデータを転送するなど色々と考えたのですが、BigQueryではparquet形式のデータをサポートしているので、RDSのデータをparquet形式でエクスポートすることのできるRDSスナップショットのS3エクスポートを利用することになりました。また週に1回での更新頻度という要件でしたので、こちらを自動化する必要がありました。BigQueryでのテーブルの作成なども行なっているのですが、これらはまた別の記事にしようかなと思っています。

構成

AWS LambdaでRDSスナップショットのS3エクスポート処理を行い、その関数をEventbrigdeで定期実行させるというような構成です。S3へのエクスポートにはKMSを利用が必要となります。弊社の過去のブログで、S3エクスポートについては書かせていただいているので必要なリソース作成についてはこちらもご覧ください。
https://www.seeds-std.co.jp/blog/creators/2020-02-27-183446/

自動化についてですが、一旦コンソール使って実行することをオススメします。というのもIAM Roleなど自動で作成されるものを流用する方が最低限の権限で作成されるので、設定が楽になります。

S3の作成

任意のバケット名でS3を作成します。設定などはデフォルトで問題ありません。

KMSの作成

こちらも任意の名前で作成します。デフォルトの設定で問題ありません。Lambdaを作成後に、Lambdaのロールを作成したキーの所有者に追加して、Lambdaから作成したキーを利用できるようにします。

AWS Lambdaの作成

以下のようなソースコードになります。ランタイムははnode.jsの最新で、arm64で動かしています。csv-parseのモジュールについては別途インストールが必要となります。今回エクスポート対象としているのが、RDSクラスターのスナップショットを対象としています。つまりRDSのAuroraを対象としていますので、MySQLなどクラスターでない場合は、RDSインスタンスを対象として指定する必要があります。

const AWS = require('aws-sdk');
const { parse } = require('csv-parse/sync');
const fs = require('fs');

exports.handler = (e, ctx) => {

  // taskID用に日付を取得
  // 現在時刻の取得
  var dt = new Date();
  
  // 日本の時間に修正
  dt.setTime(dt.getTime() + 32400000); // 1000 * 60 * 60 * 9(hour)
  // 日付を数字として取り出す
  var year = dt.getFullYear();
  var month = dt.getMonth() + 1;
  var day = dt.getDate();
  var hour = dt.getHours();
  var min = dt.getMinutes();
  // 値が1桁であれば '0'を追加 
  if (month < 10) {
    month = '0' + month;
  }
  if (day < 10) {
    day = '0' + day;
  }
  if (hour < 10) {
    hour = '0' + hour;
  }
  if (min < 10) {
    min = '0' + min;
  }
  // 出力
  var today = year + month + day;

  // エクスポート対象テーブルを取得
  const data = fs.readFileSync('table.csv');
  const parseData = parse(data);

  const exportTables = parseData.reduce((newArr, elem) => {
    return newArr.concat(elem);
  }, []);

  // S3エクスポートを実行
  const rds = new AWS.RDS();
  var params = {
    DBClusterIdentifier: process.env.DBCLUSTER_IDENTIFIER,
  };
  console.log(params);
  rds.describeDBClusterSnapshots(params, function (err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else {
      const response = data['DBClusterSnapshots'];
      const latestSnapshot = response.sort(
        // snapshotを降順で取得
        (a, b) => (a.SnapshotCreateTime?.getTime() ?? 0 < (b.SnapshotCreateTime?.getTime() ?? 0)) ? -1 : 1
        )[0];
      console.log(latestSnapshot);
      const snapshotArn = latestSnapshot?.DBClusterSnapshotArn;
      console.log(snapshotArn);
      const taskID = "export-task" + today ;
      var params = {
        ExportTaskIdentifier: taskID, /* required */
        IamRoleArn: process.env.IAM_ROLE_ARN, /* required */
        KmsKeyId: process.env.KMS_KEY_ID, /* required */
        S3BucketName: process.env.S3_BUCKET_NAME, /* required */
        SourceArn: snapshotArn, /* required */
        ExportOnly: exportTables, /* テーブルを指定する場合はこちらを利用 */
      };
      rds.startExportTask(params, function (err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else console.log(data);           // successful response
      });
    }
  });
}

table.csvで、エクスポートしたい対象のテーブル名を指定することで、対象テーブルのみエクスポートすることが可能です。以下のような記載をします。

データベース名.テーブル名

環境変数の設定

以下の環境変数を設定します。
・DBCLUSTER_IDENTIFIER:エクスポート対象にするDBクラスター名
・ IAM_ROLE_ARN:S3エクスポート用のIAM Role
・KMS_KEY_ID:KMSのキーID
・S3_BUCKET_NAME:エクスポート先のS3名

IAM Roleの修正

Lambdaを作成した際に作成されるIAM Roleに以下のポリシーを追加します。

1.exportタスクの実行とスナップショットを取得する権限を追加

{
     "Version": "2012-10-17",
     "Statement": [
         {
             "Sid": "VisualEditor0",
             "Effect": "Allow",
             "Action": [
                 "rds:StartExportTask",
                 "rds:DescribeDBClusterSnapshots"
             ],
             "Resource": "*"
         }
     ]
 }

2.exportタスクへのPassRoleする権限を追加

S3エクスポートを利用する際にIAM Roleが作成されますので、Lambdaからそちらの権限をPassRoleできるように設定します。

{
     "Version": "2012-10-17",
     "Statement": [
         {
             "Action": "iam:PassRole",
             "Resource": "arn:aws:iam::account_id:role/service-role/Role_Name",
             "Effect": "Allow"
         }
     ]
 }

KMSの所有者に追加

Lambdaからexport用のKMSキーを利用できるように、所有者にLambdaのIAM Roleを追加します。

IAM Role名はLambda作成時に作成されるものを指定しています。

Eventbridgeの作成

Lambdaを作成したので、こちらをEventbrigdeで指定した時間に自動で動かすように設定します。以下のように作成していきます、ルール名は任意で、また関数名は作成したものを指定してください。

毎週金曜朝の7時に実行する設定です。

作成したLambda関数を指定します。あとは指定した時間にS3エクスポートが実行されているか確認します。S3にエクスポートされたファイルが溜まっていくので、S3のライフサイクルを設定して定期的に削除やアーカイブしていくのも良いでしょうね。

最後に

エクスポートを完了したことをEventbrigdeなどで取れるかなと色々と探していたのですが、現時点では見つけられずでした。AWS CLIを使ってエクスポートタスクの状況を確認することもできるのでCodebuildなどであればタスクの状況を定期的に確認して、終了次第に次の処理を実行ということができそうです。ただこのエクスポート処理自体が対象のデータベースによりますが、結構時間がかかったりするので、コスト面を考えるとLambdaでタスクの開始だけを行うというのが良いと思います。またエクスポートが完了するとS3バケットにファイルが出力されるので、S3イベントでそちらを受け取り終了の判定を行うというので問題ないかと思っています。BigQueryへの転送編はまた時間を見て書きたいと思います。