Shogo's Blog

Jan 2, 2021 - 2 minute read - perl

Perl Runtime for AWS Lambda の Docker コンテナ対応を公開しました

いつかやろうと思っていた AWS::Lambdaの Docker コンテナ対応、 年を越してしまったけど、ようやく手を付けました。

使い方

以下の handler.pl を Docker コンテナとして AWS Lambda デプロイする例です。

use utf8;
use warnings;
use strict;

sub handle {
    my $payload = shift;
    return +{"hello" => "lambda"};
}

1;

ビルド済みイメージを使う

Amazon Linux 2 ベースの Perl Runtime 入りイメージをDocker Hub で公開しています。 これをベースにデプロイしたいファイルを追加し、CMD に実行したい関数名を指定するだけ。 簡単ですね。

FROM shogo82148/p5-aws-lambda:base-5.32-paws.al2
COPY handler.pl /var/task/
CMD [ "handler.handle" ]

Docker Hub からのダウンロードに Rate Limit が適用されるようになったので、 同じイメージを Amazon ECR Public Gallery でも公開しました。 こちらを利用することも可能です。

FROM public.ecr.aws/w2s0h5h2/p5-aws-lambda:base-5.32-paws.al2
COPY handler.pl /var/task/
CMD [ "handler.handle" ]

このベースイメージには AWS Lambda Runtime Interface Emulator がインストールされているので、 ビルドすればローカルで動かすこともできます。

$ docker run -p 9000:8080 hello-perl:latest
$ curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

これをそのまま ECR にアップロードすれば・・・

$ aws ecr create-repository --repository-name hello-perl --image-scanning-configuration scanOnPush=true
$ docker tag hello-perl:latest 123412341234.dkr.ecr.sa-east-1.amazonaws.com/hello-perl:latest
$ aws ecr get-login-password | docker login --username AWS --password-stdin 123412341234.dkr.ecr.sa-east-1.amazonaws.com
$ docker push 123412341234.dkr.ecr.sa-east-1.amazonaws.com/hello-perl:latest

AWS Lambda 関数としてデプロイできます。

$ aws --region "$REGION" --profile "$PROFILE" lambda create-function \
    --function-name "hello-perl" \
    --code ImageUri=123412341234.dkr.ecr.sa-east-1.amazonaws.com/hello-perl:latest \
    --handler "handler.handle" \
    --runtime provided.al2 \
    --role arn:aws:iam::xxxxxxxxxxxx:role/service-role/lambda-custom-runtime-perl-role

全部自前でビルドする

Docker コンテナ対応によって、Amazon Linux 以外の Linux を使用可能になりました。 例としてPerl の Docker Official Imagesを使ってみましょう。

FROM perl:5.32-slim-buster
RUN mkdir -p /var/task \
    && apt-get update \
    && apt-get install -y --no-install-recommends gcc libc6-dev \
    && cpanm --notest AWS::Lambda \
    && apt-get purge -y --auto-remove gcc libc6-dev \
    && rm -fr /var/cache/apt/* /var/lib/apt/lists/* \
    && rm -fr ./cpanm /root/.cpanm /tmp/*
COPY handler.pl /var/task/
WORKDIR /var/task
ENTRYPOINT [ "/usr/local/bin/perl", "-MAWS::Lambda::Bootstrap", "-e", "bootstrap(@ARGV)" ]
CMD [ "handler.handle" ]

AWS::Lambda の依存に XS を利用したモジュールが含まれているので、gcc をインストールが必要です。 その分長くなってしまいましたが、App::cpanminusで AWS::Lambda をインストールしているだけです。

エントリーポイントでは AWS::Lambda::Bootstrap を読み込んで、 bootstrap 関数を呼び出せば OK です。

ENTRYPOINT [ "/usr/local/bin/perl", "-MAWS::Lambda::Bootstrap", "-e", "bootstrap(@ARGV)" ]

ちょっとハマったのは /usr/local/bin/perl のように絶対パスを指定する必要があること。 どうやら環境変数の PATH は読んでくれないみたい(?)

あとは ECR にアップロードすれば AWS Lambda 関数としてデプロイできます。

実装

AWS Lambda との連携 API は今までのカスタムランタイムと一緒なので、AWS::Lambda の実装自体はほとんどいじらずに済みました。 イメージの作成と実行が簡単になるよう、ちょっと調整したくらいです。

  • AWS Lambda Runtime Interface Emulator が Lambda-Runtime-Invoked-Function-Arn ヘッダーを返してくれない
    • 必須にしていたのをオプションに変えて対応
  • ENTRYPOINT から直接モジュールを呼べるよう bootstrap をエクスポートするようにした

ECR Public

今回始めて Amazon ECR Public Gallery にイメージを公開してみました。 今までの lambci/docker-lambda ベースのイメージも公開しているので、合わせてご利用ください。 オフィシャルな Docker イメージが提供されるようになったとはいえ、XS を使ったモジュールに依存していて gcc が必要になるケースは結構多いと思います。 そういった場合は、開発ツールがインストールされたイメージを使うのが便利でしょう。

レポジトリの作成には CloudFormation の AWS::ECR::PublicRepository リソースを利用しました。 ここにちょっとハマって、何も考えずに東京リージョンでデプロイしたら、 “Template format error: Unrecognized resource types: [AWS::ECR::PublicRepository]” と怒られてしまいました。 最終的にはバージニア北部(us-east-1) でデプロイすることで解決しました。

ざっとドキュメントを見た感じリージョンの指定はなかったのと、マネージドコンソールではリージョンの切り替えが必要ないので、ちょっと手こずりました。 docker login のコマンドを注意深く見ていなかったら気が付かないままだったでしょう・・・。

aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/w2s0h5h2

まとめ

Perl Runtime for AWS Lambda で Docker コンテナを簡単にデプロイできるようになりました。 一番嬉しいのは Zip ファイルだと 50MB、レイヤー機能を含めても 250MB までのサイズしかデプロイできなかったのが、 10GB まで拡張されたことだと思います。 ぜひ遊んでみてください。

参考