localstackにsamでlamndaと{proxy+} なapigwを作ってfastapiなpythonでDynamoDBにCRUD

中身は↓と同じ
https://zenn.dev/notfound_pan/articles/059e61cfdb689e

# 注意事項
僕はpro課金勢です
無料版では動くかは確認してません

# 次の記事
https://qiita.com/kk-tn/items/959d4d3f7e5c26311ce2

# やりたいこと
- aws lambdaは便利なんだけどapiが増えるたびにインフラさんにlambda作ってもらって・・・ってめんどくさい
    - apigwのリソースパスを{proxy+}にしてapigwをリバプロとする
    - lambda側はpython/fastapiで作る
- ただ実際にawsに作っちゃうとお金がかかるからローカルの開発環境でやりたい
    - localstackでやる
- いろいろやろうとすると環境が汚れる（そしてそのうち壊れる）
    - 開発環境もコンテナに閉じ込める

# localstackとは

ローカルマシンで起動するとawsをエミュレートしてくれる

開発端末でawscliやsamcliでリソースを作ったりするとawsではなくlocalstackにリソースができる

# 今回作りたいもの

AWSでつくるならこんな感じ

開発環境からsamでlambdaをデプロイする

デプロイのときにtemplate.yamlからapigw,lambda,DynamoDBを作る

ユーザはhttpでapigw経由でlambdaにつないでDynamoへCRUDする

・・・というものをlocalstackで作る

```mermaid
flowchart LR

%%外部要素
DEV[開発環境]
USER[ユーザ]

%%グループとサービス
subgraph AWS[AWS]
	APIGW{{"APIGW"}}
	LAMBDA("LAMBDA")
	DynamoDB[("DynamoDB")]
	S3[("S3")]
end

%%サービス同士の関係
DEV --> |sam deploy|S3 
DEV --> |sam deploy|APIGW 
DEV --> |sam deploy|DynamoDB
S3 --> |deploy from s3 backet|LAMBDA
USER --> |http|APIGW
APIGW --> LAMBDA
LAMBDA--> DynamoDB

%%グループのスタイル
classDef SAWS fill:none,color:#345,stroke:#345
class AWS SAWS

%%サービスのスタイル
classDef SOR fill:#aaa,color:#fff,stroke:#fff
class USER SOR
class DEV SOR

classDef SNW fill:#84d,color:#fff,stroke:none
class APIGW SNW

classDef SCP fill:#e83,color:#fff,stroke:none
class LAMBDA SCP

classDef SDB fill:#46d,color:#fff,stroke:#fff
class DynamoDB SDB

classDef SST fill:#493,color:#fff,stroke:#fff
class S3 SST
```

localstackで作るとこんな構成になる

開発環境、localstackどっちもdockerのコンテナとして動かす

localstackでlambdaを動かすとlocalstack外の別コンテナになるのでこんな感じ

```mermaid
flowchart LR

%%外部要素
subgraph DOCKER [Docker]
	subgraph DEVCONTINER [開発コンテナ]
	end
	subgraph LAMBDACONTINER [LAMBDAコンテナ]
	end
	subgraph LOCALSTACK [LOCALSTACK]
		APIGW{{"APIGW"}}
		DynamoDB[("DynamoDB")]
		S3[("S3")]
	end
end

%%サービス同士の関係
DEVCONTINER --> |sam deploy|S3 
DEVCONTINER --> |sam deploy|APIGW 
DEVCONTINER --> |sam deploy|DynamoDB
S3 --> |deploy from s3 backet|LAMBDACONTINER 
DEVCONTINER --> |http|APIGW
APIGW --> LAMBDACONTINER
LAMBDACONTINER --> DynamoDB

%%グループのスタイル
classDef SDOCKER fill:none,color:#345,stroke:#345
class DOCKER SDOCKER

classDef SCONTINER fill:none,color:#345,stroke:#345
class DEVCONTINER SCONTINER
class LOCALSTACK SCONTINER
class LAMBDACONTINER SCONTINER

classDef SAWS fill:none,color:#345,stroke:#345
class LOCALSTACK SAWS

%%サービスのスタイル
classDef SOR fill:#aaa,color:#fff,stroke:#fff
class USER SOR
class DEV SOR

classDef SNW fill:#84d,color:#fff,stroke:none
class APIGW SNW

classDef SCP fill:#e83,color:#fff,stroke:none
class LAMBDA SCP

classDef SDB fill:#46d,color:#fff,stroke:#fff
class DynamoDB SDB

classDef SST fill:#493,color:#fff,stroke:#fff
class S3 SST
```

