Go EchoサーバーをLambda Web Adapter + SAM + Lambda Function URLsで公開する
背景
Goで作ったWebアプリケーションをLambdaで動かす方法を調べていた際にAWS Lambda Web Adapterという技術の存在を知りました。
AWS Lambda Web Adapterを使えば様々なWebアプリケーション・フレームワークで構築されたwebアプリをLambdaで動かすことができます。(Express.js、Flask、Laravel、Next.js、...etc.)
公式のExamplesに載っていないRuby on RailsなどのWebアプリケーション・フレームワークもLambdaで動かせると推測できます。
Runtime埋め込み系のAdapterというのもいくつか存在するようですが、それを使うデメリットとLambda Web Adapterを使う場合のメリットはこちらのスライドがとても参考になりました。
今回は、GoのWebアプリケーション・フレームワークであるEchoで作った簡易的なサーバーアプリをAWS Lambda Web AdapterとSAM(serverless-application-model)を使ってLambda Function URLs (関数URL)で公開してみました。
私が作成したコードはGitHubでテンプレートリポジトリとして公開しています。
自分が調査した際はAWS Lambda Web Adapterの公式ExamplesでGinを使ったサンプルやZennの記事でFiberを使ったサンプルを見つけることはできましたが、Echoを使ったサンプルを見つけることができなかったのでこうして記事として公開することにしました。
手順・解説
1. Echoサーバーの構築
EchoでWebアプリケーションを構築します。
今回は簡単にlocalhost:8000/へアクセスしたらHello!
と表示されるだけのアプリを構築しました。
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.GET("/", hello)
e.Logger.Fatal(e.Start(":8000"))
}
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello!")
}
2. Dockerfileを作成
DockerfileはLambda Web Adapterの公式Examplesで公開されているginのDockerfileを参考にしました。
FROM golang:1.23-alpine AS build_base
RUN apk add --no-cache git
WORKDIR /app
COPY . .
RUN go mod download
RUN GOOS=linux CGO_ENABLED=0 go build -o bootstrap ./app
FROM alpine:3.9
RUN apk add ca-certificates
# Lambda Web AdapterをDockerイメージで使用するために必要なのはこの1行を追加するだけです
COPY /lambda-adapter /opt/extensions/lambda-adapter
COPY /app/bootstrap /app/bootstrap
ENV PORT=8000 AWS_LWA_ASYNC_INIT=true
EXPOSE 8000
CMD ["/app/bootstrap"]
Lambda Web Adapterはデフォルトで8080番ポートをWebアプリがリッスンしていると想定しています。
そのため、8080番ポート以外を使用したい場合は環境変数PORT
かAWS_LWA_PORT
で任意のポート番号を指定する必要があります。
しかし、Lambda実行環境でWebアプリは非rootユーザーとして実行されるため1024以下のポート番号をリッスンすることはできません。
また、3000番と9001番もポートとして利用することは避けた方が良さそうです。
3000番は、CloudWatch Lambda Insight extensionが使用し、9001番はLambda Runtime APIが使用するためです。
以下の環境変数はなくても問題ありません。
AWS_LWA_ASYNC_INIT=true
Lambda関数が10秒以内に初期化を完了できなかった場合、Lambdaは関数を再起動し、初期化の料金を請求します。
Lambda Web Adapterは、この10秒間の初期化時間を有効に使って初期化の再起動を回避するために非同期初期化をサポートしています。
この機能を有効にすると、最大9.8秒の準備完了チェックを行い、それまでにWebアプリの準備が完了しなかったらLambdaサービスに初期化が完了したことを通知し、ハンドラ内で準備完了チェックを継続します。
この機能はデフォルトで無効になっていますが、環境変数AWS_LWA_ASYNC_INIT
またはASYNC_INIT
をtrueに設定することで有効にできます。
3. SAMのtemplate.yamlを作成
Lambda Function URLsを使うにあたって、Lambda Web Adapterの公式Examplesで公開されているnextjs-response-streamingのtemplate.yamlを参考にしました。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for Go's Echo Web application.
Globals:
Function:
Timeout: 5
MemorySize: 128
Resources:
GoEchoAppFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: app/
PackageType: Image
Architectures:
- x86_64
FunctionUrlConfig:
AuthType: NONE
Metadata:
DockerTag: v1
DockerContext: .
Dockerfile: Dockerfile
Outputs:
GoEchoAppFunctionOutput:
Description: "Go's Echo App Function ARN"
Value: !GetAtt GoEchoAppFunction.Arn
GoEchoAppFunctionUrlOutput:
Description: "Go's Echo App Function URL"
Value: !GetAtt GoEchoAppFunctionUrl.FunctionUrl
FunctionUrlConfigのAuthTypeをNONEに設定しているため、誰でもアクセス可能なURLとして公開されます。
5. SAM CLIでビルド
$ sam build
Building codeuri: /Pathto/go-echo-lambda-function-url-template runtime: None architecture: x86_64 functions: GoEchoAppFunction
Building image for GoEchoAppFunction function
Setting DockerBuildArgs for GoEchoAppFunction function
Step 1/13 : FROM golang:1.23-alpine AS build_base
~ 省略 ~
Successfully tagged goechoappfunction:v1
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
6. SAM CLIでデプロイ
$ sam deploy
~ 省略 ~
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
2024-08-24 21:45:24 - Waiting for stack create/update to complete
CloudFormation events from stack operations (refresh every 5.0 seconds)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS AWS::CloudFormation::Stack go-echo-app User Initiated
UPDATE_IN_PROGRESS AWS::Lambda::Function GoEchoAppFunction -
UPDATE_COMPLETE AWS::Lambda::Function GoEchoAppFunction -
UPDATE_COMPLETE_CLEANUP_IN_PROGRESS AWS::CloudFormation::Stack go-echo-app -
UPDATE_COMPLETE AWS::CloudFormation::Stack go-echo-app -
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CloudFormation outputs from deployed stack
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key GoEchoAppFunctionUrlOutput
Description Go's Echo App Function URL
Value https://xxx.lambda-url.ap-northeast-1.on.aws/
Key GoEchoAppFunctionOutput
Description Go's Echo App Function ARN
Value arn:aws:lambda:ap-northeast-1:000000000000:function:go-echo-app-GoEchoAppFunction-XXXXXXXX
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - go-echo-app in ap-northeast-1
7. 動作確認
$ curl https://xxx.lambda-url.ap-northeast-1.on.aws/
Hello!%
8. リソースの削除
$ sam delete
その他参考にした資料
Discussion