メインコンテンツまでスキップ

Lambda Web Adapter と Prisma を利用する際の注意点

· 約10分
Yusuke Wada

Lambda Web Adapter を利用することで、 コンテナイメージとして実装した Web システムを簡単に Lambda で動かすことができるようになります。
この Lambda Web Adapter を利用して、 TypeScript の ORM ツールである Prisma を使用する際に注意すべきポイントがありましたので、そちらをご紹介します。

Lambda Web Adapter について

Lambda Web Adapter とは、開発者が使い慣れた Web フレームワークをほぼそのまま AWS Lambda 上で実行することができるツールです。
このツールを使うことで、コンテナ用に実装した Web アプリに変更を加えることなく、Lambda 上で実行させることができます。

Lambda Web Adapter については、弊チームメンバーが記載した builders.flash の記事にて具体的な使い方や性能面など詳しく紹介されていますので、こちらをご覧ください。

Prisma について

Prisma とは、Node.js の ORM ツールです。
TypeScript に対応しており、型安全なデータベース操作、自動補完機能による効率の良いコーディングなどを実現することができます。

アーキテクチャ図

アーキテクチャ図

Lambda には、コンテナイメージで実装した以下の Web アプリをデプロイしています。

  • ベースイメージ:node:18.14-bullseye-slim
    • Prisma を動作させるために必要なので、Dockerfile 内で openssl をインストールしています。
    • RUN apt-get -y install openssl
  • Web フレームワーク:Express

Lambda Web Adapter と Prisma を利用する際の注意点

Lambda 関数のアーキテクチャ不一致による実行エラー

こちらは、Prisma とは直接関係のないものとなりますが、ハマりやすいポイントのためご紹介します。

Lambda 関数には、arm64 アーキテクチャと x86_64 アーキテクチャの2種類が用意されています(参考)。
Lambda 関数で利用するアーキテクチャとコンテナイメージのアーキテクチャが一致していない場合は、exec format error というエラーが発生し実行できません。
Docker を利用してコンテナイメージをビルドする際は、--platform オプションを利用してアーキテクチャを一致させるようにしてください(参考)。

AWS CodeBuild を利用してコンテナイメージをビルドする際の注意点

CodeBuild にはビルド用環境のイメージが用意されています。
コンテナイメージをビルドする際は、以下のイメージを選択いただければそれぞれのプラットフォームでビルドすることができます。

  • arm64 の場合は、aws/codebuild/amazonlinux2-aarch64-standard:2.0
  • x86_64の場合は、aws/codebuild/amazonlinux2-x86_64-standard:4.0 または、aws/codebuild/standard:6.0

arm64 でビルドを行いたい場合は、以下について注意が必要です。
aws/codebuild/amazonlinux2-aarch64-standard:2.0 にプリインストールされている Node.js のバージョンは 10.24.1 と非常に古いものになっています(参考)。
これでは、2023年03月 現在よく使われている v16, v18 を利用して開発を行なっていた場合に、CodeBuild 内で npm ci コマンドの実行に失敗してしまいます(注意:v16 は 2023-09-11 EOL 予定)。
※ v15 以上の Node.js は lockfileVersion が 3 であるため、pakage-lock.json の互換性がなくなり、npm ci コマンドが失敗します(参考)。
そのため、Node.js をアップグレードしたカスタムイメージを利用するか、buildspec にて Node.js のアップグレードを行う必要があります。

Prisma と OpenSSL の互換性エラー

Prisma が DB アクセスする仕組み

OpenSSL 互換性エラーの話に入る前に、Prisma が DB にアクセスする仕組みの一部を簡単にご説明します。
Prisma は、Prismaエンジン と呼ばれるバイナリを利用して DB にアクセスをします。
この中には Query エンジンというものが含まれており、この Query エンジンは DB へのクエリを実行するために利用されます。

