大量のファイルをgzipしたものをS3に配置したいニーズがあって、非力な手元のマシンで一旦gzipしてから転送するよりはLambdaにやらせたらいいのではないか?ということでやってみました。
- 以下のようなLambda functionを設置
- 大きなファイル(数十MB以上)を扱う場合はtimeoutをデフォルトの3秒から伸ばす。メモリも128MBでは足りないことがあるので512MBなど
- S3の読み書き権限があるIAM Roleを設定
- S3のイベント通知でLambda functionをkick
aws s3 sync
で大量のファイルを同期してもアップロードが終わったファイルから順番に処理が走るので、同期が終わった数秒後にはgzipされたファイルが生成されている状態になります。
var aws = require('aws-sdk');
var zlib = require('zlib');
exports.handler = function(event, context) {
var bucket = event.Records[0].s3.bucket.name;
var key = event.Records[0].s3.object.key;
if ( key.match(/\.gz$/) ) {
context.succeed(key + ' already gzipped');
return;
}
console.log('starting gzip ' + bucket + '/' + key);
var s3 = new aws.S3();
var gzStream = s3.getObject({ Bucket: bucket, Key: key }).
createReadStream().pipe(zlib.createGzip());
var s3obj = new aws.S3({ params: { Bucket: bucket, Key: 'gz/' + key + '.gz' }});
s3obj.upload({Body: gzStream}).
send(function(err, data) {
context.done(err, data);
});
};
streamを使うと、一旦テンポラリファイルに保存して変換してアップロードしなくても、S3からダウンロードしながらgzipしつつアップロードに回せて便利ぽい。