LocalStack のセットアップ（Docker Compose使用）

## このエントリについて

- しばらく前に、好きに使えるAWS環境をローカルにエミュレートできるとのことで色々試しました。その後はしばらく違う仕事をしていましたが、当時のメモが残っていたので、それらの供養がてら共有しようと考えた次第です
- 既に [LocalStack v3 がリリースされています](https://blog.localstack.cloud/2023-11-16-announcing-localstack-30-general-availability/) が、ここにあるのは LocalStack v2 のときに書いた内容です
    - 2024/07時点では `localstack/localstack` のバージョンを指定せずにコンテナを起動すると、 LocalStack v3 が起動します。そこで問題なく動くことは確認したので、基本的な設定はそのまま通用するかと思われます
    - とはいえ、あくまでv2当時の設定がv3でも使えるよということで、v3に最適化した訳ではありません。その点ご留意ください m(_ _)m
- 公式の説明は[こちら](https://docs.localstack.cloud/getting-started/installation/#docker-compose "https://docs.localstack.cloud/getting-started/installation/#docker-compose")をご覧ください
- `docker run` を叩いて [localstack/localstack を起動する](https://docs.localstack.cloud/getting-started/installation/#docker "https://docs.localstack.cloud/getting-started/installation/#docker")手もありますが、ここでは割愛します

## 使用上の注意

- コンテナを停止すると、それまでの作業は残りませんのでご注意下さい
    - 作ったバケットやLambda関数も、コンテナを再起動すると全て消えてしまいます
- 永続化する方法もありますが、Proオプションとのことですので、ここでは割愛します
    - 詳細については [こちら](https://docs.localstack.cloud/user-guide/state-management/persistence/) でご確認ください

## 公式の docker-compose.yaml

- 公式ドキュメントに、そのまま使える docker-compose.yaml が載っています
    - https://docs.localstack.cloud/getting-started/installation/#docker-compose
- これをコピーして docker-compose.yaml を作り `docker compose up` すると、LocalStack が使える状態でコンテナが起動します
    - あくまで最低限の設定しか無い点にご注意下さい
    - さっとお試しになりたい方や、 docker-compose.yaml を作るうえでの叩き台が欲しい方にはよいと思います

## セットアップにおいて注意すべきこと

下記の3点が必要です

1. `MAIN_CONTAINER_NAME` 環境変数
2. `SERVICES` 環境変数
3. Dockerソケットのマウント

### 1. `MAIN_CONTAINER_NAME` 環境変数

LocalStack が、自身が稼働しているコンテナ名を知るための値

- `container_name` に設定したのと同じ値にすること
    - `MAIN_CONTAINER_NAME` を設定しなかった場合、デフォルト値である "localstack_main" が設定される
    - `MAIN_CONTAINER_NAME` を設定せず `container_name` に "localstack_main" を設定し、デフォルト値を利用する方法でもよい
- `container_name` と `MAIN_CONTAINER_NAME` の値を同じにすること
    - 2つの値が違っていると LocalStack 上のLambda関数を実行できない。 `lambda create-function` で関数を作成しても、 `lambda invoke` で関数からのレスポンスが戻ってこないなどの不具合が生じる（後掲）
    - どちらも設定しない場合は、それぞれのデフォルト値が採用される。そうなると確実に2つの値は異なってしまうので、少なくとも `container_name` を "localstack_main" に設定する対応は必要
    - とはいえ無用なトラブルを避ける目的で、両方ともしっかり定義しておいた方が確実かと

#### （参考） `lambda invoke` のレスポンスが戻ってこないときのメッセージ

```console
l.u.container_networking : Unable to get network name of main container "localstack_main": localstack_main
l.u.container_networking : Unable to get IP address of main Docker container "localstack_main": localstack_main
```

### 2.  `SERVICES` 環境変数

どのAWSサービスを LocalStack で有効にするか示すための値

- `SERVICES` の値として、カンマ区切りでサービスを指定する
    - v2だと `logs` を指定しなくても CloudWatch Logs は使えた記憶がある
    - v3だとエラーになるので、明示的に設定しておいた方が無難かと…
- 指定できるサービス名の詳細は以下を参照
    - [https://docs.localstack.cloud/references/configuration/#core](https://docs.localstack.cloud/references/configuration/#core)
    - [https://docs.aws.amazon.com/cli/latest/reference/#available-services](https://docs.aws.amazon.com/cli/latest/reference/#available-services)  

```bash
SERVICES=dynamodb,s3,lambda
```

### 3. Dockerソケットのマウント

LocalStack でLambda関数を実行するのに必要な設定。以下は [Migrating to Lambda v2](https://docs.localstack.cloud/user-guide/aws/lambda/#migrating-to-lambda-v2 "https://docs.localstack.cloud/user-guide/aws/lambda/#migrating-to-lambda-v2") から引用

> To run Lambda functions in LocalStack, mount the Docker socket into the LocalStack container.   
> Add the following Docker volume mount to your LocalStack startup configuration: /var/run/docker.sock:/var/run/docker.sock.   
> You can find an example of this configuration in our official  [docker-compose.yml file](https://docs.localstack.cloud/getting-started/installation/#starting-localstack-with-docker-compose "https://docs.localstack.cloud/getting-started/installation/#starting-localstack-with-docker-compose")  

- `volumes:` に `/var/run/docker.sock:/var/run/docker.sock` を追加すればOK

### 設定例

#### 自作のテンプレ

```yaml
localstack:
    image: localstack/localstack                        # 必要ならバージョンを指定
    container_name: <arbitary-container-name>           # 任意だがboto3でのアクセスで必要
    environment:
        - SERVICES=<comma-separated-services-name>      # 必須。カンマ区切りでサービス名を指定
        - PERSISTENCE=1
        - AWS_DEFAULT_REGION=<arbitary-region>          # 必須
        - MAIN_CONTAINER_NAME=<container-name>          # 任意だが、boto3でのアクセスで必要。container_name と合わせる
    volumes:
        - "${LOCALSTACK_VOLUME_DIR:-./localstack}:/var/lib/localstack"  # v2では必須
        - "/var/run/docker.sock:/var/run/docker.sock"                   # ソケットのマウント。Lambdaを使うなら必須
    hostname: <arbitary-host-name>
    ports:
        - 4566:4566
    networks:
        - <arbitary-network-name>   # 有効なネットワーク名を指定
```

#### テンプレをもとに作った docker-compose.yaml

`LOCALSTACK_DEFAULT_CONTAINER_NAME` あたりは環境変数に定義済み

```yaml
networks:
  localstack_net01:

services:
  localstack:
    image: localstack/localstack
    container_name: ${LOCALSTACK_DEFAULT_CONTAINER_NAME}
    environment:
      # LocalStack configuration: https://docs.localstack.cloud/references/configuration/
      - MAIN_CONTAINER_NAME=${LOCALSTACK_DEFAULT_CONTAINER_NAME}
      - SERVICES=s3,dynamodb,lambda,logs
      - AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
      - DEBUG=${DEBUG:-0}
    volumes:
      - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"
    hostname: localstack-host
    ports:
      - 4566:4566
    networks:
      - localstack_net01
```

`docker compose up` の実行結果

```terminal
% docker compose up
[+] Running 1/0
 ✔ Container localstack-main  Created                                                                                                                                          0.0s 
Attaching to localstack-main
localstack-main  | 
localstack-main  | LocalStack version: 3.5.1.dev
localstack-main  | LocalStack build date: 2024-07-19
localstack-main  | LocalStack build git hash: 9d37d8285
localstack-main  | 
localstack-main  | Ready.
```

### 追記

自作の docker-compose.yaml を[こちら](https://github.com/outerlet/sample-sam-app/tree/main/docker)に起きました。もしよければご覧ください。

### 最後に

誤りなどあればご指摘頂けると助かります
また、LocalStack に関してはこれ以外にもメモがいくつか残っているので、可能な限り供養したいと思っています

- [LocalStack v2 で AWS CLI コマンドを使う](https://qiita.com/outerlet/items/509b34af87467ac62645)
- [LocalStack に Lambda 関数を作成して実行する](https://qiita.com/outerlet/items/a1b8b3e6cc1c690c6d21)