LocalStackを試してみた

# 背景・目的
昨年、LocalStackというものを知りました。特徴の整理や、簡単な動作を確認してみます。

# まとめ
下記に特徴をまとめます
|特徴|説明|
|:--|:--|
|LocalStackの特徴|AWS アプリケーションをローカルで開発およびテストすることで、開発時間を短縮し、製品の速度を向上できる<BR>不要な AWS の支出を削減し、AWS 開発アカウントを維持する複雑さとリスクを排除する|
|生産性|ローカルで開発とテストを行うことで、開発者が重要な部分に時間と労力を集中できる|
|IAMポリシー|必要に応じて IAM の適用を有効または無効にする<BR>IAM ポリシーをその場で生成し、本番環境に移行する前にポリシーをテストする|
|複雑性の排除|複雑な権限を扱ったり、誰がクラウド アカウントを取得するかを決めたりする必要はない<BR>インフラストラクチャを毎回更新することなく、さまざまなブランチで作業できる|
|時間の節約|インフラストラクチャのデプロイを待つ必要はない<BR>すべてのデータを含む完全なスタックをすばやくロードする|
|リスクの排除|リスクやコストのかからないローカル サンドボックスをセットアップして、開発者を迅速にスタックにオンボードする|

# 概要
下記を基に整理します。

https://www.localstack.cloud/

## Run Locally, Deploy Globally

> Develop and test your AWS applications locally to reduce development time and increase product velocity. Reduce unnecessary AWS spend and remove the complexity and risk of maintaining AWS dev accounts.

- AWS アプリケーションをローカルで開発およびテストすることで、開発時間を短縮し、製品の速度を向上できる
- 不要な AWS の支出を削減し、AWS 開発アカウントを維持する複雑さとリスクを排除する

## Increase Dev Productivity
> Allow your developers to focus their time and effort where it counts by developing and testing locally. Nobody likes setting up sandbox accounts, cleaning up resources or constantly monitoring AWS dev spending.

- ローカルで開発とテストを行うことで、開発者が重要な部分に時間と労力を集中できる
- サンドボックス アカウントの設定、リソースのクリーンアップ、AWS 開発費の継続的な監視は誰も好まない

### No IAM Complication
> Don't worry about IAM policies unless you really want to and enable or disable IAM enforcement however you need it. Have IAM policies generated on the fly and test your policies before hitting production.

- 本当に必要な場合を除き、IAM ポリシーについては心配する必要はない
- 必要に応じて IAM の適用を有効または無効にする
- IAM ポリシーをその場で生成し、本番環境に移行する前にポリシーをテストする


### Reduce Complexity
> No dealing with complex permissions, or deciding who gets a cloud account anymore. Since everything runs locally these concerns disappear. Work across different branches without having to update your infrastructure every time.

- 複雑な権限を扱ったり、誰がクラウド アカウントを取得するかを決めたりする必要はない
- すべてがローカルで実行されるため、これらの懸念はなくなる
- インフラストラクチャを毎回更新することなく、さまざまなブランチで作業できる


### Get Rid of Dead Time
> No need to go grab a cup of coffee waiting for your infrastructure to deploy, load a complete stack with all its data quickly. Hot reload and debug your lambdas locally.
- インフラストラクチャのデプロイを待つ必要はない
- すべてのデータを含む完全なスタックをすばやくロードする
- Lambda をローカルでホット リロードしてデバッグする

### Risk free developer onboarding
> Setup a local no-risk, no-cost sandbox to rapidly onboard developers into your stack. Dev and test your app as you wish, there’s no cloud spend when running locally.

- リスクやコストのかからないローカル サンドボックスをセットアップして、開発者を迅速にスタックにオンボードする
- 必要に応じてアプリを開発およびテストする
- ローカルで実行する場合はクラウド費用は発生しない


## More than just an Emulator
> By emulating cloud services locally, LocalStack enables additional features and workflows that are not feasible on the cloud.

- LocalStack は、クラウド サービスをローカルでエミュレートすることで、クラウドでは実現できない追加の機能やワークフローを実現する

# 実践
## インストール
### localstack-cli
下記を基に試します。

https://github.com/localstack/localstack?tab=readme-ov-file#install

1. BrewでCLIをインストールします
    ```bash
    % brew install localstack/tap/localstack-cli
    ```