# フォルダ構成

ホスト側から見るとこんな感じ

```bash
satoshi@Ubuntu:/workspace/projects$ tree localstack -La 4
localstack
├── dev_lambnda_python3.9.16_Dockerfile
├── docker-compose.yml
├── localstack_with_dockercli
└── mount
    ├── dev
    │   ├── home
    │   │   └── .aws
    │   └── work
    └── localstack
```

mount以下はホストとコンテナで共有するvolume

.awsはaws configureした後にできるファイルたちを残したいからコンテナ内の~/.awsを保持してもらう

dev_lambnda_python3.9.16_Dockerfileが開発用のイメージを作るDockerfile

localstack_with_dockercliはlocalstackのイメージにちょっと足したイメージを作るDockerfile

## 各ファイル

### dev_lambnda_python3.9.16_Dockerfile

python,pip,pipenv,awscli,aws-sam-cli,aws-sam-cli-localを入れている

他にもいりそうなものを何個かインストール

```docker
FROM ubuntu:jammy

#base
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update
RUN apt install -y apt-transport-https ca-certificates curl software-properties-common \
	&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \
	&& add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu jammy stable"

RUN apt-get update
RUN apt-get install -y apt-utils sudo locales tzdata \
	iputils-ping net-tools dnsutils jq tzdata curl gcc make tree \
	g++ git unzip groff-base \
	build-essential libtool texinfo dpkg-dev pkg-config \
	gfortran ccache qt5-qmake \
	zlib1g-dev libffi-dev libbz2-dev libreadline-dev libssl-dev libsqlite3-dev liblzma-dev tk-dev docker-ce-cli \
	&& apt-get clean \
	&& rm -rf /var/lib/apt/lists/*

RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LC_ALL ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV TZ Asia/Tokyo

RUN cd /tmp \ 
	&& curl -O https://www.python.org/ftp/python/3.9.16/Python-3.9.16.tgz \
	&& rm -rf Python-3.9.16 \
	&& tar -xvzof Python-3.9.16.tgz \
	&& cd ./Python-3.9.16 \
	&& ./configure --enable-optimizations \
	&& make \
	&& sudo make install

RUN python3 -m pip install -U pip setuptools \
	&& pip install --upgrade pip \
	&& pip install pipenv

RUN groupadd -g 1000 dev-lambda-user \
	&& useradd -u 1000 -g 1000 -m dev-lambda-user \
    && useradd -g 1000 -G sudo -m -s /bin/bash iganari \
	&& echo "dev-lambda-user:passwd" | chpasswd \
	&& echo "root:passwd" | chpasswd
RUN echo 'Defaults visiblepw'             >> /etc/sudoers
RUN echo 'dev-lambda-user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

RUN cd /tmp \
	&& curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
	&& unzip awscliv2.zip \
	&& sudo ./aws/install \
	&& rm -fr aws/ awscliv2.zip \
	&& pip install awscli-local \
	&& pip install aws-sam-cli \
	&& pip install aws-sam-cli-local

USER dev-lambda-user

SHELL [ "/bin/bash", "-c" ]
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

RUN . /home/dev-lambda-user/.nvm/nvm.sh \
    && nvm install --lts \
    && nvm use --lts \
	&& nvm cache clear \
    && node -v && npm -v \
    && npm i -g yarn wscat

SHELL [ "/bin/bash", "-c" ]
RUN echo -e 'export PATH=/home/dev-lambda-user/.local/bin:$PATH' >> /home/dev-lambda-user/.bashrc \
	&& echo -e 'export PIPENV_VENV_IN_PROJECT=true' >> /home/dev-lambda-user/.bashrc \
	&& source /home/dev-lambda-user/.bashrc

RUN echo -e "\
export NVM_DIR=\"\$HOME/.nvm\"\n\
[ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\"\n\
" >> /home/dev-lambda-user/.bashrc \
	&& source /home/dev-lambda-user/.bashrc

RUN echo -e "complete -C '/usr/local/bin/aws_completer' aws" >> /home/dev-lambda-user/.bashrc \
	&& echo -e "complete -C '/usr/local/bin/aws_completer' awslocal" >> /home/dev-lambda-user/.bashrc \
	&& source /home/dev-lambda-user/.bashrc
	
CMD ["bash"]
```

