昨今では、ECSやApp Runnerなどを利用してアプリケーションを簡単にリリースすることができるようになっています。また、シンプルなアプリケーションでは、そもそもサーバレスでも十分なケースもあると思います。
これまではECSやApp Runnerなどを使ってみましたが、まだサーバレスなサービスを触ったことがなかったので、今回はAWS LambdaとAPI Gatewayを使ってサーバレスなAPIを作ってみました。
AWS LambdaはFaaSと呼ばれるサービスで、アプリケーションが動作するサーバを用意する必要がありません。開発者はLambdaに実行可能ファイルやコンテナをアップロードするだけで、簡単にサービスを立ち上げることができます。
LambdaではNode.jsをはじめ、Golang、Java、Paythonなどの様々なランタイムが利用できます。また、ラインタイムが提供されていない場合でも、レイヤという機能を使って使いたいライブラリなどのファイルをZIP化してアップロードすることで、Lambda関数内で任意のライブラリを使用することができます。
Lambdaには起動時間と同時実行数に制限があります。起動時間については、1つの実行ごとに15分までとなっています。また、同時実行数については、同一リージョン内で1000までとなっており、これを超えると関数の呼び出しが制限されます(スロットリング)
Lambda単体ではHTTPでアクセス可能なAPIとしてリリースすることはできません。そこでAPI Gatewayと組み合わせてこれを実現します。これはLambdaの最もポピュラーなユースケースの1つです。
作業内容は以下のとおりです。
次から順番に手順を紹介します。
マネジメントコンソールでAWS Lambdaのページを開き、「関数の作成」をクリックします。
作成方法が3種類あり、それぞれ
となっています。
「一から作成」の場合は、ランタイムやアーキテクチャなどを選択してLambda関数を作成します。
「設計図を使用」の場合は、予めAWSが用意したテンプレートに沿ってLambda関数を作成します(S3 Get ObjectsやReturn HTTP Redirect Responseなど)。この場合では使用できるランタイムが「一から作成」の場合と比べて少なくなっています(Golangなどはない)
「コンテナイメージ」の場合は、ECRのイメージURLを指定してLambda関数を作成します。
今回は「一から作成」を選んで以下のように作成しました。
次に、ランタイム設定を編集してハンドラをgreetingにします(ハンドラ名と実行可能ファイル名を同じにする必要がある)。
Lambda関数で実行する実行可能ファイルを作成します。Lambdaで実行可能な関数を作るために、以下のパッケージを予めインストールしておきます。
github.com/aws/aws-lambda-go/lambda
今回はリクエストで名前を渡してレスポンスにその名前への挨拶を返すだけのシンプルな関数を実装します。コードは以下のとおりです。
package main import ( "fmt" "github.com/aws/aws-lambda-go/lambda" ) type GreetingEvent struct { Name string `json:"name"` } type GreetingResponse struct { Message string `json:"message:"` } func greeting(event GreetingEvent) (GreetingResponse, error) { return GreetingResponse{ Message: fmt.Sprintf("Hello %s!!", event.Name), }, nil } func main() { lambda.Start(greeting) }
コードが書けたら以下のようにビルドしてZIP化します。
% GOOS=linux GOARCH=amd64 go build . % zip greeting.zip greeting
マネジメントコンソールに戻って、「コードソース」の「アップロード元」で「.ZIPファイル」を選択して、先程ZIP化したファイルをアップロードします。
アップロードが完了したら、「テスト」タブを開いて、一番下の「イベントJSON」にリクエストのJSONを書いて「テスト」をクリックします。
成功すると以下のようなログが表示されます。
これでLambdaの設定は完了です。
Lambdaの設定ができたら、API GatewayでREST APIを作成します。
「APIを作成」をクリックし、「REST API」の「構築」をクリックし、「REST」、「新しいAPI」をチェックし、「API名」を入力して「APIの作成」をクリックします。
作成したAPIの画面を開いて、「リソース」の「アクション」から「リソースの作成」をクリックします。
「リソース名」を入力して「リソースの作成」をクリックします。
リソースが作成できたら、リソースを選択した状態で「アクション」から「メソッドの作成」をクリックします。
「POST」を選択して「Lambda関数」に先程作成したLambda関数名を記入して、「保存」をクリックします。
作成できると以下のように表示されます。
「クライアント」の「テスト」をクリックし、「リクエスト本文」にJSONを書いて「テスト」をクリックします。
成功するとこのようなログが表示されます。
無事テストが通ったら、APIをデプロイします。
「アクション」の「APIのデプロイ」をクリックし、「デプロイされるステージ」で「default」を選択して「デプロイ」をクリックします。
デプロイに成功すると以下のようにステージが表示されます。
Lambdaに戻って確認してみると、「関数の概要」にAPI Gatewayのトリガーが追加されているはずです。
これで設定はすべて完了です。curlでリクエストしてみると以下のようにレスポンスが返ってくるはずです。
% curl -X POST https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/default/greeting -H 'Content-Type: application/json' -d '{"name":"Taro"}' {"message:":"Hello Taro!!"}
AWS LambdaとAPI Gatewayを組み合わせてサーバレスでAPIを作成してみました。簡単にAPIを作れるのがとても良いですね。他にもCognitoと組み合わせて認証機能を追加したり、RDSやDynamoDBなどを組み合わせたら、かなりの範囲をカバーできそうです。