サーバーレスに画像リサイズとDB構築。LambdaからS3とRDSを同時に扱うには

LambdaからS3やRDSを操作した時の備忘録です。サーバーレスにS3イベントをフックして画像処理を走らせたり、RDSのMySQLを操作するLambda Functionを作りたいと思いました。

画像アップロートのタイミングでサムネイルを生成させたり、画像検索データベースを自動構築してくれたら非常に楽ですよね。

keyboard

photo by Mr. Alex Garcia - Double Cliche on flickr

Ads

構成図と結論

考えている構成図は以下のようなイメージです。結論を先に言ってしまうと、S3のPutイベントをVPCに置いたLambda functionが受けて、LambdaからRDSに接続、またS3に対してはVPCエンドポイント越しからアクセスする事にしました。

AWS

目次

VPCに置くべきか?

ここに至るまでに躓いたのが、LambdaをVPCへ置くか否かでした。VPCの外に配置したLambdaからはRDSにアクセスできなくなり、VPCに置くと今度は逆にS3へアクセスできなくなります。

各サービス Lambda (No VPC) Lambda on VPC
S3 X
RDS X

S3にアクセスできないのはLambda on VPCがインターネットにアウトバンドすることができない仕様だからです。また、RDSへセキュアにアクセスするためには、EC2からRDSにアクセスする時と同じように、VPCのサブネットからアクセスしたいところです。

従来の回避策

前述の問題を回避するために、いくつか方法が提案されていました。まず最初に、Lambda VPCがサポートされる以前ではRDSを開放(インバウンド 0.0.0.0/0)する方法が紹介されていました。

AWS LambdaでRDS(MySQL)に接続してみた | Qiita
http://qiita.com/Keisuke69/items/cba4b501e91da95188f8

さらに踏み込んで、RDSに安全にアクセスするために、SecurityGroupにLambdaのIPアドレスが追加し、LambdaからセキュアにRDSへアクセスする方法も紹介されていました。

LambdaからセキュアにRDSに接続する | ナレコムAWSレシピ
http://recipe.kc-cloud.jp/archives/7388

また、Lambda VPCからS3にアクセスする手段としてはNAT InstanceまたはNAT gatwayを介して、外部からからS3にアクセスする方法もあるようです。

VPC Lambdaからs3へアクセスする | Qiita
http://qiita.com/ijin/items/94c0bc4b8f6f5e77a591

いずれにしても、構築の手間や維持費用が多く掛かる事がわかりました。

VPC Endpoint for S3を使う

そこで今回はVPCエンドポイントを使うことにしました。VPCエンドポイントを作っておくとAWS網内でS3へのトラフィックを終端できるようになり、Lmabda VPCからS3に接続。もちろんRDSも使えるようになります。VPCエンドポイントについては以下が参考になりました。

AWSでS3を使う場合は必ずVPCエンドポイントも作成しておくクセをつけましょう。| 株式会社ビットクリア
https://www.bitclear.co.jp/vpcendpoint/

NAT Instanceとの違いも分かりやすかったです。VPCからアクセスできるのはいいですね。

S3 VPCエンドポイントを利用するメリット | Qiita
http://qiita.com/SatoHiroyuki/items/b611485b6ec736e9076f

ここで注意点としてはVPC Endpoint for S3のリージョンはVPCを扱うリージョンに制限されてしまいます(VPCに置いたLambdaが東京リージョンならばS3も東京リージョンのみとなる)。あと、aws-sdkからS3に接続する際にはS3認証のVersion4を指定する必要があるそうです。具体的にはsignatureVersionを指定しないとlambdaからのアクセスが拒否されタイムアウトしてしまいます。

VPC Private Network 内の Lambda Function から boto3 で S3 を操作する | Qiita
http://qiita.com/sokutou-metsu/items/47c00bb381e1b103e878#_reference-734313aae611eb61bfe7

ということで

最終的なlambda functionはざっくりと以下のようになりました。

index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
'use strict';

let im = require('imagemagick');
let fs = require('fs');
let mysql = require('mysql');
let aws = require('aws-sdk');
aws.config.update({
region: 'ap-northeast-1'
});

let s3 = new aws.S3({
apiVersion: '2006-03-01',
signatureVersion: 'v4'
});

exports.handler = (event, context, callback) => {
const bucket = event.Records[0].s3.bucket.name;
const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
const params = {
Bucket: bucket,
Key: key
};
s3.getObject(params, (err, data) => {
if (err) {
console.log(err);
callback(err);
} else {
// S3 resize function
// (略)

// RDS
let conn = mysql.createConnection({
host : 'your-db.***.ap-northeast-1.rds.amazonaws.com',
user : 'your-user',
password : 'your-password',
port : '3306',
database : 'your-db'
});
conn.connect();
conn.query('**your query**', (err, rows, fields) => {
if(err){
console.log('[mysql query error] ' + err);
}else{
console.log('[mysql query success] rows:' + JSON.stringify(rows));
}
conn.end(function(err){
console.log('[mysql end] ' + err);
callback(null,rows);
});
});
}
});
};

リサイズ処理とDB処理の順番を考え中です。リサイズ処理は以下が参考になりました。

AWS Lambdaを使ってS3にアップロードされた画像をリサイズする | Qiita
http://qiita.com/awm-kaeruko/items/00d92cf2484405fb5579

Lambdaのコンソール画面ではnode.js 4.3より古いBlue printが削除されてしまった事情から、従来あったimage-processing-serviceが参照できなくなっています。あとQiitaのサンプルをそのまま記述すると無限ループになるので要注意です(^^;)一度タイムアウトまで無限リサイズさせてしまいましたw

最後に

VPC Endpointを活用することで、LambdaからS3やRDSを操作することができるようになりました。roleでアクセスを絞り込んでいけば、安全なものが構築できるかなぁと思っていますが、いかがでしょうか。

Ads
Ads