🎄

AWSとSSTで実現する次世代サーバーレス開発

2023/12/26に公開

AWSでサーバーレスなアプリを作りたいとき,どのようなIaCフレームワークを使っていますか?

  • AWS SAM
  • AWS CDK
  • Serverless Framework
  • AWS Amplify

このあたりが代表的だと思います.

最近私が激推ししているIaCフレームワークは SST です.本記事ではSST使ったことがない方に,その魅力を伝えることを目指します.ハンズオンのような形式になっているので,ぜひ実際に手を動かしてみてください.
https://sst.dev/

SSTの特徴

SSTの推しポイントはたくさんありますが,勝手に厳選すると以下の3点になります:

  1. Lambdaをローカルで開発しながらAWSリソースにもアクセスできる(Live Lambda
  2. フロントエンド,バックエンド,インフラストラクチャのすべてをSSTで開発できる
  3. AWS CDK Constructs をすべて利用できる

特に1番目が重要です.Live Lambdaという機能のおかげで,ローカル環境にあるLambdaのコードがまるでAWS上で実行されているような感覚で開発・デバッグできます.さらに開発環境(ローカル)と本番環境(AWS)での挙動の違いが少なくなるというメリットもあります.

SST Getting Started

開発環境をデプロイする

早速SSTでサーバーレスアプリを作ってみます.

まずはSSTプロジェクトのテンプレートをダウンロードし,必要なパッケージをインストールします.ここではプロジェクト名をmy-sst-appとしましたが,もちろん好きな名前で構いません.

npx create-sst@latest my-sst-app
cd my-sst-app
npm install

VSCode等のエディタでディレクトリを開きます.ディレクトリの直下にあるsst.config.tsというファイルを開きます.デフォルトではリージョンがus-east-1に設定されているので,好きなところに書き換えましょう.私はap-northeast-1にしました.

sst.config.ts
import { SSTConfig } from "sst";
import { API } from "./stacks/MyStack";

export default {
  config(_input) {
    return {
      name: "my-sst-app",
-      region: "us-east-1",
+      region: "ap-northeast-1",
    };
  },
  stacks(app) {
    app.stack(API);
  }
} satisfies SSTConfig;

開発環境を起動します.

npm run dev

ステージ名をどうしたいか聞かれますが,特に気にせずEnterを押してデフォルトのままで行きます.デフォルトではユーザー名(私の場合はbe4rr)が開発環境のステージ名になります.

Please enter a name you’d like to use for your personal stage. Or hit enter to use be4rr: 

開発用の環境がAWSにデプロイされます.初回のデプロイには数分かかります.

SST v2.38.7  ready!

➜  App:     my-sst-app
   Stage:   be4rr
   Console: https://console.sst.dev/local/my-sst-app/be4rr
   
   (略)

デプロイが完了すると次のように表示されます.

✔  Deployed:
   API
   ApiEndpoint: https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com

API Gatewayが作成されたことがわかります.npm run devを実行したまま表示されたURLをブラウザなどで開くと,現在の時刻が表示されると思います.

Hello world. The time is 2023-12-23T11:11:39.851Z

何が起こった?

my-sst-appディレクトリに作られたファイルを眺めてみます.

.
├── package-lock.json
├── package.json
├── packages
│   ├── core
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── event.ts
│   │   │   └── todo.ts
│   │   ├── sst-env.d.ts
│   │   └── tsconfig.json
│   └── functions
│       ├── package.json
│       ├── src
│       │   ├── events
│       │   ├── lambda.ts
│       │   └── todo.ts
│       ├── sst-env.d.ts
│       └── tsconfig.json
├── pnpm-workspace.yaml
├── sst.config.ts
├── stacks
│   └── MyStack.ts
└── tsconfig.json

stacks/MyStack.tsにAWSインフラストラクチャが定義されています.

stacks/MyStack.ts
import { StackContext, Api, EventBus } from "sst/constructs";

export function API({ stack }: StackContext) {
  ...()...

  const api = new Api(stack, "api", {
    defaults: {
      function: {
        bind: [bus],
      },
    },
    routes: {
      "GET /": "packages/functions/src/lambda.handler",
      "GET /todo": "packages/functions/src/todo.list",
      "POST /todo": "packages/functions/src/todo.create",
    },
  });
  
  ...()...

  stack.addOutputs({
    ApiEndpoint: api.url,
  });
}

SSTではAWS CDKと同じように「スタック」という単位でインフラストラクチャを定義します.上のコードではAPIというスタックが定義されています.その中でEventBusApiという2つのコンストラクト(AWSリソース)が定義されています.

ここではAPI Gatewayを定義しているApiに注目します.このApiが先ほどのAPIhttps://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.comを定義しています."GET /": "packages/functions/src/lambda.handler"では,APIへのGETリクエストをLambda関数に結びつけています.そのLambda関数の実際の処理はpackages/functions/src/lambda.ts内のhandler関数に記述されています.

ファイルの中身を見ると次のようになっています.APIのURLを開いたときに現在時刻が表示されましたが,その処理がここに定義されていることがわかります.

packages/functions/src/lambda.ts
import { ApiHandler } from "sst/node/api";

export const handler = ApiHandler(async (_evt) => {
  return {
    statusCode: 200,
    body: `Hello world. The time is ${new Date().toISOString()}`,
  };
});

先ほどのnpm run devは,これらのAPI GatewayやLambda関数をAWSにデプロイしていました.

Live Lambda の威力

Lambda関数を編集することで,Live Lambdaの威力を体験してみましょう.

次のようにLambdaを変更します.

packages/functions/src/lambda.ts
export const handler = ApiHandler(async (_evt) => {
  return {
    statusCode: 200,
-   body: `Hello world. The time is ${new Date().toISOString()}`,
+   body: `こんにちは.今の時間は ${new Date().toTimeString()} です.`,
  };
});

ファイルを保存してAPIエンドポイントhttps://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.comを再び開くかブラウザをリロードします.するとLambda関数への変更がすでに反映されていることがわかります.

こんにちは.今の時間は 20:12:04 GMT+0900 (日本標準時) です.

AWS上のAPI GatewayからLambda関数を起動しているのにも関わらず,ローカルでの変更がすぐに反映されるのは驚きです.これがSSTのLive Lambdaです.

Live Lambdaの特徴として,Lambda関数自体はローカル環境に存在しますが,他のリソースはAWSクラウドにデプロイされています.この構成によりAWSクラウド上のリソースがローカルのLambda関数をトリガーすることや,逆にローカルのLambda関数からAWSクラウド上のリソースを操作することが可能です.この機能によってまるでクラウド上のLambda関数を直接編集しているかのような体験が得られます.

本番環境にデプロイ

ここまでは開発環境で作業をしていました.ここでは開発環境で作成したものを本番環境にデプロイしてみます.

本番環境にデプロイする,といっても実際に必要な操作は以下のコマンド1つだけです.

npx sst deploy --stage prod

上のコマンドを実行することで,プロジェクトで定義されたリソースが,開発環境とは完全に独立してデプロイされます.つまり開発環境をデプロイした時とは異なるAPI GatewayやLambda関数が作成されます.

実際,CloudFormationを見てみるとprod-my-sst-app-API[ユーザー名]-my-sst-app-APIの2つのスタックができています.私の場合はprod-my-sst-app-APIbe4rr-my-sst-app-APIができています.

後片付け

ここまでにデプロイした開発環境と本番環境を削除します.

開発環境の削除:

npx sst remove

本番環境の削除:

npx sst remove --stage prod

ちなみにCloudFormationのコンソールから削除することもできます.

参考

最後にSSTを使う際に参考になるリソースを紹介します.

  • SST Docs
    公式ドキュメントがとても丁寧でわかりやすいです.SSTに興味を持ったらまずはGetting StartedExamplesGuideから始めるのがおすすめです.
  • GitHub Issue
  • Discord
    GPTにSSTについて質問できるチャンネルがあります.
  • Web Dev Cody - Youtube
    SSTに限らず,サーバーレスなアプリケーション開発全般の動画を上げているTech系チャンネルです.個人的に好きなので紹介しました.

Discussion