やりたいこと
Lambda関数でlibvipsで画像をリサイズする
Lambda関数はRubyで動かす
画像はS3から取得する
ローカル環境で動作確認もしたい
Dockerfileの用意
libvipsを使う場合そもそもlibvips本体をインストールしないといけません。
今回は、libvipsをインストールしたDockerイメージからLambdaを作成することにしてみました。
FROM amazon/aws-lambda-ruby:latest
# EPELリポジトリを追加
RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# remiレポジトリを追加
RUN yum install -y https://rpms.remirepo.net/enterprise/remi-release-7.rpm
# libvipsとlibvipsを使うために必要なパッケージをインストール
RUN yum install -y install vips make gcc
COPY Gemfile Gemfile.lock ${LAMBDA_TASK_ROOT}
COPY lambda_function.rb ${LAMBDA_TASK_ROOT}
# /usr/local/bundleにGemをインストールする
ENV GEM_HOME=/usr/local/bundle
RUN bundle install
CMD [ "lambda_function.lambda_handler" ]
解説
DockerイメージからLambdaを作成する場合、AWSが提供しているamazon/aws-lambda-ruby
イメージを使います。
次にlibvipsをインストールしたいのですが、CentOS 7やAmazon Linux 2の標準のリポジトリにはlibvipsが用意されていないため、remiリポジトリを使えるようにします。
remiレポジトリを使用するには、先にEPELリポジトリを追加する必要があり、Amazon Linux 2にEPELリポジトリを追加する方法は下記リンク先に記載があります。
Amazon Linux 2 で EPEL レポジトリを有効にするには、次のコマンドを使用します。
[ec2-user ~]$ sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
Gemfileの用意
image_processingをインストールすることで、Rubyからlibvipsを使うことができるのでGemfileに追記します。
source 'https://rubygems.org'
gem 'image_processing'
docker-compose.ymlの用意
ローカル環境で動作確認するためにdocker-compose.ymlファイルも作成しておきます。
ローカルでS3の機能を実現するために今回はminioを使うことにしました。
version: '3'
services:
app:
build: .
image: lambda_libvips_demo
environment:
BUCKET_NAME: local-bucket
AWS_REGION: 'ap-northeast-1'
ports:
- "8080:8080"
tty: true
stdin_open: true
volumes:
- .:/var/task
minio:
image: minio/minio:latest
environment:
MINIO_ROOT_USER: minio_user
MINIO_ROOT_PASSWORD: minio_password
ports:
- 9000:9000
- 9001:9001
volumes:
- minio:/storage
command: ['server', '/storage', '--console-address', ':9001']
mc:
image: minio/mc:latest
depends_on:
- minio
environment:
MINIO_ROOT_USER: minio_user
MINIO_ROOT_PASSWORD: minio_password
entrypoint: >
/bin/sh -c "
mc alias set myminio http://minio:9000 minio_user minio_password;
mc mb myminio/local-bucket;
"
volumes:
minio:
lambda_function.rbの用意
実行する関数です。
実際やるならリサイズしたい画像の情報をeventで渡すのがいいと思いますが今回は簡単のため固定の画像 image.jpg
をリサイズする処理を書いています。
require 'image_processing/vips'
require 'aws-sdk-s3'
Aws.config.update({
credentials: Aws::Credentials.new('minio_user', 'minio_password'),
endpoint: 'http://minio:9000',
force_path_style: true
})
def lambda_handler(event:, context:)
# 画像データ取得
s3_client = Aws::S3::Client.new(:region => 'ap-northeast-1')
key = 'image.jpg'
uploaded_data = s3_client.get_object(:bucket => ENV['BUCKET_NAME'], :key => key).body.read
# 画像リサイズ
uploaded_file = Vips::Image.new_from_buffer(uploaded_data, '')
resized_file_path = ImageProcessing::Vips.source(uploaded_file).resize_to_limit!(200, 200).path
# アップロード実行
s3_resource = Aws::S3::Resource.new()
s3_resource.bucket(ENV['BUCKET_NAME']).object("resize_image.jpg").upload_file(resized_file_path, content_type: "image/jpeg")
end
ローカルでの動作確認
ビルド後docker-compose upコマンドで立ち上げます。
docker-compose build app
docker-compose up
ブラウザでhttp://localhost:9001
にアクセスし、あらかじめ image.jpg
をアップロードしておきます。
別のターミナルを開きcurlコマンドでPOSTすることでLambda関数が動きます。
curl -d '{"payload":"hello world!"}' "http://localhost:8080/2015-03-31/functions/function/invocations"
実行後再びminioを見るとリサイズされた画像がアップロードされていることが確認できると思います。
本番用にlambda_function.rbを修正
AWSで実際Lambda関数を動かすときには Aws.config.update
は不要なので削除しておきましょう。
require 'image_processing/vips'
require 'aws-sdk-s3'
def lambda_handler(event:, context:)
# 画像データ取得
s3_client = Aws::S3::Client.new(:region => 'ap-northeast-1')
key = 'image.jpg'
uploaded_data = s3_client.get_object(:bucket => ENV['BUCKET_NAME'], :key => key).body.read
# 画像リサイズ
uploaded_file = Vips::Image.new_from_buffer(uploaded_data, '')
resized_file_path = ImageProcessing::Vips.source(uploaded_file).resize_to_limit!(200, 200).path
# アップロード実行
s3_resource = Aws::S3::Resource.new()
s3_resource.bucket(ENV['BUCKET_NAME']).object("resize_image.jpg").upload_file(resized_file_path, content_type: "image/jpeg")
end
再ビルド&ECRにpush
docker-compose build app
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com
docker tag lambda_libvips_demo:latest XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/lambda_libvips_demo:latest
docker push XXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/lambda_libvips_demo:latest
ECRでlambda_libvips_demoリポジトリを作成した後に上記コマンドを実行してECRにプッシュします。
S3の作成
S3バケットを作成し、image.jpgファイルをアップロードしておきます。
S3の設定は全てデフォルトでOKです。
Lambda関数を作成
Lambdaの関数の作成でコンテナイメージから作成で、先ほどECRにpushしたコンテナイメージから作成します。
環境変数に作成したS3のバケット名を追加し、Lambdaの実行ロールに AmazonS3FullAccess
を追加します。