🐳
AWS CDKでLambda and FFmpegレイヤー環境を構築する
概要
ffmpegをLambdaで動かす機会があった。
手動でFFmpegのLambdaレイヤーを構築する手順については、AWS公式から紹介されている。
この手順をCDKで整備してみたので、紹介したい。
構築するゴールイメージ
- 動画格納用のS3バケット
- 動画のサムネイル作成をするLambda関数
- FFmpegのLambdaレイヤー
成果物
本記事で説明しているコードは以下にある。
環境
terminal
$ sw_vers
ProductName: macOS
ProductVersion: 11.4
BuildVersion: 20F71
$ cdk --version
1.121.0 (build 026cb8f)
CDKプロジェクトの作成
プロジェクト用ディレクトリを作成し、CDKプロジェクトを作成する。
terminal
mkdir lamba-ffmpeg-sample && cd lamba-ffmpeg-sample
cdk init app --language typescript
必要パッケージをインストール
terminal
npm install \
@aws-cdk/aws-s3 \
@aws-cdk/aws-lambda \
@aws-cdk/aws-s3-notifications
FFmpegのバイナリを準備
AWS公式から紹介されている手順と同様に、https://johnvansickle.com/ffmpeg/ からダウンロードする。
terminal
mkdir -p lambda_layer/ffmpeg && cd lambda_layer/ffmpeg
# download
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar xvf ffmpeg-release-amd64-static.tar.xz
# 必要ファイルだけ取り出す
mkdir bin
cp ffmpeg-*-static/ffmpeg bin/
# 不要ファイル削除
rm -rf ffmpeg-*
動作確認用のLamda Functionを作成
ffmpegの動作を検証する、lambda関数を作成する。
terminal
cd (PROJECT_ROOT)
mkdir lambda_function
上記ディレクトリに、以下ファイルを配置する。
function.py
import json
import os
import subprocess
import shlex
import boto3
SIGNED_URL_TIMEOUT = 60
def lambda_handler(event, context):
s3_source_bucket = event['Records'][0]['s3']['bucket']['name']
s3_source_key = event['Records'][0]['s3']['object']['key']
s3_source_basename = os.path.splitext(os.path.basename(s3_source_key))[0]
s3_destination_filename = s3_source_basename + "_thumbnail.jpg"
s3_client = boto3.client('s3')
s3_source_signed_url = s3_client.generate_presigned_url('get_object',
Params={'Bucket': s3_source_bucket, 'Key': s3_source_key},
ExpiresIn=SIGNED_URL_TIMEOUT)
ffmpeg_cmd = "/opt/bin/ffmpeg -i \"" + s3_source_signed_url + "\" -f image2 -ss 1 -vframes 1 -vf scale=400:400:force_original_aspect_ratio=decrease -y -"
command1 = shlex.split(ffmpeg_cmd)
p1 = subprocess.run(command1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
resp = s3_client.put_object(Body=p1.stdout, Bucket=s3_source_bucket, Key=s3_destination_filename)
return {
'statusCode': 200,
'body': json.dumps('Processing complete successfully')
}
Stackを作成
lib/lamba-ffmpeg-sample-stack.ts
を以下のように修正する。
lib/lamba-ffmpeg-sample-stack.ts
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as lambda from '@aws-cdk/aws-lambda'
import * as notifications from '@aws-cdk/aws-s3-notifications';
export class LambaFfmpegSampleStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 動作検証用のS3を作成
const videoBucket = new s3.Bucket(this, 'video-bucket');
// FFmpegのLambdaレイヤーを作成
const ffmegLayer = new lambda.LayerVersion(this, 'ffmpeg-layer', {
layerVersionName: 'ffmpeg',
compatibleRuntimes: [lambda.Runtime.PYTHON_3_8],
code: lambda.AssetCode.fromAsset('lambda_layer/ffmpeg')
});
// Lambda関数を作成
const videoHandler = new lambda.Function(this, 'video-handler', {
functionName: 'video-handler',
runtime: lambda.Runtime.PYTHON_3_8,
handler: 'function.lambda_handler',
code: lambda.AssetCode.fromAsset('lambda_function'),
layers: [ffmegLayer],
timeout: cdk.Duration.seconds(60),
});
// Lambda関数にS3の権限を付与
videoBucket.grantReadWrite(videoHandler);
// S3トリガーでLambdaを起動
videoBucket.addObjectCreatedNotification(
new notifications.LambdaDestination(videoHandler),
{ suffix: '.mp4' }
)
}
}
Deploy
これで準備が出来たのでデプロイを実行する。
terminal
cdk deploy
動作確認
CDKで作成されたS3のバケットに、適当な動画をアップロードする。
1分程で、サムネイルが作成されることが確認出来た。
まとめ
CDKを使って、Lambda and FFmpegレイヤー環境を構築することが出来た。
注意点としては、FFmpegのバイナリは、73Mbyteと大きめなので、リポジトリに含めるかどうかは別途検討が必要になるかと思う。
Discussion