1. インストールが成功したか確認します
    ```bash
    % localstack --version
    3.8.1
    % 
    ```

### awslocal

LocalStack で使用するための aws コマンドライン インターフェイスのラッパーである awslocal コマンドです。

下記を基に試します。
1. pipでインストールします
    ```bash
    % pip install awscli-local
    ```

1. インストールが成功したか確認します
    ```bash
    % awslocal --version
    aws-cli/2.17.37 Python/3.11.9 Darwin/23.6.0 exe/x86_64
    % 
    ```

## クイックスタート
### 事前に
localstackは、Dockerを利用してますので事前に起動しておきます。

### スタート
1. 起動します
    ```bash
    % localstack start -d
    
         __                     _______ __             __
        / /   ____  _________ _/ / ___// /_____ ______/ /__
       / /   / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_/
      / /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,<
     /_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_|
    
     💻 LocalStack CLI 3.8.1
     👤 Profile: default
    
    [23:36:49] starting LocalStack in Docker mode 🐳                                                                                                                                                                localstack.py:503
               preparing environment                                                                                                                                                                                bootstrap.py:1283
    [23:36:55] configuring container                                                                                                                                                                                bootstrap.py:1291
               container image not found on host                                                                                                                                                                    bootstrap.py:1272
    [23:37:55] download complete                                                                                                                                                                                    bootstrap.py:1276
               starting container                                                                                                                                                                                   bootstrap.py:1301
    [23:37:58] detaching                                                                                                                                                                                            bootstrap.py:1305
    % 
    ```

1. localstack上の各サービスのステータスを確認します
    ```bash
    % localstack status services
    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
    ┃ Service                  ┃ Status      ┃
    ┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
    │ acm                      │ ✔ available │
    │ apigateway               │ ✔ available │
    │ cloudformation           │ ✔ available │
    │ cloudwatch               │ ✔ available │
    │ config                   │ ✔ available │
    │ dynamodb                 │ ✔ available │
    │ dynamodbstreams          │ ✔ available │
    │ ec2                      │ ✔ available │
    │ es                       │ ✔ available │
    │ events                   │ ✔ available │
    │ firehose                 │ ✔ available │
    │ iam                      │ ✔ available │
    │ kinesis                  │ ✔ available │
    │ kms                      │ ✔ available │
    │ lambda                   │ ✔ available │
    │ logs                     │ ✔ available │
    │ opensearch               │ ✔ available │
    │ redshift                 │ ✔ available │
    │ resource-groups          │ ✔ available │
    │ resourcegroupstaggingapi │ ✔ available │
    │ route53                  │ ✔ available │
    │ route53resolver          │ ✔ available │
    │ s3                       │ ✔ available │
    │ s3control                │ ✔ available │
    │ scheduler                │ ✔ available │
    │ secretsmanager           │ ✔ available │
    │ ses                      │ ✔ available │
    │ sns                      │ ✔ available │
    │ sqs                      │ ✔ available │
    │ ssm                      │ ✔ available │
    │ stepfunctions            │ ✔ available │
    │ sts                      │ ✔ available │
    │ support                  │ ✔ available │
    │ swf                      │ ✔ available │
    │ transcribe               │ ✔ available │
    └──────────────────────────┴─────────────┘
    % 
    ```

## API Gatewayのチュートリアル
下記を元に試します。

https://docs.localstack.cloud/user-guide/aws/apigateway/


1. 専用のディレクトリを作成します
    ```bash
    % mkdir api-gateway
    % cd api-gateway 
    ```


### Lambda関数の作成
API Gateway とLambdaを統合するため、事前にLambdaを作成します。

1. ディレクトリを作成します
    ```bash
    % mkdir lambda
    % cd lambda 
    % 
    ```

1. 下記のjsファイルを作成します
下記のコードは、ステータスコードと文字列を返すだけのものです。

    ```js
    'use strict'
    
    const apiHandler = (payload, context, callback) => {
        callback(null, {
            statusCode: 200,
            body: JSON.stringify({
                message: 'Hello from Lambda'
            }),
        }); 
    }
        
    module.exports = {
        apiHandler,
    }
    ```

1. 作成したjsファイルをzipに圧縮します
    ```bash
    % zip function.zip lambda.js 
      adding: lambda.js (deflated 32%)
    % 
    ```

