ffmpeg を Docker Lambda で使う方法
はじめに
動画処理を行う際、ffmpeg は非常に強力なツールです。 S3 PUT をトリガー Lambda を起動させて動画や音声のフォーマット変換もよくあるユースケースでしょう。
しかし、Lambda (python) で ffmpeg を使う際には、pip install や yum install が使えないため Lambda レイヤーや Docker Lambda を利用する必要があります。
この記事では Docker Lambda で ffmpeg をインストールする方法、注意点、デプロイ方法について説明します。
Lambda で ffmpeg をインストールするためのオプション
ffmpeg を AWS Lambda で使うためには、大きく分けて2つの方法があります。
- Lambda Layer を使う
- Docker Image Lambda を使う
今回は、Docker Image Lambda を選択しました。
理由は、利用経験があるのと、CDK で DockerImageFunction を使ったデプロイをしたいためです。
最新の Lambda ベースイメージは Amazon Linux 2023
2023 年 11 月から、最新の Lambda Docker Image は、 Amazon Linux 2023 を利用することになりました。
Amazon Linux 2023 で利用しているパッケージ管理ツールは yum ではなく dnf になりました。また、Lambda の Amazon Linux 2023 ベースのイメージは microdnf を利用します。
Dockerfile はその影響も反映しています。
Dockerfile
以下は、ffmpeg をインストールするための Dockerfile です。
FROM public.ecr.aws/lambda/python:3.12
RUN microdnf install -y tar gzip xz
RUN curl -O https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
tar -xJf ffmpeg-release-amd64-static.tar.xz && \
mv ffmpeg-*/ffmpeg /usr/local/bin/ && \
mv ffmpeg-*/ffprobe /usr/local/bin/ && \
rm -rf ffmpeg-*
COPY main.py ./
CMD ["main.lambda_handler"]
Dockerfile では、以下の手順で ffmpeg をインストールしています。
- curl コマンドで ffmpeg の静的ビルド版をダウンロード
- tar コマンドでダウンロードしたアーカイブを解凍
- 解凍した ffmpeg バイナリを /usr/local/bin/ に移動
- 不要になったファイルを削除
Python Lambda ファンクションの作成と実行
この例では、S3 PUT OBJECT のイベントをトリガーに、Lambda が mp4 から m4a に変換しています。
やっていることは、S3 PUT イベントから、ソースバケットとキーを取得してファイルを Lambda の /tmp 領域にダウンロードする。ffmpeg でフォーマット変換をして上で、Output の S3バケットにアップロードしています。
import os
import boto3
import subprocess
from urllib.parse import unquote_plus
s3_client = boto3.client('s3')
def lambda_handler(event, context):
source_bucket = event['Records'][0]['s3']['bucket']['name']
key = unquote_plus(event['Records'][0]['s3']['object']['key'])
download_path = f'/tmp/{os.path.basename(key)}'
output_path = f'/tmp/{os.path.splitext(os.path.basename(key))[0]}.m4a'
output_bucket = '{your_output_bucket}'
s3_client.download_file(source_bucket, key, download_path)
convert_mp4_to_m4a(download_path, output_path)
s3_client.upload_file(output_path, output_bucket, os.path.basename(output_path))
def convert_mp4_to_m4a(input_file, output_file):
command = ['ffmpeg', '-i', input_file, '-vn', '-acodec', 'copy', output_file]
subprocess.run(command, check=True)
ephemeral storage (/tmp)
Lambda の ephemeral storage (/tmp) に上限があります。
デフォルトでは 512 MB に設定されていますが、最大 10GB までいけるようになってます。
大きいファイルを処理する必要があるときには Lambda の ephemeral storage 設定も忘れずに行ってください。
デプロイ
私の場合、インフラを CDK でデプロイしていますので参考までにコードを貼ります。
- DockerImageCode を利用して直接 Dockerfile があるディレクトリを指定したらローカルでビルドしてデプロイしてくれます。
- Platform を AMD64 を指定することで Macbook で ARM のチップを使っていても x86 にビルドします。
- 5 分の Timeout を設定
- Memory Size を 512 MB に設定
- Lambda のアーキテクチャを x86 に設定
- ephemeralStorageSize を 4GB に設定
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
// ...
const convertToAudio = new lambda.DockerImageFunction(this, 'convertToAudio', {
functionName: `${resourceName}-convertToAudio`,
code: lambda.DockerImageCode.fromImageAsset('./{your_code_directory}',{ platform: Platform.LINUX_AMD64 }),
timeout: cdk.Duration.seconds(300),
memorySize: 512,
architecture: lambda.Architecture.X86_64,
role: lambdaRole,
ephemeralStorageSize: cdk.Size.mebibytes(4096)
});
まとめ
AWS Lambda で ffmpeg を Docker Lambda を使ってインストールする方法について書きました。ご参考になれますと幸いです。
Discussion