LoginSignup
0
0

Dockerイメージから作成したLambdaで画像リサイズ処理を行う

Last updated at Posted at 2023-11-30

やりたいこと

Lambda関数でlibvipsで画像をリサイズする
Lambda関数はRubyで動かす
画像はS3から取得する
ローカル環境で動作確認もしたい

Dockerfileの用意

libvipsを使う場合そもそもlibvips本体をインストールしないといけません。
今回は、libvipsをインストールしたDockerイメージからLambdaを作成することにしてみました。

Dockerfile
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に追記します。

Gemfile
source 'https://rubygems.org'
gem 'image_processing'

docker-compose.ymlの用意

ローカル環境で動作確認するためにdocker-compose.ymlファイルも作成しておきます。
ローカルでS3の機能を実現するために今回はminioを使うことにしました。

docker-compose.yml
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 をリサイズする処理を書いています。

lambda_function.rb
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をアップロードしておきます。
スクリーンショット 2023-12-01 0.40.22.png

別のターミナルを開きcurlコマンドでPOSTすることでLambda関数が動きます。

curl -d '{"payload":"hello world!"}' "http://localhost:8080/2015-03-31/functions/function/invocations"

実行後再びminioを見るとリサイズされた画像がアップロードされていることが確認できると思います。
スクリーンショット 2023-12-01 1.05.12.png

本番用にlambda_function.rbを修正

AWSで実際Lambda関数を動かすときには Aws.config.update は不要なので削除しておきましょう。

lambda_function.rb
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にプッシュします。

スクリーンショット 2023-12-01 1.21.38.png

S3の作成

S3バケットを作成し、image.jpgファイルをアップロードしておきます。
S3の設定は全てデフォルトでOKです。
スクリーンショット 2023-12-01 1.29.59.png

Lambda関数を作成

Lambdaの関数の作成でコンテナイメージから作成で、先ほどECRにpushしたコンテナイメージから作成します。
環境変数に作成したS3のバケット名を追加し、Lambdaの実行ロールに AmazonS3FullAccess を追加します。

スクリーンショット 2023-12-01 1.32.14.png
スクリーンショット 2023-12-01 1.34.14.png

Lambda関数を実行

テスト実行するとS3にリサイズされた画像がアップロードされていることが確認できると思います。
スクリーンショット 2023-12-01 1.36.28.png

スクリーンショット 2023-12-01 1.38.05.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0