LocalStackを試してみた

## はじめに
AWS を勉強のために触りたいが、課金が怖くてなかなか試せない。
そういった方向けに、ローカル開発環境でAWSサービスを実行できるのが、LocalStack です。

今回は、LocalStackを使って簡単なAPIをデプロイしてみようと思います。

## 前提条件
docker（docker compose コマンドを実行できること）を使用できる状態にしておいてください。

## 下準備
### AWS CLIのインストール
```
$ sudo apt  install awscli
```


### プロファイルの設定
```
$ aws configure --profile localstack

AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: us-east-1
Default output format [None]: json
```

### LocalStackのclone
```
$ git clone https://github.com/localstack/localstack.git
$ cd localstack
```

※私の環境では、エラーになったため、docker-compose.yml に以下を記載した。
```
environment:
- LAMBDA_DOCKER_NETWORK=host
```

### LocalStackの起動
```
docker-compose up -d
```

## Lambdaのデプロイ
### 1. サンプルファイルの準備


```python:Lambda.py
import json

def lambda_handler(event, context):
    return {
        'statusCode': '200',
        'body': json.dumps('Hello LocalStack API'),
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
            },
    }
```

### 2. zipにする
```
$ zip lambda.zip lambda.py
```

### 3. Lambda作成
```
$ aws lambda create-function \
  --function-name test-api-lambda \
  --runtime python3.8 \
  --handler lambda.lambda_handler \
  --memory-size 128 \
  --zip-file fileb://lambda.zip \
  --role arn:aws:iam::000000000000:role/lambda-role \
  --profile localstack \
  --region us-east-1 \
  --endpoint-url=http://localhost:4566
```

以下については、ダミーで問題ありません。
```
--role arn:aws:iam::000000000000:role/lambda-role
```
ただし、 
```
--role test
```
のようにすると、エラーとなるため、以下の形式にする必要があります。
```
--role arn:aws:iam::xxx:role/xxx
```

### 4. Lambdaの確認
```
$ aws --endpoint-url=http://localhost:4566 lambda list-functions --profile localstack
```
この時点で Lambdaが作成できているかどうか確認します。


## API Gatewayデプロイ
### 1. APIの作成
```
$ aws apigateway create-rest-api --name 'Sample API' --endpoint-url=http://localhost:4566

# 結果
{
    "id": "xxx",
    "name": "Sample API",
    "createdDate": "2023-04-25T10:17:35+09:00",
    "apiKeySource": "HEADER",
    "endpointConfiguration": {
        "types": [
            "EDGE"
        ]
    },
    "disableExecuteApiEndpoint": false
}
```
 
### 2. ルートリソース ID取得
```
$ aws apigateway get-resources --rest-api-id {api-id} --endpoint-url=http://localhost:4566

# 結果
{
    "items": [
        {
            "id": "xxx",
            "path": "/"
        }
    ]
}
```
`{api-id}` は **1. APIの作成** で取得できるidを使用する

### 3. 子リソースを追加
```
$ aws apigateway create-resource --rest-api-id {api-id} \
  --parent-id {parent-id} \
  --path-part sample \
  --endpoint-url=http://localhost:4566

# 結果
{
    "id": "xxx",
    "parentId": "xxx",
    "pathPart": "sample",
    "path": "/sample"
}
```
`{parent-id}` は **2. ID取得** で取得できるidを使用します。

### 4. GETメソッドを参照できるように設定
```
$ aws apigateway put-method \
  --rest-api-id {api-id} \
  --resource-id {resource-id} \
  --http-method GET \
  --authorization-type "NONE" \
  --endpoint-url=http://localhost:4566

# 結果
{
    "httpMethod": "GET",
    "authorizationType": "NONE",
    "apiKeyRequired": false
}
```
`{resource-id}` は **3. 子リソースを追加** で取得できるidを使用します。

### 5. API Gateway と Lambda の設定
```
$ aws apigateway put-integration \
  --rest-api-id {api-id} \
  --resource-id {resource-id} \
  --http-method GET \
  --type AWS_PROXY \
  --integration-http-method POST \
  --uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:test-api-lambda/invocations \
  --passthrough-behavior WHEN_NO_MATCH \
  --endpoint-url=http://localhost:4566

# 結果
{
    "type": "AWS_PROXY",
    "httpMethod": "POST",
    "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:000000000000:function:test-api-lambda/invocations",
    "requestParameters": {},
    "passthroughBehavior": "WHEN_NO_MATCH",
    "cacheNamespace": "ui91214dss",
    "cacheKeyParameters": []
}
```

### 6. API デプロイ
```
$ aws apigateway create-deployment \
  --rest-api-id {api-id} \
  --stage-name dev \
  --endpoint-url=http://localhost:4566

# 結果
{
    "id": "xxx",
    "createdDate": "2023-04-25T10:32:39+09:00"
}
```

### 実行確認
```
$ curl http://localhost:4566/restapis/{api-id}/dev/_user_request_/sample
```

### うまくいかない時
APIが作成されているか確認してみてください。
```
$ aws apigateway get-rest-apis --endpoint-url=http://localhost:4566

$ aws apigateway get-resources --rest-api-id {api-id} --endpoint-url=http://localhost:4566 
```


## LocalStackを使用してみて
### メリット
- 動作確認のたびにAWSにデプロイする手間が省ける
- 動作確認の都度課金を心配しなくて良い
- 何かをまず試してみる時に便利

### デメリット
- コンソールで設定ができない（CLIに慣れていないと効率は落ちそう）
- Community 版（無料）だと使えないサービスもある

## 参照URL
https://localstack.cloud/company/

https://github.com/localstack/localstack