この Query エンジンは、デフォルトでは Node-API ライブラリとしてロードされ、Node.js 上で実行されます。
Node-API ライブラリとしてロードした場合は、オーバヘッドを最小限にすることができます。
もう1つのアプローチとして、バイナリをサイドカープロセスとして起動することで、Node.js に依存しない形で Query エンジンを利用することもできます。
こちらの詳細については、Prisma の公式ドキュメントPrisma エンジンのGitHub をご確認ください。

Prisma で OpenSSL の互換性エラーが発生するパターン

Node-APIライブラリとしてQueryエンジンを利用した場合に、プラットフォームと Node.js の組み合わせによって、OpenSSL の互換性エラーが発生してしまいます。

Node.js は OpenSSL 1.1.1 の脆弱性対応として、v17 から OpenSSL3 へ移行されました(参考)。 Node.js v17 以降では、OpenSSL1 系で実装されたプログラムとの互換性問題が発生し、エラーが発生してしまう場合があります(参考)。

Linux の Prisma エンジンのバイナリは OpenSSL に依存しているのですが、そこで Node.js と プラットフォーム側の OpenSSL のバージョンに違いがあると互換性エラーが発生してしまいます。
こちらを見ていただきますとわかります通り、Prisma エンジンはごく一部の Linux ディストリビューションを除き、OpenSSL1 系に依存しています。
上記の OpenSSL1 系に依存したプラットフォームをベースイメージにしたコンテナイメージで v17 以上の Node.js を実行すると、Prisma がエラーとなり実行することができません。
そのため、ローカルマシン(Windows や Mac)の Docker 上で動作していたものが、Lambda 上では実行できないという状態になってしまいます。

互換性エラーの解消方法

上記で説明した通り、この互換性エラーは Node.js と Prisma エンジンのバイナリとで OpenSSL のバージョンが異なるために発生しています。
そのため、Prisma エンジンを Node-API ライブラリとしてロードせずに、バイナリをサイドカープロセスとして Node.js と切り離して実行すれば、エラーを解消することができます。
こちらの設定を行うことで、エンジンタイプを binary に変更することができます。

Prisma では RDS Proxy を利用するメリットがない

こちらの話題は、Lambda Web Adapter とは直接関係のない話題となりますが、 Lambda + RDS(Aurora)の構成の場合に、コネクションを効率的に管理するために RDS Proxy を利用するケースがあるかと思います。
しかし、Prisma を利用している場合は、RDS Proxy がコネクションをピン留め(コネクションが固定化されて、他のクライアントから再利用できなくなる)してしまいます。
そのため、Prisma を利用している場合は RDS Proxy を利用するメリットがないと Prisma の公式ドキュメントに記載がされています。

Prisma is compatible with AWS RDS Proxy. However, there is no benefit in using it for connection pooling with Prisma due to the way RDS Proxy pins connections:

引用:https://www.prisma.io/docs/guides/deployment/deployment-guides/caveats-when-deploying-to-aws-platforms#aws-rds-proxy

Prisma を利用するとピン留めが発生する理由

RDS Proxy を利用している場合、多重化によって予期せぬ動作が発生する可能性がある場合に、コネクションがピン留めされます。
そして、このコネクションがピン留めされる原因の1つに、Prepared statements を利用してSQLを発行するというものがあります。

The proxy pins the session to the current connection in the following situations where multiplexing might cause unexpected behavior:

  • Any statement with a text size greater than 16 KB causes the proxy to pin the session.
  • Prepared statements cause the proxy to pin the session. This rule applies whether the prepared statement uses SQL text or the binary protocol.

引用:https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/rds-proxy-managing.html#rds-proxy-pinning

Prisma は Prepared Statement を利用して SQL を発行する仕様であるため、RDS Proxy を利用すると必ずピン留めが発生します。

Because Prisma uses prepared statements for all queries, you won't see any benefit when using RDS Proxy with Prisma.

引用:https://www.prisma.io/docs/guides/deployment/deployment-guides/caveats-when-deploying-to-aws-platforms#aws-rds-proxy

まとめ

以上、Lambda Web Adapter と Prisma を利用する際の注意点でした。
Lambda Web Adapter と Prisma はどちらも便利なツールです。
皆さんもぜひ使ってみてください。