LoginSignup
2
5

More than 1 year has passed since last update.

RDS Proxy 経由で MySQL にアクセスするLambdaを、VPC内で実行

Last updated at Posted at 2022-06-24

はじめに

RDS Proxy 経由で MySQL にアクセスするLambdaをVPC内で実行させましたので、手順をまとめます。

スクリーンショット 2022-06-23 22.00.58.png

RDS Proxyの作成

RDS Proxyは、以前作成した記事がありますので、こちらを参考にしてください。

private subnetにLambdaを作成

設定

  • IAMロール

    • AWSLambdaENIManagementAccessを付与します.これによってVPC上でLambdaが実行できます。
  • タイムアウト時間

    • 30秒にします。実行に数秒かかります。
  • 環境変数

    • RDS_HOSTNAME:proxyのライターエンドポイント
    • RDS_DB_NAME:データベース名
    • RDS_USERNAME:ユーザー名
    • RDS_PASSWORD:パスワード
  • VPC

    • private subnetに設置
    • sgの設定は以下の通り
設定 タイプ ポート ソース
Lambda All All 0.0.0.0/0
Proxy MySQL/Aurora 3306 LambdaのSG
Aurora MySQL/Aurora 3306 ProxyのSG

mysqlモジュール

Lambdaは、Nodejsを使用します。

mysqlモジュールを使用するため、ローカルでmysqlモジュールをインストールします。

LambdaLayerでアップロード

$ mkdir nodejs
$ cd nodejs
$ tree
.nodejs
├── package-lock.json
└── package.json

// package name以外はデフォルトにしました
$  npm init -y

$ npm install mysql

$ tree
.nodejs
├── node_modules
├── package-lock.json
└── package.json

$ cd ..

$ zip -r nodejs.zip nodejs

nodejsフォルダごとzip化すること。

zip化したnodejs.zipをLambdaLayerにアップしましょう。

具体的なアップロード方法は、以前作成した記事を参考にしてください

Lambdaに直接アップロード

LambdaLayerを使用しない場合、以下のように作成します。

$ mkdir nodejs
$ cd nodejs
$ tree
.nodejs
├── package-lock.json
└── package.json

// package name以外はデフォルトにしました
$  npm init -y

$ npm install mysql

$ touch index.js

$ tree
.nodejs
├── index.js
├── node_modules
├── package-lock.json
└── package.json

$ zip -r nodejs.zip *

nodejs.zipをLambdaにアップロードします
スクリーンショット 2022-11-04 12.56.40.png

Lambdaのコード

const hostname = process.env.RDS_HOSTNAME;
const databaseName = process.env.RDS_DB_NAME;
const password = process.env.RDS_PASSWORD;
const user_name= process.env.RDS_USERNAME;

const mysql = require('mysql');

const beginTransaction = (connection) => {
  return new Promise((resolve, reject) => {
    connection.beginTransaction((err) => {
      if (err) {
        reject(err);
      } else {
        resolve();
      }
    });
  });
};
const query = (connection, statement, params) => {
  return new Promise((resolve, reject) => {
    connection.query(statement, params, (err, results, fields) => {
      if (err) {
        reject(err);
      } else {
        resolve(results, fields);
      }
    });
  });
};
const commit = (connection) => {
  return new Promise((resolve, reject) => {
    connection.commit((err) => {
      if (err) {
        reject(err);
      } else {
        resolve(err);
      }
    });
  });
};
const rollback = (connection, err) => {
  return new Promise((resolve, reject) => {
    connection.rollback(() => {
      reject(err);
    });
  });
};

exports.handler = async (event) => {
  // console.log('event:', JSON.stringify(event, null, 2));

  const connection = mysql.createConnection({
    host: hostname,
    user: user_name,
    password: password,
    database: databaseName,
  });

  const now = new Date().toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' });
  const sql = 'INSERT INTO database_table (title, created_at) VALUES (?, ?);';
  const inserts = ['test', now];

  try {
    await beginTransaction(connection);

    const results = await query(connection, sql, inserts);
    console.log(results);

    await commit(connection);
  } catch (err) {

    await rollback(connection);
    throw err;
  }
};

今回は、database_tableというテーブルに、タイトルと作成日時を登録してみました。
'INSERT INTO databaseTable (title, created_at) VALUES (?, ?);'

mysqlの使用メソッド

  • createConnection
    • mysqlと接続します
  • beginTransaction
    • トランザクションを開始します
  • query
    • クエリを実行します
  • commit
    • トランザクション中のデータ処理を確定します
  • rollback
    • トランザクション中のデータ処理を取り消され、トランザクション実行前の状態に戻りトランザクションを終了します。

モジュールを作成し、LambdaLayerで共通ライブラリ化

beginTransactionquerycommitrollbackの4つは、モジュールにして、LambdaLayerで共通ライブラリ化してもよいです。

beginTransaction.js
module.exports = (connection) => {
  return new Promise((resolve, reject) => {
    connection.beginTransaction((err) => {
      if (err) {
        reject(err);
      } else {
        resolve();
      }
    });
  });
};
query.js
module.exports = (connection, statement, params) => {
  return new Promise((resolve, reject) => {
    connection.query(statement, params, (err, results, fields) => {
      if (err) {
        reject(err);
      } else {
        resolve(results, fields);
      }
    });
  });
};
commit.js
module.exports = (connection) => {
  return new Promise((resolve, reject) => {
    connection.commit((err) => {
      if (err) {
        reject(err);
      } else {
        resolve(err);
      }
    });
  });
};
rollback.js
module.exports = (connection, err) => {
  return new Promise((resolve, reject) => {
    connection.rollback(() => {
      reject(err);
    });
  });
};

こちらの記事を参考にしました。

$ tree
.
└── node_modules
    ├── beginTransaction.js
    ├── commit.js
    ├── query.js
    ├── rollback.js
    ├── package-lock.json
    └── package.json

先程と同様に、nodejsをzip化し、アップロードします。

Lambdaのコード

const hostname = process.env.RDS_HOSTNAME;
const databaseName = process.env.RDS_DB_NAME;
const password = process.env.RDS_PASSWORD;
const user_name= process.env.RDS_USERNAME;

const mysql = require('mysql');
const beginTransaction = require('beginTransaction');
const commit = require('commit');
const query = require('query');
const rollback = require('rollback');

exports.handler = async (event) => {
  // console.log('event:', JSON.stringify(event, null, 2));

  const connection = mysql.createConnection({
    host: hostname,
    user: user_name,
    password: password,
    database: databaseName,
  });

  const now = new Date().toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' });
  const sql = 'INSERT INTO databaseTable (title, created_at) VALUES (?, ?);';
  const inserts = ['test', now];

  try {
    await beginTransaction(connection);

    const results = await query(connection, sql, inserts);
    console.log(results);

    await commit(connection);
  } catch (err) {

    await rollback(connection);
    throw err;
  }
};

mysql2

2022.07.23 更新
mysql2モジュールの方がコード量が少ないため、こちらをおすすめします

参考

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5