概要
エンジニアもどき2年目に入りました。色々あって以下を行うLambda関数を作成することになりました。
色々学びがあったので備忘録がわり兼アウトプットのために書くことにしました。
- 特定のページのキャプチャ取得
- 取得したキャプチャをS3に保存
- S3に保存したURLをDyanmoに記録
part2では2. 取得したキャプチャをS3に保存
の実装とデプロイまで行います。
part2での実装内容はこちら
前提
前回(part1)の続きです。part1に引き続き以下の準備は完了している前提です。
前回(part1)の実装内容はこちら
- nodejs
- ServerlessFramework
- yarn
- webpack
- iamのユーザ作成済み
実装作業
1. 準備
ローカルでの動作確認のためにローカルにS3のバケットを作成できるserverless-s3-local
を使用します。
# 追加
yarn add -D serverless-s3-local
続いてserveress.yml
にS3の設定を追加します。
service:puppeteer-captureprovider:# ・・・ 省略 ・・・# テーブル名やバケット名など環境変数environment:# ・・・ 省略 ・・・# 追加1 : バケット名CAPTURE_BUCKET:${self:provider.environment.PREFIX}-capture-bucketiamRoleStatements:# 追加2 : S3の設定-Effect:AllowAction:-'s3:PutObject'-'s3:PutObjectAcl'Resource:'arn:aws:s3:::${self:provider.environment.S3_BUCKET}*'# 追加3 : ローカルでの動作用設定custom:defaultStage:devs3:port:8081directory:.s3cors:false# 追加3 : プラグインplugins:-serverless-webpack-serverless-s3-local# ・・・ 省略 ・・・# 追加4 : リソースの設定resources:Resources:CaptureBucket:Type:AWS::S3::BucketProperties:BucketName:${self:provider.environment.CAPTURE_BUCKET}
ローカルで起動できるか確認します。
sls s3 start -c ./serverless.yml
また、AWSのリソース(S3やDynamoDB)を操作する必要があるので、aws-sdk
を使用します。
# 追加
yarn add -D aws-sdk
Lambdaの実行環境には AWS SDK for JavaScriptが含まれているためdevDependenciesにのみ追加しています。webpack.config.js
の外部依存にaws-sdk
を追加して準備は完了です。
// ・・・ 省略 ・・・target:'node',// 追加externals:['chrome-aws-lambda','aws-sdk'],// ・・・ 省略 ・・・};
2. 実装
前回は取得したキャプチャ画像をローカルに書き出して保存していましたが、Lambdaは実行後、使用されたすべてのリソース(が破棄されてしまうので、S3に保存するように修正します。
// ・・・ 省略 ・・・// 追加1 : S3のインポートimport{config,S3}from'aws-sdk';// 追加2 : S3の設定とオプション(LOCALで実行した際の設定)config.update({region:process.env.AWS_REGION});consts3Options=process.env.LOCAL?{s3ForcePathStyle:true,accessKeyId:'S3RVER',secretAccessKey:'S3RVER',endpoint:newAWS.Endpoint('http://localhost:8081'),}:{};// 追加3 : s3のクライアント/バケット名/アップロード関数consts3=newS3(options);constbucket=process.env.CAPTURE_BUCKET;constputObject=({key,body,contentType,acl})=>{constparams={Bucket:bucket,Key:key,Body:body,ContentType:contentType,ACL:acl,};console.log(params);returns3.putObject(params).promise();};constgetCapture=async(url)=>{// ・・・ 省略 ・・・};exportconstcaptureFunction=asyncevent=>{// ・・・ 省略 ・・・// 修正 : ファイルに書き出しからS3へアップロードするように変更// Before : ファイル書き出し// writeFileSync('/tmp/hoge.jpg', jpgBuf);// After : S3へアップロードtry{awaitputObject({key:'hoge.txt',body:jpgBuf,contentType:'image/jpeg',acl:'public-read',});}catch(error){console.log(error);return{statusCode:500,body:error.message};}return{statusCode:200,body:'キャプチャの取得に成功しました。'};};
注意する点はacl
、つまりアクセスコントロールリストにpublic-read
の設定を忘れるとS3にアップロードはできるもののAccess Deniedとなりリソースにアクセスができなくなってしまいます。
3. 動作の確認
まずはローカル環境での動作の確認です。
LOCAL=true sls invoke local--function captureFunction -c ./serverless.yml
LOCAL=true sls invoke local--function captureFunction --data'{"url":"https://qiita.com/"}'-c ./serverless.yml
実行して 200でレスポンスが帰ってくること、ローカルのバケットにキャプチャ画像が保存されていることを確認します。
バケットに保存されているhode.jpg._S3rver_object
をhoge.jpg
にリネームして開くと確認することができます。
4. デプロイと動作確認
デプロイします。
serverless deploy
実行し200でレスポンスが返ってくることを確認します。
また、AWSのコンソールからS3にアクセスしてバケットの中を確認します。
sls invoke --function captureFunction -c ./serverless.yml
sls invoke --function captureFunction --data'{"url":"https://qiita.com/"}'-c ./serverless.yml
以上でpart2の作業は完了です。
次はS3に保存した画像のURLをDynamoDBに書き出す処理までの実装を行います。
おわりに
- ACLのところで結構引っかかった(Bucketに保存できるもののアクセスできない)
- ローカルでのS3の使い方、ServerlessFrameworkでS3のバケットの作成など色々勉強になった
- 今回は日本語のページのキャプチャは必要なかったので対応していませんが、Lambdaのインスタンスに日本語フォントが含まれておらず、日本語を含むページのキャプチャした際に文字化けが発生します。(フォントを用意して設定する必要がある)