### localstack_with_dockercli

```docker
FROM localstack/localstack-pro:1.4.0

#base
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update
RUN apt install -y apt-transport-https ca-certificates curl software-properties-common \
	&& curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
RUN echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

RUN apt-get update
RUN apt-get install -y libc6 docker-ce-cli iputils-ping net-tools dnsutils tree \
	&& apt-get clean \
	&& rm -rf /var/lib/apt/lists/*
```

### ポイント

```docker
ENV DEBIAN_FRONTEND=noninteractive
```

これをいれとかないとgitのapt-get installで躓く

```docker
RUN cd /tmp \ 
	&& curl -O https://www.python.org/ftp/python/3.9.16/Python-3.9.16.tgz \
	&& rm -rf Python-3.9.16 \
	&& tar -xvzof Python-3.9.16.tgz \
	&& cd ./Python-3.9.16 \
	&& ./configure --enable-optimizations \
	&& make \
	&& sudo make install
```

lambdaで使うpythonとバージョンを合わせたいので自分でmake

```docker
RUN echo -e 'export PATH=/home/dev-lambda-user/.local/bin:$PATH' >> /home/dev-lambda-user/.bashrc \
	&& echo -e 'export PIPENV_VENV_IN_PROJECT=true' >> /home/dev-lambda-user/.bashrc \
	&& source /home/dev-lambda-user/.bashrc
```

pipenv使ったときに~/.local以下に諸々入ってしまうとコンテナを止めて動かしたときに消えてしまう

プロジェクト配下に.venvを作るようにPIPENV_VENV_IN_PROJECTを仕込む

### docker-compose.yml

```docker
version: "3.7"

services:
  localstack:
    container_name: "localstack_a04"
    build:
      context: .
      dockerfile: localstack_with_dockercli
    user: "${UID}:${GID}"
    ports:
      - "127.0.0.1:4566:4566"            # LocalStack Gateway
      - "127.0.0.1:4510-4559:4510-4559"  # external services port range
      - "127.0.0.1:53:53"                # DNS config (only required for Pro)
      - "127.0.0.1:53:53/udp"            # DNS config (only required for Pro)
      - "127.0.0.1:443:443"              # LocalStack HTTPS Gateway (only required for Pro
      - 8000:8080
    environment:
      - SERVICES=${SERVICES- }
      - DEBUG=1
      # - LEGACY_DOCKER_CLIENT=1
      - DATA_DIR=${DATA_DIR- }
      - LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR- }
      - LAMBDA_DOCKER_NETWORK=localstack.internal
      - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY- }  # only required for Pro
      - HOST_TMP_FOLDER=${TMPDIR:-/tmp/}localstack
      - DOCKER_HOST=unix:///var/run/docker.sock
      - LAMBDA_EXECUTOR=docker-reuse
      - HOSTNAME_EXTERNAL=localstack
    volumes:
      - "/workspace/projects/localstack/mount/localstack/var/lib/localstack:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"
    networks:
      - container-link
  devlambda:
    build:
      context: .
      dockerfile: dev_lambnda_python3.9.16_Dockerfile
    container_name: "localstack_dev_a03"
    user: "dev-lambda-user:dev-lambda-user"
    environment:
      - LOCALSTACK_HOSTNAME=localstack
      - LOCALSTACK_HOST=localstack
      - DEFAULT_REGION=ap-northeast-1
    volumes:
      - "/workspace/projects/localstack/mount/dev/home/.aws:/home/dev-lambda-user/.aws"
      - "/workspace/projects/localstack/mount/dev/work:/work"
      - "/var/run/docker.sock:/var/run/docker.sock"
    tty: true
    working_dir: /work
    networks:
      - container-link
networks:
  container-link:
    name: localstack.internal
```

### ポイント

```docker
      - DEBUG=1
```

トラブル時に捗る

```docker
      - LOCALSTACK_HOSTNAME=localstack
      - LOCALSTACK_HOST=localstack
```

awscli localやsam localはデフォルトだとlocalhost:4566につなぐ

今回、開発用のコンテナとlocalstackのコンテナは別で動かすのでawslocal,samlocalの向き先をlocalstackに変えている

