何をしようとしたか
Lambda上で動画や画像のメタデータ取得するためにExifToolのRubyラッパーツールを導入しました。 しかし、ExifToolをLambda上で実行するには一筋縄ではいかなかったので、その解決方法をまとめてみます。
環境
- AWS Lambda
- Ruby3.2
- serverless framework
ExifToolをRubyで扱うために以下のgemを使用しました。
発生した問題:Exiftoolの実行ファイルが存在しないと怒られる
READMEを参考にGemfile内にexiftool_vendoredを追加した後、
gem 'exiftool_vendored'
以下のコマンドで必要なgemを指定パスにインストールしました。
bundle install --path
Exiftoolを使用して動画や画像のメタデータを取得するコードを記述します。
# sample code require 'exiftool_vendored` exiftool = Exiftool.new("tmp/test.jpg").to_hash # 画像の縦横の長さを取得 width = exiftool[:width] height = exiftool[:height]
serverless frameworkを用いてLambdaにデプロイし、実際にLambdaを実行すると、以下のようなExiftool::ExiftoolNotInstalled
エラーが発生します。
Exiftool::ExiftoolNotInstalled "/var/task/vendor/bundle/ruby/3.2.0/gems/exiftool-1.2.4/lib/exiftool.rb:60:in `initialize'" ... ... ...
該当するソースコードを参照するとcmd
の中身が空である場合ExiftoolNotInstalled
エラーになっているようです。
# I'd like to use -dateformat, but it doesn't support timezone offsets properly, # nor sub-second timestamps. cmd = "#{self.class.command} #{exiftool_opts} -j -coordFormat \"%.8f\" #{escaped_filenames} 2> /dev/null" json = `#{cmd}`.chomp raise ExiftoolNotInstalled if json == ''
Exiftool.command
でExiftoolの実行ファイルパスを出力してみましたが、以下のように実行ファイルパスが返ってきますし、実行ファイルはLambdaにアップロードしたファイル群にも含まれています。
"/var/task/vendor/bundle/ruby/3.2.0/gems/exiftool_vendored-12.68.0/bin/exiftool"
しかし、Exiftool.exiftool_installed?
を実行するとfalse
が返ってくる謎の状態となっていました。
原因
ExifToolは、Perlライブラリであり実行環境にPerlがインストールされていないといけません。すなわち、Lambdaの実行環境(ランタイムがRubyの場合)にはデフォルトでPerlが入っていかなったため上記のエラーが発生していました。
ExifTool is a platform-independent Perl library plus a command-line application for reading, writing and editing meta information in a wide variety of files.
そのため、ExifToolを実行するにはLambda上にPerlをインストールする必要があります。
解決方法
今回は、Lambda Layerを使ってPerlとExiftoolのレイヤーを作成しました。レイヤーの作成方法は以下のブログを参考にしました。
上記のブログと異なるのは、デプロイするリージョンはTokyoリージョンなので、Tokyoリージョンのパブリックレイヤー(arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2
)を使用しました。
serveless.yml
には対象のhandlerにlayersを追加すればOKです。
handler: handler.main layers: - arn:aws:lambda:ap-northeast-1:445285296882:layer:perl-5-38-runtime-al2-x86_64:2 # public layer - arn:aws:lambda:ap-northeast-1:<account_id>:layer:exiftool:1 # custom layer
そして、ExifToolを実行するために参照するパスをExiftool.command
で指定しておきます。
# sample code require 'exiftool_vendored` #exiftoolはperlが必要なためlambda layer上のexiftoolを指定 Exiftool.command = '/opt/bin/perl /opt/bin/exiftool' exiftool = Exiftool.new("tmp/test.jpg").to_hash # 画像の縦横の長さを取得 width = exiftool[:width] height = exiftool[:height]
この状態でLambdaをデプロイ&実行すれば、問題なく画像のメタデータを取得することができました。