Lambda関数をRuby コンテナイメージを作って動かしてみた

[Increments × cyma (Ateam Inc.) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/increments-cyma) の21日目は、Increments株式会社の @kiitan が担当します

## はじめに

Amazon Web Services（AWS）は、オンラインで開催中の年次イベント「AWS re:Invent 2020」で、[AWS Lambdaのコンテナサポートを発表](https://aws.amazon.com/jp/blogs/news/new-for-aws-lambda-container-image-support/)しました。要するにECRリポジトリにPushしたイメージをLambda関数で使うことができるようになったよってことでした。そこで早速触ってみました．

## 作るもの
 S3に動画をアップロードされると gif 作成してS3にアップロードしてくれるLambda関数を作っていきます．


## 実装

今回のファイル構成は以下のようになります．

``` binbash
├── Dockerfile
├── Gemfile
├── Gemfile.lock
└── app.rb
```

app.rb はS3がから動画を取得してgifに変換してまたアップロードしてあげるだけ．
Lambdaのお作法でファイルを保存する場合は `tmp/` 以下でないと書き込み権限がないのでそこだけ注意が必要です．

``` app.rb
require 'aws-sdk-s3'
require 'streamio-ffmpeg'

module LambdaFunction
  class Handler
    def self.process(event:, context:)
      s3_client = Aws::S3::Client.new(
                           :region => ENV['REGION'],
                           :access_key_id => ENV['ACCESS_KEY'],
                           :secret_access_key => ENV['SECRET_ACCESS_KEY']
                          )
      input_bucket = event['Records'][0]['s3']['bucket']['name']
      input_key = event['Records'][0]['s3']['object']['key']
      file_name = input_key.split("/").last
      file_path = "/tmp/#{file_name}"

      # S3からアップロードされた動画を取得し /tmp/ に保存する
      movie_file = s3_client.get_object(:bucket => input_bucket, :key => input_key).body.read
      File.write(file_path, movie_file)

      # ffmpeg で動画を読み込み gif に変換する
      movie = FFMPEG::Movie.new(file_path)
      # 開始6秒間を切り取って gif　に変換する
      options = {frame_rate: '10', duration: '00:00:6.000'}
      movie.transcode("#{file_path}.gif", options)

      # S3 の gif/ 以下に作成した gif をアップロードする
      movie_object = s3_client.put_object({ 
        :bucket => input_bucket,
        :key => "gif/#{file_name}.gif",
        :body => File.new("#{file_path}.gif"),
      })
    end
  end
end
```

``` Gemfile
source 'https://rubygems.org'

ruby '2.7.2'

gem 'streamio-ffmpeg'
gem 'aws-sdk'
```

次に Dockerfile に関してですが，ベースイメージはどんなものでも利用できる訳ではなくLambda用のLambda Runtime APIが実装されている必要があります．

<!-- ECR Public gallery に [Lambda ruby用のコンテナ](https://gallery.ecr.aws/lambda/ruby) -->

今回は `amazon/aws-lambda-ruby:2.7` をベーズイメージとして利用していきます．
ベースイメージ以外は気をつけることは特になくffmpeg をダンロード配置してgem をインストールするだけのいたってシンプルなDockerfileになります．

``` DockerFile
FROM amazon/aws-lambda-ruby:2.7

RUN yum -y install wget tar xz xz-devel
RUN wget https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz \
      && tar Jxvf ./ffmpeg-git-amd64-static.tar.xz \
      && cp ./ffmpeg*amd64-static/ffmpeg /usr/local/bin/ \
      && cp ./ffmpeg*amd64-static/ffprobe /usr/local/bin/ 
COPY Gemfile Gemfile.lock ./
RUN bundle install --path vendor/bundle
COPY app.rb ./

CMD ["app.LambdaFunction::Handler.process"]
```

## ECRへpush
ECRへpushは難しいことはなくリポジトリを作成をしてリポジトリ画面のプッシュコマンドを表示に丁寧に書かれているので迷うことはないと思います．

![スクリーンショット 2020-12-18 3.12.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316631/3fb55afa-22fd-5cf2-8eea-e3de4e6c7682.png)

1. 認証トークンを取得し、レジストリに対して Docker クライアントを認証します。AWS CLI を使用します.

```
aws ecr get-login-password --region REGION | docker login --username AWS --password-
stdin XXX.dkr.ecr.XXX.amazonaws.com
```

2. 以下のコマンドを使用して、Docker イメージを構築します．

```
docker build -t ffmpeg-lambda .
```

3. 構築が完了したら、このリポジトリにイメージをプッシュできるように、イメージにタグを付けます．

```
docker tag ffmpeg-lambda:latest XXX.dkr.ecr.XXX.amazonaws.com/ffmpeg-lambda:latest
```

4. 以下のコマンドを実行して、新しく作成した AWS リポジトリにこのイメージをプッシュします．

```
docker push XXX.dkr.ecr.XXX.amazonaws.com/ffmpeg-lambda:latest
```


## Lambda関数の作成
Lambdaを作っていきましょう．
コンテナイメージを選択して先ほど作成したコンテナイメージを指定してすれば作成は完了です．

![スクリーンショット 2020-12-14 3.08.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316631/95d47e59-6caf-d21a-350c-b49e27e6d794.png)

あとはいつも通りにトリガーを作成設定する
![スクリーンショット 2020-12-14 3.37.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316631/48a0edca-70b9-f11f-2afc-f756dea39d9a.png)

このまま実行するとデフォルトのタイムアウト設定が3秒になっているため失敗していまいます．
基本設定からタイムアウトの時間を伸ばす必要がありました．

![スクリーンショット 2020-12-18 3.36.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316631/981125cd-4d02-c212-5853-f01e809ec14a.png)

S3に動画をアップロードして gif ができていれば完成です！

## 感想
感想としてはすごく簡単に実装が完了しました．

また従来のzipパッケージのアップロードが最大250MBと比べてイメージサイズが10GBまで許可されるようになったりと今までより柔軟になりました．
yumなどでインストールができるようになるので利用可能なシーンの幅が広がったように思いました．

## 最後に

[Increments × cyma (Ateam Inc.) Advent Calendar 2020](https://qiita.com/advent-calendar/2020/increments-cyma) の22日目は、
株式会社エイチームの @o93 が担当します！