LOCALSTACK_HOSTNAMEがsamlocal用でLOCALSTACK_HOSTがawslocal用

なんでそろえなかったんだろうね…

# 動かす

docker compose upしてlocalstackと開発用のコンテナを起動する

```bash
satoshi@Ubuntu:/workspace/projects/localstack$ docker compose up
WARN[0000] The "UID" variable is not set. Defaulting to a blank string.
WARN[0000] The "GID" variable is not set. Defaulting to a blank string.
[+] Running 2/2
 ⠿ Container localstack_a04      Recreated                                                                                                                                                                                                                                         0.2s
 ⠿ Container localstack_dev_a03  Recreated
・・・
```

# lamndaを作る

## vscodeで開発用のコンテナにつなぐ
![](https://storage.googleapis.com/zenn-user-upload/ca482dc8861d-20230324.png)


## /workを開く
![](https://storage.googleapis.com/zenn-user-upload/1dcff53d68f1-20230324.png)

docker-compose.ymlでホストの/workspace/projects/localstack/mount/dev/workとつなげているので開発コンテナ内ではそこが/workでみえる

初期状態ではworkの下は空

```docker
      - "/workspace/projects/localstack/mount/dev/work:/work"
```

以降はvscodeのターミナルで実行

## aws configureでlocalstackにつなぐときのprofileを作る

適当でOK

```bash
dev-lambda-user@6ebb0a4f7fd1:/work$ aws configure --profile localstack
AWS Access Key ID [None]: dummy
AWS Secret Access Key [None]: dummy
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

## samlocal initでプロジェクト作成

```bash
dev-lambda-user@f220fa55d305:/work$ samlocal init

You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Hello World Example With Powertools
        8 - Infrastructure event management
        9 - Serverless Connector Hello World Example
        10 - Multi-step workflow with Connectors
        11 - Lambda EFS example
        12 - DynamoDB Example
        13 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]: y

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N

Project name [sam-app]: py-app

    -----------------------
    Generating application:
    -----------------------
    Name: py-app
    Runtime: python3.9
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .
    Configuration file: py-app/samconfig.toml
    
    Next steps can be found in the README file at py-app/README.md
        

Commands you can use next
=========================
[*] Create pipeline: cd py-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd py-app && sam validate
[*] Test Function in the Cloud: cd py-app && sam sync --stack-name {stack-name} --watch
```

実行するとpy-appフォルダができてsamが諸々ファイルを作ってくれている

lambdaで実行するプログラムがhello_world/app.py

lambda、apigatewayのデプロイに使うのがtemplate.yaml

他はあんまり気にしない

testは今回書かないのでtestsは消してもよし

```bash
.
├── README.md
├── __init__.py
├── events
│   └── event.json
├── hello_world
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── samconfig.toml
├── template.yaml
└── tests
    ├── __init__.py
    ├── integration
    │   ├── __init__.py
    │   └── test_api_gateway.py
    ├── requirements.txt
    └── unit
        ├── __init__.py
        └── test_handler.py
```

## pipenvで仮想環境を作る

pythonの仮想環境を開発コンテナ内につくる

hello_world以下がlambdaのコードなので/work/py-app/hello_worldに移動してから仮想環境を作る

```bash
dev-lambda-user@f220fa55d305:/work/py-app/hello_world$ pipenv --python 3.9.16
Creating a virtualenv for this project...
Pipfile: /work/py-app/hello_world/Pipfile
Using /usr/local/bin/python3.9 (3.9.16) to create virtualenv...
⠋ Creating virtual environment...created virtual environment CPython3.9.16.final.0-64 in 649ms
  creator CPython3Posix(dest=/work/py-app/hello_world/.venv, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/dev-lambda-user/.local/share/virtualenv)
    added seed packages: pip==23.0.1, setuptools==67.4.0, wheel==0.38.4
  activators BashActivator,CShellActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

✔ Successfully created virtual environment!
Virtualenv location: /work/py-app/hello_world/.venv
requirements.txt found in /work/py-app/hello_world instead of Pipfile! Converting...
✔ Success!
Warning: Your Pipfile now contains pinned versions, if your requirements.txt did. 
We recommend updating your Pipfile to specify the "*" version, instead.
```

## 仮想環境に入る

```bash
dev-lambda-user@f220fa55d305:/work/py-app/hello_world$ pipenv shell
Launching subshell in virtual environment...
 . /work/py-app/hello_world/.venv/bin/activate
```

## pipenvでfastapiとmangumを入れる

```bash
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app/hello_world$ pipenv install fastapi mangum
Installing fastapi...
Resolving fastapi...
Installing...
Adding fastapi to Pipfile's [packages] ...
✔ Installation Succeeded
Installing mangum...
Resolving mangum...
Installing...
Adding mangum to Pipfile's [packages] ...
✔ Installation Succeeded
Pipfile.lock not found, creating...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success!
Locking [dev-packages] dependencies...
Updated Pipfile.lock (b49ab962751802c60e89e1ff81be94395ae0a96ed15a13806310592559663cc9)!
Installing dependencies from Pipfile.lock (663cc9)...
```

## requirements.txtを作っておく

```bash
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app/hello_world$ pipenv requirements > requirements.txt
```

## Pythonのプログラムを作る

/work/py-app/hello_world/app.pyを以下に書き換え

/helloでhello worldを返してuser/{uuid}/{index}でDynamoにデータを書き込む

DynamoDBはsamlocal deployしたときにtemplate.yamlから作る

```python
from fastapi import FastAPI,Body
from mangum import Mangum
import boto3
dynamodb = boto3.resource("dynamodb", region_name='ap-northeast-1',endpoint_url='http://localstack:4566/')
table = dynamodb.Table("userTable")

app = FastAPI()
handler = Mangum(app)

@app.get("/hello")
async def hello():
    print("hello get called")
    return {"message" : "Hello,World v2"}

@app.get("/user/{uuid}/{index}")
async def get_user(uuid:str):
    response = table.get_item(
    Key={
        'Uuid': uuid,
        'Index': 0
    })
    return response['Item']

@app.put("/user/{uuid}/{index}")
async def put_user(uuid:str,index:int,body=Body(...)):
    print("put_user called")
    user_data = {
            'Uuid': uuid,
            'Index': 0,
            'UserInfo' : body['UserInfo']
        }
    try:
        table.put_item(Item = user_data)
    except Exception as e:
        print("error")
        print(e)

    return user_data
```

## /work/py-app/template.yamlを以下に書き換え

APIGW、lamnda、DynamoDBを作る

localstackで動く最低限のものだけ書いた

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  py-app

  Sample SAM Template for py-app

Globals:
  Function:
    Timeout: 3

Resources:
  HelloWorldApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: stg
      MethodSettings:
        # ログを有効化
        - DataTraceEnabled: true
          LoggingLevel: 'INFO'
          ResourcePath: '/*'
          HttpMethod: '*'
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.handler
      Runtime: python3.9
      Timeout: 80
      Architectures:
        - x86_64
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: Any
            RestApiId:
              Ref: HelloWorldApiGateway
  dynamoDBTest: 
    Type: AWS::DynamoDB::Table
    Properties: 
      TableName: userTable
      AttributeDefinitions:
        - AttributeName: Uuid
          AttributeType: S
        - AttributeName: Index
          AttributeType: N
      KeySchema:
        - AttributeName: Uuid
          KeyType: HASH
        - AttributeName: Index
          KeyType: RANGE
      ProvisionedThroughput: 
        ReadCapacityUnits: 10
        WriteCapacityUnits: 5

Outputs:
  HelloWorldApiGateway:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "http://localstack:4566/restapis/${HelloWorldApiGateway}/stg/_user_request_/hello"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
```

## samでビルド

```bash
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app/hello_world$ cd ../
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app$ samlocal build
Starting Build use cache
Manifest is not changed for (HelloWorldFunction), running incremental build
Building codeuri: /work/py-app/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running PythonPipBuilder:CopySource
Running PythonPipBuilder:CopySource

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
```

## samlocalでデプロイ

```bash
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app$ samlocal deploy --stack-name my-py-app --region ap-northeast-1
        Creating the required resources...
        Successfully created!

                Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-1336e058
                A different default S3 bucket can be set in samconfig.toml
                Or by specifying --s3-bucket explicitly.
        Uploading to 129bcb1b34288ef5f9d229ce6880b08a  4073745 / 4073745  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : my-py-app
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-1336e058
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================

        Uploading to bbee67b9c357de5f62e649b6c08dc303.template  1837 / 1837  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                          LogicalResourceId                                  ResourceType                                       Replacement                                      
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                              HelloWorldFunctionRole                             AWS::IAM::Role                                     N/A                                              
+ Add                                              HelloWorldApiGatewaystgStage                       AWS::ApiGateway::Stage                             N/A                                              
+ Add                                              HelloWorldApiGatewayDeployment50b9b0bd4f           AWS::ApiGateway::Deployment                        N/A                                              
+ Add                                              HelloWorldFunctionHelloWorldPermissionstg          AWS::Lambda::Permission                            N/A                                              
+ Add                                              dynamoDBTest                                       AWS::DynamoDB::Table                               N/A                                              
+ Add                                              HelloWorldApiGateway                               AWS::ApiGateway::RestApi                           N/A                                              
+ Add                                              HelloWorldFunction                                 AWS::Lambda::Function                              N/A                                              
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1679633665/7c2ab037

Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2023-03-24 13:54:30 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 5.0 seconds)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                     ResourceType                                       LogicalResourceId                                  ResourceStatusReason                             
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         HelloWorldFunctionRole                             -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         dynamoDBTest                                       -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         HelloWorldApiGateway                               -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         HelloWorldFunction                                 -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         HelloWorldApiGatewayDeployment50b9b0bd4f           -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         HelloWorldFunctionHelloWorldPermissionstg          -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         HelloWorldApiGatewaystgStage                       -                                                
CREATE_COMPLETE                                    AWS::CloudFormation::Stack                         my-py-app                                          -                                                
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                                                                                  
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldApiGateway                                                                                                                                                                 
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                                                                     
Value               http://localstack:4566/restapis/iuj1odgjmo/stg/_user_request_/hello                                                                                                                  

Key                 HelloWorldFunction                                                                                                                                                                   
Description         Hello World Lambda Function ARN                                                                                                                                                      
Value               arn:aws:lambda:ap-northeast-1:000000000000:function:my-py-app-HelloWorldFunction-cc732ca3                                                                                            
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - my-py-app in ap-northeast-1
```

```bash
Key                 HelloWorldApiGateway                                                                                                                                                                 
Description         API Gateway endpoint URL for Prod stage for Hello World function                                                                                                                     
Value               http://localstack:4566/restapis/iuj1odgjmo/stg/_user_request_/hello                                                                                                                  
```

ここに接続先のlocalstackのURLが出てる

## LocalStackのダッシュボードで確認

deployするとs3にバケットができている
![](https://storage.googleapis.com/zenn-user-upload/d5d6eaf91717-20230324.png)


ここを経由してlambdaが作られる

lambdaもできてる
![](https://storage.googleapis.com/zenn-user-upload/ac825751f3ac-20230324.png)


apigatewayもできてる
![](https://storage.googleapis.com/zenn-user-upload/57c4ef95992a-20230324.png)


## 開発コンテナからLocalstackのlambdaを叩いてみる

curlでlocalstackのapigwをたたく

繋がっている

OK

```bash
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app$ curl -H "accept: application/json" -H "Content-Type: application/json" http://localstack:4566/restapis/iuj1odgjmo/stg/_user_request_/hello | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    28  100    28    0     0    279      0 --:--:-- --:--:-- --:--:--   282
{
  "message": "Hello,World v2"
}
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app$ curl -X PUT -H "accept: application/json" -H "Content-Type: application/json" http://localstack:4566/restapis/iuj1odgjmo/stg/_user_request_/user/satoshi/0 -d '{"UserInfo":{"data1":"value1","data2":"value2"}}'  | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   123  100    75  100    48    262    167 --:--:-- --:--:-- --:--:--   431
{
  "Uuid": "satoshi",
  "Index": 0,
  "UserInfo": {
    "data1": "value1",
    "data2": "value2"
  }
}
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app$ curl -H "accept: application/json" -H "Content-Type: application/json" http://localstack:4566/restapis/iuj1odgjmo/stg/_user_request_/user/satoshi/0 | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    75  100    75    0     0    540      0 --:--:-- --:--:-- --:--:--   543
{
  "Index": 0,
  "UserInfo": {
    "data1": "value1",
    "data2": "value2"
  },
  "Uuid": "satoshi"
}
(hello_world) dev-lambda-user@f220fa55d305:/work/py-app$
```