既存の Web フレームワークを Lambda に組み込む方法として Lambda Web Adapter というのがあります。
その仕組みですが、API Gateway などの統合先から受信したイベントをフレームワークの手前にある Lambda Web Adapter のエントリポイントが HTTP リクエストに変換して、フレームワークに渡してくれる、というイメージで良さそうです。
公式の実装例では、Node.js であれば Next.js と Express.js が対応していますが、HTTP であればどのようなフレームワークも動作するはずです。
今回はこれを使って Remix アプリをサーバーレス化してみました。既に作ったものは GitHub にあげてあります。
CDKの準備
デプロイの方法は CDK にしました。init で新しいプロジェクトを作成しておきます。
$ cdk --version
2.148.0 (build e5740c0)
$ cdk init app --language typescript
今回は HTTP リクエストを受け付けるので、API Gateway と統合します。Stack は以下からお借りしました。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
import * as apigw from 'aws-cdk-lib/aws-apigatewayv2';
import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
export class MyLambdaStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const handler = new lambda.DockerImageFunction(this, 'Handler', {
code: lambda.DockerImageCode.fromImageAsset('./my-remix', { // Remix アプリケーションのディレクトリ名とする
platform: Platform.LINUX_AMD64,
}),
memorySize: 256,
timeout: cdk.Duration.seconds(30),
});
new apigw.HttpApi(this, 'Api', {
apiName: 'MyLambdaRemix',
defaultIntegration: new HttpLambdaIntegration('Integration', handler),
});
}
}
Remixアプリケーションの作成
CDK のプロジェクトルートで Remix アプリを作成します。
$ npx create-remix@latest
Remix アプリのルートに Dockerfile を作成します。Remix に対応した Dockerfile を作成したことがなかったので、以下を参考にそれっぽく書いてみました。
FROM node:22-bookworm-slim AS base
FROM base AS deps
RUN mkdir /app
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM base AS builder
RUN mkdir /app
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NODE_ENV production
RUN npm run build
FROM base AS runner
# lambda-web-adapter
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.5.0 /lambda-adapter /opt/extensions/lambda-adapter
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 remix
RUN mkdir /app
WORKDIR /app
RUN chown remix:nodejs ./
USER remix
COPY --from=builder --chown=remix:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=remix:nodejs /app/build ./build
COPY --from=builder --chown=remix:nodejs /app/public ./public
COPY --from=builder --chown=remix:nodejs /app/package.json /app/package-lock.json ./
ENV NODE_ENV production
ENV PORT 3000
EXPOSE 3000
CMD ["npm", "run", "start"]
ここでは Lambda Web Adapter のために難しい記述をする必要はありません。ローカルでも ECS でも動くコンテナイメージであれば、Lambda Web Adapter で動作するようです。
追記が必要なのは Lambda の extension を追加するというところのみです。
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.5.0 /lambda-adapter /opt/extensions/lambda-adapter
また、デフォルトでは 8080 でポートを Listen しているので、変更する場合は PORT を指定します。
ENV PORT 3000
デプロイ
CDK のルートディレクトリでデプロイを実行します。
$ cdk deploy
管理コンソールから API Gateway の画面を確認すると、作成した API Gateway のエンドポイントが作成されています。
デフォルトのエンドポイントの URL をクリックして Remix アプリの画面が表示されていれば OK です。