サーバレスアーキテクチャ

[参考記事](https://codezine.jp/article/detail/8446)

## 定義
EC2のような時間による従量課金サーバーを利用しないアーキテクチャ
（lambda自体はサーバーの上に乗っている）

* EC2の課金システム - 時間制
* lambdaの課金システム - プログラム実行時間(100ms) × 回数  

## メリット
* バッチの実行待機時間、夜間などアクセスが少ない時間帯や期間などを考慮するとコストを最適化できる可能性がある。  
=> インフラに関わる固定コストを変動コストに変えることができる
* 保守管理コストが低減できる  
=> EC2インスタンスへのセキュリティーパッチ更新やログ管理、ヘルスチェックなど


## デメリット・制約
* 開発言語はpython, node, java
* 1回の起動時間は5分以内に制限される（タイムアウトは60秒）
* 同時起動数はリージョンアカウントあたり100回（上限は上げられる）
* ディスクIOの読み書きは/tmp配下に限定され、容量は512MB
* Lambdaファンクションとそれに紐付けるイベントソースは同一のリージョンである必要がある


## 使い所
* アクセス数が少ないサービス（100回/1日など）
* 特定の時間内にのみ行われる処理（メール、push配信などのバッチサーバが担当していた処理）

## 注意点
* lambdaファンクションは実行〜破棄されるまでのデータを保持(永続化)することができないため、ステートレスな実装が必要

## イベントソース
lambdaファンクションの起動トリガーとなるS3などのイベント発生元AWSリソース

### Pushモデル
イベント発生に応じて直接lambdaファンクションを呼び出す形式  

- S3、カスタムイベントが該当  
- イベントの実行順序は順不同  
- リトライは3回まで

### Pullモデル
AWS lambdaがポーリングを行い、自らイベントを取得する形式  

- Amazon DynamoDBとAmazon Kinesisなどが該当  
- イベントは順次実行（ストリームに入ってきた順）  
- リトライは無限（ストリームのデータが期限切れになるまで）

## 権限とポリシーの設定
権限には`Invocation Role`、`Execution Role`の2種があり、それぞれ`Accecc-policy`、`Trust-policy`を設定する必要がある。

また、`Invocation Role`に関しては、Pushモデル, Pullモデル毎に`Accecc-policy`、`Trust-policy`の設定内容が異なる

権限はそれぞれIAMロールとして用意、割り当てることで実現される。
(もしくはcognitoなどの代替認証サービス)

||設定内容|
|---|---|---|---|
|Invocation Role(Push)|イベントソースがLambdaファンクションを起動できる権限を設定|AWS LambdaがストリームからイベントをPullできる権限を設定|
|Invocation Role(Pull)|AWS LambdaがストリームからイベントをPullできる権限を設定|
|Execution Role|Lambdaファンクションに対して必要なAWSリソースへのアクセスを許可する権限|

### Invocation Role
誰がファンクションを実行できるかを決定

#### Pushモデルの場合
イベントソースがLambdaファンクションを起動できる権限を設定する

- Accecc-policy  
Amazon S3に対してlambda:InvokeAsyncを許可する例

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": "*",
      "Action": [ "lambda:InvokeAsync" ]
    }
  ]
} 
```

- Trust-policy  
Amazon S3に対してsts:AssumeRoleの許可を与える例  
（条件として特定のバケットから発信される場合のみAmazon S3がイベント発行するよう制限）

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
          "StringEquals":{
            "sts:ExternalId": "arn:aws:s3:::bucket name"
          }
      }
    }
  ]
}
```

### Invocation Role
#### Pullモデルの場合
AWS LambdaがストリームからイベントをPullできる権限を設定する

- Accecc-policy  
Amazon Kinesisのストリームに対する読み取りとlambda:InvokeAsyncというアクションに対して許可する例

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": "*",
      "Action": [
         "kinesis:ReadStream"]
    }
  ]
}
```

- Trust-policy  
sts:AssumeRoleというアクションをAWS Lambdaにのみ許可する例 

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
          "StringEquals":{
            "sts:ExternalId": "arn:aws:s3:::bucket name"
          }
      }
    }
  ]
}
```

### Execution Role
Lambdaファンクションに対して、必要なAWSリソースへのアクセスを許可する権限を設定する
ファンクションは実行の際、ここで指定されたIAMロールにそってAWSのリソースへのアクセスが許可される。

- Access-policy  
AWS Lambdaに対して、Amazon CloudWatch Logsへのログを書き込みを許可する例

```
{
    "Statement": [
        {
            "Action": [
                "logs:*"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:logs:*:*:*"
        }
    ]
}
```

- Trust-policy

AWS Lambdaがロールを引き受けられるように許可

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```


> IAMロールを作成しているユーザがAWS Lambdaに対してこのロールを引き受けるための権限を渡しているため、ユーザはこれを許可するためにiam:PassRoleというアクションに対して許可されている必要がある

## モニタリング
AWS Lambdaは各Lambdaファンクションの実行を監視しており下記の内容をAmazon CloudWatch内に保存し、後から参照できる。

- メトリクス : リクエスト数、遅延、可用性とエラー率など
- ログ : 実行開始／終了時刻、メモリ使用量や実行時間といったファンクション実行時に実際に消費したリソースに関する内容、その他任意のログ