2024年 Serverless Framework v3 から SAM に移行するときに考えたこと、やったこと

# はじめに
「[Serverless Framework の使い方を初心者にも分かりやすく説明する](https://qiita.com/mkin/items/0a82c84df084496544c6)」という記事を書いたのが3年前。当時は Serverless Framework の魅力に心奪われ、Lambda の管理がしやすいなぁと思っていた記憶です。

https://qiita.com/mkin/items/0a82c84df084496544c6

## Serverless Framework の魅力とは何だったか

さて、そもそも何故 3年前に Serverless Framework を魅力に感じたのか。
自分の中では以下の3点でした。

:::note
1. デプロイがしやすい
2. 開発がしやすい
3. 開発環境、ステージング環境、本番環境の切り替えが設定ファイルで完結する
:::

### 1. デプロイがしやすい

`sls deploy` を実行すると ドバドバァ〜っと CloudFormation が関連リソースを作って、Lambdaをデプロイしてくれました。あの感動は忘れません。

### 2. 開発がしやすい

`sls invoke [local]` でデプロイした Lambda を実行できたり、ローカル関数を実行してくれ、ちゃっちゃか開発できました。

### 3. 開発環境、ステージング環境、本番環境の切り替えが設定ファイルで完結する

`sls deploy --stage dev` ...そう！この `stage` オプションの使い方さえ分かってしまえば、 serverless.ts で設定値を好きに変えられました。

## Serverless Framework v3 から v4 へ

私が触っていたのは v3。そして、2023年10月26日に v4 の発表があり有料化いたしました。

（Google 翻訳）
> Serverless Framework CLI V.4+ は無料ですが、年間収益が 200 万ドルを超える組織の場合は有料サブスクリプションが必要です。

https://www.serverless.com/pricing

破れた肌着を着るほど貧乏性な私は、これは うかうかしてられないと代替サービスを探して行き着いたのが SAM でした。Serverless Framework を既に触っていたので、選定ポイントは上述の Serverless Framework の魅力3点を満たせるか？ というシンプルなものでした。

# SAM ってすごい

SAM を知らない私は、まず下記のチュートリアルサイトを見て挨拶しに行きました。サムはいい奴でした。

## よぉ、サム！ SAM のチュートリアルで分かること

もし、15分でも時間があれば、サムに挨拶してみてください。サムがいい奴ってことが分かります。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html

私も改めてチュートリアルやってみたんですが、ざっくり以下のことが分かります。

- テンプレートにだいたい作りたいものが用意されている

<details><summary>テンプレートの一覧</summary>

```bash:テンプレート一覧
Choose an AWS Quick Start application template
    1 - Hello World Example
    2 - Multi-step workflow
    3 - Serverless API
    4 - Scheduled task
    5 - Standalone function
    6 - Data processing
    7 - Hello World Example With Powertools
    8 - Infrastructure event management
    9 - Serverless Connector Hello World Example
    10 - Multi-step workflow with Connectors
    11 - Lambda EFS example
    12 - DynamoDB Example
    13 - Machine Learning
```
</details>

- 設定ファイル: `template.yaml` が `serverless.ts` に相当する
- デプロイ: `sls deploy` が `sam build` `sam deploy` に相当する
- ローカルマシンからデプロイした Lambda を実行できる
- ローカルマシンで変更した内容がデプロイした Lambda と同期できる（自動デプロイ）
- ローカルマシンで Lambda を実行できる
- ローカルマシンで API Gateway を起動できる

すごくないですか？ Serverless Framework に求めていた開発体験の良さが用意されてました。（私が大規模な Lambda を作ってないってのも、ある）

ローカル実行では Docker を使い、実際の Lambda ランタイム上で動かすことができますし、API Gateway もローカルマシンでホストできるのでとても便利ですね。

`sam sync --watch`すれば、デプロイした Lambda とローカルマシンのコードが同期してくれるので、コード修正したら自動で Lambda デプロイしてくれます。これと `sam remote invoke`（リモート実行） を使い回せば実際の AWS 環境での動作確認もはかどります。

## 環境も切り替えられる

Serverless Framework の `stage` に相当するのが `config-env` オプションです。

```bash:config-envオプションで環境ごとの設定を切り替える
# 開発
$ sam build --config-env dev
$ sam deploy --config-env dev

# 本番
$ sam build --config-env prd
$ sam deploy --config-env prd
```

`config-env` オプションの値は、環境ごとのデフォルト値が保存されている `samconfig.toml` に渡り、指定した環境の設定値を参照してくれます。

```toml:samconfig.tomlの一部抜粋
[dev.build.parameters]
template = "template-dev.yaml"

[prd.build.parameters]
template = "template-prd.yaml"
```

```mermaid
flowchart LR
    A[sam build --config-env 環境名 を入力する] --> B[samconfig.toml の指定した環境の設定値を使う]
    B -- 環境名がdev --> C1[template-dev.yaml を参照]
    B -- 環境名がprd --> C2[template-prd.yaml を参照]
```

私たちは環境ごとの template.yaml を用意しましたが、1つの template.yaml の中で Parameter を使って切り替える方法も検討しました。しかし、将来、構成が変わることも考慮して、開発環境が本番環境に影響を与えない形を優先しました。

## GitHub Actions でのデプロイ

（書こうとしたけど、公式リファレンスのまんまでした...とにかく簡単ってこと！）

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/deploying-using-github.html


# 実際に移行してみたときに困ったこと

## 既存の Lambda 関数を使い回すには考慮することが多い

Serverless Framework と SAM はどちらもデプロイに CloudFormation を使います。既存の Lambda は Serverless Framework が生成した CloudFormation スタックから生成されており、タグを見るとそれを確認できます。Lambda 関数名を新旧で合わせておくだけでなく、スタック管理主体が変わることの影響や移行期間の対応方法を考慮する必要があります。
私たちのチームでは、Lambda 含めリソース名を維持する必要性が無かったので、別の関数名で Lambda を作成し直しました。

## SAM の template.yaml に慣れる

SAM の template.yaml は CloudFormation の YAML 構造を拡張したものに近いようです。私たちのチームは IaC に Terraform を使っているので、最初は書きっぷりが分からなかったです。（困ったというより、学べて良かったなという気持ちが多いですが。）

template.yaml を環境ごとに柔軟に切り替えるには、`!Sub` や `!FindInMap` などのシンタックスを使います。それだけ template.yaml の理解も複雑になるのもあり、上述の通り、私たちのチームでは環境ごとにファイルを分割しました。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html

Tagsの設定で困ったので追加記事です↓

https://qiita.com/mkin/items/363cb16b7e35a55f5509

## 既存S3バケットへのイベント追加機能がない

Serverless Framework だと下記のように既存S3のバケットへのイベントをトリガーとしてLambdaを作成できるのですが、SAM には用意されていませんでした。

https://dev.classmethod.jp/articles/serverless-supports-existing-s3/

なので、新規で S3 バケットを用意するか、Lambda デプロイ後に手動でトリガーを設定する必要がありました。

ちなみに、下記の Issue が解決されてたら使えるようになってるのでご確認ください。

https://github.com/aws/serverless-application-model/issues/1020

# おわりに

2024年は Serverless Framework v3 から SAM 移行を経験できました。SAM は移行の選定ポイント3点も満たせており、Serverless Framework を触った方であれば馴染みやすいツールだと思います！

:::note
## SAMの魅力
1. デプロイがしやすい
2. 開発がしやすい
3. 開発環境、ステージング環境、本番環境の切り替えが設定ファイルで完結する
:::

# 付録

## なぜ CDK じゃないか

Lambda をデプロイできるツールには、SAM 以外にも AWS Cloud Development Kit (AWS CDK) があります。しかし、CDK は IaC（インフラをコードで書けるよってやつ）であり、Lambda をデプロイできてもローカル実行はできません。つまり、Lambda 単体で考えると開発しづらくなってしまいます。また、私たちのチームでは IaC に Terraform を使っているので No More IaC でもあります。

## Serverless Framework v4 の変更点

https://www.serverless.com/framework/docs/guides/upgrading-v4

v4 からは AWS プロバイダーに絞っていくんですね。
ますます開発体験が良くなりそうですね。