SAMについてまとめと運用の疑問点を整理してみた

## SAM（AWS Serverless Application Model）とは

YAML形式でAWSリソース（Lambda、API Gateway、DynamoDBなど）を定義するIaCツール。
```yaml
Resources:
  HelloFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs22.x
      # 普通のクラウドフォーメーションでAPI Gateway＆Lambdaの構成を書こうとすると色々リソース定義しないといけないがSAMなら少ないコードで書ける
      Events:
        Api:
          Type: Api
          Properties:
            Path: /hello
            Method: get

    MyApi:
        Type: AWS::Serverless::Api
        Properties:
          Name: my-proxy-api
          StageName: dev
          EndpointConfiguration: REGIONAL
```


---

### SAMのインストール方法

下記リンクを参考にCLIインストール  
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html


確認
```bash
sam --version
```
---

### デプロイ方法
```bash
sam build
sam deploy --guided
```

`--guided` は最初だけで、以降は `samconfig.toml` に設定が保存される。

---

### Lambda エイリアスとステージの関連付け
```yaml
Resources:
  HelloFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: hello
      MemorySize: 1024
      Timeout: 10
      Environment:
        Variables:
          TABLE_NAME: !Ref DynamoTable
      Layers:
        - !Ref Layer
      Handler: index.handler
      Runtime: nodejs22.x
      # ここが重要
      AutoPublishAlias: !Ref StageName
      DeploymentPreference:
        Type: AllAtOnce
```
こう書くことで、ステージ別デプロイが可能に。  
API Gateway とのバインドも `StageName` と `AutoPublishAlias` を合わせればOK！

---

### デプロイ後のトラフィック切り替え

- `AWS::Serverless::Function` のリソースで以下のように書けば全部一気に更新、段階的に更新、など設定可能

```yaml
DeploymentPreference:
 Type: AllAtOnce
```

|  Type   |  意味   |
| --- | --- |
|  AllAtOnce   |   一気に新バージョンへ切替  |
|  Canary10Percent5Minutes   |   10%流して5分様子見、問題なければ残り90%  |
|  Linear10PercentEvery1Minute | 1分ごとに10%ずつ段階的に切替 |
|  Linear10PercentEvery10Minutes | 10分ごとに10%ずつ |

---

### 作成したリソースをコンソールから手でいじったらどうなる？
- **上書きされる**。  
ただし次回 `sam deploy` すると **テンプレに定義された内容で再構築される**から注意⚠️

---

### デプロイ前に差分確認できる？
```bash
sam deploy --guided --no-execute-changeset
```
で CloudFormation の差分（change set）を確認できる
本番前チェックにおすすめ！

---

### 環境変数ファイルみたいなものの作り方

- `parameter_overrides` を使って SAM 側に渡す
- samconfig.tomlに以下のように記載することで`sam build --config-env dev`としたときに `[dev.deploy.parameters]` が使われるようになる

```toml
[dev.deploy.parameters]
stack_name = "hello-app"
s3_bucket = "hello-app-sam-artifact-bucket"
s3_prefix = "hello"
region = "us-west-2"
capabilities = "CAPABILITY_NAMED_IAM"
confirm_changeset = true
parameter_overrides = "StageName=dev Prefix=test"

```

### 通常のCloudFormationのリソースも一緒に書ける？

- 書ける

### 組み込み関数について

- !Subとか!Refとかをよく使う
- !Subは変数展開用
    - `FunctionName: !Sub ${Prefix}-test` みたいな感じで使う
- !Refはリソース参照用
    - `RestApiId: !Ref Api` みたいな感じで使う
    - Arnを取得したいときは`RestApiId: !Ref Api.Arn` のように書く

### template.yamlは分割できる？

- 出来ないっぽい？
- シェルスクリプトとかで対応は可能

```bash
#!/bin/bash

OUT_FILE="template.yaml"
BASE_FILE="base.yaml"
PARTIALS=(lambda1.yaml lambda2.yaml)

# base.yaml の Resources以外を抽出
awk '
  BEGIN {in_resources=0}
  /^Resources:/ {in_resources=1; next}
  in_resources==0 {print}
' "$BASE_FILE" > "$OUT_FILE"

echo "Resources:" >> "$OUT_FILE"

# 各パーシャルYAMLからResources配下だけ抽出して追加
for f in "${PARTIALS[@]}"; do
  awk '
    /^Resources:/ {in_resources=1; next}
    in_resources==1 && /^[^ ]/ {exit} # 次のトップレベルきたら終了
    in_resources==1 {print "  " $0}
  ' "$f" >> "$OUT_FILE"
done

```