はじめに・動機
先日、RDS(PostgreSQL)に接続するLambda関数をRubyで実装しようとしたとき、pg gemの動作がうまく動きませんでした。このため、今回はLambda関数をコンテナイメージで動かすことをやってみます。
コンテナイメージを作る
AWSのドキュメントにLambda関数で動くコンテナイメージの作り方が記載されていたのでそれに従います。
ベースイメージとして、public.ecr.aws/lambda/ruby:3.2
を使うのがポイントかと思います。pg gemを使いたいので、関連ライブラリをインストールする必要があります。実際に実装したDockerfile
は以下のようなものになりました。
FROM public.ecr.aws/lambda/ruby:3.2 RUN yum install -y amazon-linux-extras && \ amazon-linux-extras enable postgresql14 && \ yum group install "Development Tools" -y RUN yum install -y postgresql-devel # Copy Gemfile and Gemfile.lock COPY Gemfile Gemfile.lock ${LAMBDA_TASK_ROOT}/ # Install the specified gems RUN bundle config set --local path 'vendor/bundle' && \ bundle install # Copy function code COPY lambda_function.rb ${LAMBDA_TASK_ROOT}/ # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) CMD [ "lambda_function.LambdaFunction::Handler.process" ]
必然的にコンテナイメージも大きくなります。マルチステージビルド化で多少小さくなるかもしれませんが、まずは動作確認のためにこのまま進めます。
コンテナイメージを作っておくと、ローカルで動作確認も取れます。docker run
で動かして、別のターミナルからcurl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
を叩けばOK。今回は、以下のようなdocker-compose.yml
を作成してdocker compose up
で起動して、
version: '3' services: app: build: . image: my_lambda_app:0.0.1 ports: - "9000:8080" environment: PG_HOSTNAME: db PG_USERNAME: "postgres" PG_PASSWORD: "postgres" db: image: postgres:15 ports: - "5432:5432" environment: POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "postgres"
先ほどのcurl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
を叩けば、動作確認も簡単にできました。
CodeBuildでコンテナイメージを作成し、ECRにpushする
次に、Lambda上で動かすことを考えます。CodeBuildでコンテナイメージを作成し、ECRにpushすることを実装します。
AWSのドキュメントにサンプルがあるのでそれをお手本に。
CodeBuildの作成時に、「特権付与」にチェックを入れるのを忘れずに。
また、ポリシーの追加も必要です。こんな感じで。
以下のbuildspec.yml
を作成してビルドを実行します。
version: 0.2 phases: pre_build: commands: - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNTID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com build: commands: - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG . - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNTID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - docker push $AWS_ACCOUNTID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
成功すると、作成していたECRにイメージがpushされています。
コンテナイメージをLambdaで動かす
あとはLambdaで動かします。Lambda作成時に「コンテナイメージ」を選択して、画面の指示通りに指定してあげればOK。
今回は、SELECT * FROM pg_stat_activity
の結果を出力させるものを動かしました。RDSの接続設定をすれば、無事動くことが確認できました。
考察
今回の検証で、一番時間がかかったのはDockerfile
の作成でした。ベースイメージのpublic.ecr.aws/lambda/ruby:3.2
はAmazon Linux 2ですのでgemのビルドに必要な前提ライブラリであるDevelopment Tools
やpostgresql-devel
を特定するのが一番時間がかかりました。特定さえできれば、あとはコピペで良いかなと考えています。
今回はRDS for PostgreSQLに接続することが目的でしたので、postgresql-devel
が前提ライブラリでしたが、RDS for MySQLなどはそれぞれ別の前提ライブラリが必要となることは注意点となります。
コンテナイメージを作ることでローカルでの動作確認が取れるというのは思わぬメリットでした。AWS上での開発も高速とはいえ、ローカルで動作させる速度には敵わないのでこれは大きなメリットかなと思います。