1. localstackにアップロードします
    ```bash
    % awslocal lambda create-function \
    --function-name apigw-lambda \
    --runtime nodejs16.x \
    --handler lambda.apiHandler \
    --memory-size 128 \
    --zip-file fileb://function.zip \
    --role arn:aws:iam::000000000000:role/apigw 
    ```

1. できました
    ```bash
    % awslocal lambda list-functions   
    {
        "Functions": [
            {
    ・・・・
                },
                "LoggingConfig": {
                    "LogFormat": "Text",
                    "LogGroup": "/aws/lambda/apigw-lambda"
                }
            }
        ]
    }
    ```

### API Gatewayの作成
#### REST APIの作成
1. 下記のコマンドを実行し、REST APIを作成します
    ```bash
    % awslocal apigateway create-rest-api --name 'API Gateway Lambda integration'
    {
        "id": "{rest-api-id}",
        "name": "API Gateway Lambda integration",
        "createdDate": "2025-01-03T19:52:10+09:00",
        "apiKeySource": "HEADER",
        "endpointConfiguration": {
            "types": [
                "EDGE"
            ]
        },
        "disableExecuteApiEndpoint": false,
        "rootResourceId": "{parent-id}"
    }
    % 
    ```

1. リソースを確認します
    ```bash
    % awslocal apigateway get-resources --rest-api-id XXXXXX
    {
        "items": [
            {
                "id": "XXXXXX",
                "path": "/"
            }
        ]
    }
    % 
    ```

#### リソースを作成
1. 下記のコマンドをリソースを作成します
    ```bash
    % awslocal apigateway create-resource \
    --rest-api-id {rest-api-id} \
    --parent-id {parent-id} \
    --path-part test 
    {
        "id": "{resource-id}",
        "parentId": "{parent-id}",
        "pathPart": "test",
        "path": "/test"
    }
    % 
    ```

#### メソッドを統合
##### GET メソッドを追加
1. 下記のコマンドにより、作成したLambdaとAPI Gatewayを統合します
    ```bash
    % awslocal apigateway put-method \     
    > --rest-api-id {rest-api-id} \
    > --resource-id {resource-id} \
    > --http-method GET \
    > --request-parameters "method.request.path.somethingId=true" \
    > --authorization-type "NON"
    {
        "httpMethod": "GET",
        "authorizationType": "NON",
        "apiKeyRequired": false,
        "requestParameters": {
            "method.request.path.somethingId": true
        }
    }
    % 
    ```
##### メソッドの統合
1. 下記コマンドでメソッドに統合します
    ```bash
    % awslocal apigateway put-integration \
    > --rest-api-id {rest-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:apigw-lambda/invocations \
    > --passthrough-behavior WHEN_NO_MATCH
    {
        "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:apigw-lambda/invocations",
        "passthroughBehavior": "WHEN_NO_MATCH",
        "timeoutInMillis": 29000,
        "cacheNamespace": "r0hxyhbgql",
        "cacheKeyParameters": []
    }
    % 
    ```

#### デプロイメントの作成
1. 下記のコマンドで、APIの新しいデプロイメントを作成します
    ```bash
    % awslocal apigateway create-deployment \
    > --rest-api-id pif4goi5zc \
    > --stage-name dev
    {
        "id": "{deployment-id}",
        "createdDate": "2025-01-03T20:31:05+09:00"
    }
    % 
    ```

### 動作確認
1. curlで確認します。表示されました
    ```bash
    % curl -X GET http://{rest-api-id}.execute-api.localhost.localstack.cloud:4566/dev/test
    {"message":"Hello from Lambda"}%                                                        % 
    ```

1. ブラウザでも確認します。次のURL「http://localhost:4566/_aws/execute-api/{rest-api-id}/dev/test」を指定します。表示されました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/5d38b364-6e6b-0526-1ca1-2b216b71ee62.png)

# 考察
今回、localstackを試しました。ローカルでAWS環境を作成し動作確認できるので、開発サイクルの短縮化に効果があると感じました。また、AWSコストも気にせず試せるのも良い点です。

今後も継続的に、試して理解を深めていきたいと思います。


# 参考

https://www.localstack.cloud/

https://github.com/localstack/localstack

https://github.com/localstack/awscli-local

https://github.com/localstack-samples/localstack-pro-samples/tree/master/iam-policy-enforcement