AWS SAMをローカルDockerコンテナ上で動かす

#目標#
前回の[AWS SAM CLIによるサーバレス環境構築](https://qiita.com/h-sakamoto/items/9a8493eb386372ceee2a)に引き継ぎ、SAM環境構築で直接にローカルPCにインストールではなく、Docker内に入れます。Docker導入の良いところは、個人開発環境のパッケージのバージョンを統一できるメリットがもちろん、MysqlやElasticSearchなどの導入も迅速できます。

ちなみに、エキサイトの「[開発現場でAWSサーバーレスを導入しました](https://qiita.com/h-sakamoto/items/9db438ff875f84e3be9b)」記事も紹介しました。

#前提#
[入門編](https://qiita.com/h-sakamoto/items/9a8493eb386372ceee2a)に紹介している知識を把握していることが前提です。また、Dockerの基礎知識があり、ローカルPCにDockerインストールしておく必要。

#構築#
##アプリケーションのひな形生成##
初回だけ雛形生成が必要なので、前回みたい```sam init```実行します。

```
$ sam init \
    --runtime python3.8 \
    --name excite-serverless-project \
    --app-template hello-world
```
excite-serverless-projectプロジェクトが作成されました。

##ディレクトリ構造を再編##
最終的にこのようなフォルダー構成を作ります

```
├── README.md
├── __init__.py
├── bin
│   ├── build.sh
│   └── deploy.sh
├── docker
│   └── Dockerfile
├── docker-compose.yml
├── src
│   ├── hello_world
│   │   ├── __init__.py
│   │   ├── app.py
│   │   └── requirements.txt
│   └── template.yaml
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_handler.py
```

とりあえず、Events不要なので削除します

```
$ rm -rf events/
```

実際にAPIエンドポイントが複数あるので、もう１段を下げます

```
$ mkdir src
$ mv hello_world template.yaml src
```

##Docker環境構築##
- AWSの認証設定
AWSへデプロイのため、アクセスキーIDとシークレットキー設定が必要です。

```
$ mkdir .aws
```
保存フォルダーだけ先に作成しておきます。

- docker管理フォルダー作成

```
$ mkdir docker
```
Dockerfileファイル作成、以下の内容を追加します

```
FROM python:3.8

# create local bin directory
RUN mkdir -p /root/.local/bin
ENV PATH $PATH:/root/.local/bin

# Install awscli and aws-sam-cli
RUN pip install -U pip setuptools wheel --no-cache-dir && \
  pip install pipx --no-cache-dir && \
  pipx install virtualenv && \
  pipx install pipenv && \
  pipx install awscli==1.* && \
  pipx install aws-sam-cli==1.9.0

WORKDIR /usr/src
```

最後にdocker-compose.yml作成します

```
version: "3"

services:
  sam_instance:
    container_name: excite-sam-instance
    image: excite-sam-instance
    build:
      context: .
      dockerfile: ./docker/Dockerfile
    networks:
      - excite-sam-network
    volumes:
      - .:/usr/src
networks:
  excite-sam-network:
    driver: bridge
```

##コマンド省略化のために、bashファイルにまとめる##
まず、スクリプト保存フォルダーを作成します

```
$ mkdir bin
```
build.shファイル作成、以下の内容を追加します。

```
#!/bin/bash
set -o errexit

# aws profile
echo -n "AWS_ACCESS_KEY_ID:"
read -r AWS_ACCESS_KEY_ID
echo -n "AWS_SECRET_ACCESS_KEY:"
read -r AWS_SECRET_ACCESS_KEY

# aws credentials
echo "[default]" > .aws/credentials
echo "aws_access_key_id = $AWS_ACCESS_KEY_ID" >> .aws/credentials
echo "aws_secret_access_key = $AWS_SECRET_ACCESS_KEY" >> .aws/credentials

# aws config
echo "[default]" > .aws/config
echo "output = json" >> .aws/config
echo "region = ap-northeast-1" >> .aws/config

# build docker
docker-compose build "${@}"
```

次にdeploy.shファイル作成、以下の内容を追加します。

```
#!/bin/bash
set -o errexit

TEMPLATE_FILE=$1
DOCKER_IMAGE_NAME=excite-sam-instance
STACK_NAME=excite-api-lambda-deploy-stack
S3_BUCKET_NAME=excite-api-lambda-deploy-bucket

# build SAM template
docker run \
  -v $(pwd):/usr/src \
  -v $(pwd)/.aws:/root/.aws --rm $DOCKER_IMAGE_NAME \
  sam build -t "$TEMPLATE_FILE"

# SAM deploy
docker run \
  -v $(pwd):/usr/src \
  -v $(pwd)/.aws:/root/.aws --rm $DOCKER_IMAGE_NAME \
  sam deploy --template-file .aws-sam/build/template.yaml --stack-name "$STACK_NAME" \
    --s3-bucket "$S3_BUCKET_NAME" --capabilities CAPABILITY_NAMED_IAM  --no-fail-on-empty-changeset

# remove unnecessary folder
rm -rf .aws-sam
```

##AWSへデプロイしてみる##
まず、ビルド実施

```
$ ./bin/build.sh
```

個別でテンプレートをAWSへデプロイ

```
$ ./bin/deploy.sh src/template.yaml 
```

API Gatewayのアクセスポイントでアクセスしてみる

```
$ curl https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
{"message": "hello world"}
```
と返ってくれば成功です。

#最後に#
実際の開発現場でdockerが非常に便利です。ローカルでAPIの開発・デバッグ・デプロイの一連作業ができます。次の単体テスト編は実際にコードを書いて、単体テストを実施してみます。

エキサイト株式会社では随時に[仲間を募集](https://www.wantedly.com/companies/excite)しております。