# serverless-todo API: Deploy
serverless-todo API は Todo を登録、取得(検索)、更新、削除 することができるシンプルな REST API です。
この API は AWS Lambda と Amazon DynamoDB をベースとしたサーバーレスアーキテクチャで設計しています。
>このドキュメントでは AWS の各名称について Amazon, AWS などのプリフィックスを省略し、`Amazon Cognito` → `Cognito`、`AWS CloudFormation` → `CloudFormation` のように表現することがありますので予めご留意ください。
### References
API 仕様書はこちらを参照してください。
[serverless-todo API: Reference](https://serverlesstodo.docs.apiary.io/)
[serverless-todo API: Cognito UserPool Auth Reference](https://cognitouserpoolauth.docs.apiary.io/)
ソース、設計については [GitHub](https://github.com/craymaru/serverless-todo-backend) を参照してください。
---
<br>
> デプロイをお試しの場合はこちらのセクションをご参照ください!
> お手数おかけいたしますが、少々お付き合いのほどよろしくお願いいたします。🙇🙇
> [name=Taiki Takayama] [time=Thu, Dec 3, 2020 17:49 PM] [color=#907bf7]
# デプロイについて
## 前提
API のデプロイには AWS のリソースを必要とします。各自 AWS アカウントをご用意ください。また AWS の利用料金が発生する可能性がありますので注意してください。
ほとんどのデプロイ作業を AWS CLI を通して行い、一部確認作業をマネジメントコンソール上から行います。
事前にお使いのアカウントにて適切なポリシーのアタッチされたユーザーを作成し、AWS CLI からログインできるようにしてください。
また、この API のデプロイされるリージョンは、明示的に指定しないため、実行されるシェル環境に依存しますので、デプロイ前に必ずご確認いただけますようお願い申し上げます。*1
> *1 本ドキュメント作成にあたってのデプロイのテストは`ap-northeast-1`で行っています。
#### アクセスキーを確認する
```shell
cat ~/.aws/credentials | grep aws_access_key_id
```
#### リージョンを確認する
```shell
cat ~/.aws/config
```
## デプロイのフロー
* ソースコードの Git を Clone
* Cognito ユーザープールの作成
* ユーザーの作成テスト
* CI/CDパイプラインを構成
* アプリをデプロイ
* お疲れさまでした!
---
<br>
# Step1: ユーザープールの作成
このステップでは Amazon Cognito 使用し、ユーザー認証の部分を作成します。
### 構成
CloudFormation `ServerlessToDoAuthCognitoUserPool`
↓
Cognito UserPool `ServerlessToDoUserPool`
### 手順
1. 以下の Git リポジトリから API のソースをクローンします。
```shell
git clone https://github.com/craymaru/serverless-todo-backend
```
```shell
Cloning into 'serverless-todo-backend'...
remote: Enumerating objects: 400, done.
remote: Counting objects: 100% (400/400), done.
remote: Compressing objects: 100% (191/191), done.
remote: Total 400 (delta 223), reused 371 (delta 194), pack-reused 0
Receiving objects: 100% (400/400), 75.88 KiB | 380.00 KiB/s, done.
Resolving deltas: 100% (223/223), done.
```
2. 以下のコマンドを実行し、ユーザープール用の CloudFormation スタックを作成します。
```shell
aws cloudformation deploy \
--template-file release/cognito_userpool.yml \
--stack-name ServerlessToDoAuthCognitoUserPool \
--capabilities CAPABILITY_IAM
```
```shell
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - ServerlessToDoAuthCognitoUserPool
```
以上の出力を確認できたら、作成が完了しています。
### 確認
1. [CloudFormation のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/cloudformation/home?region=ap-northeast-1) で `ServerlessToDoAuthCognitoUserPool` スタックが作成できていることを確認します。
2. [Cognito のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/cognito/users/?region=ap-northeast-1) で、`ServerlessToDoUserPool` ユーザープールが作成できていることを確認します。
3. 以下のコマンドを実行し CloudFormation の Outputs を確認します。
```shell
aws cloudformation describe-stacks \
--stack-name ServerlessToDoAuthCognitoUserPool \
--query 'Stacks[0].Outputs'
```
```json
[
{
"OutputKey": "CgnitoUserPoolClientId",
"OutputValue": "*"
},
{
"OutputKey": "CognitoUserPoolId",
"OutputValue": "ap-northeast-1_*"
},
{
"OutputKey": "CognitoUserPoolArn",
"OutputValue": "arn:aws:cognito-idp:ap-northeast-1:*:userpool/ap-northeast-1_*"
}
]
```
4. 出力された値は次のステップで使用します。
`CognitoUserPoolClientId` , `CognitoUserPoolId`, `CognitoUserPoolArn` をメモしておきます。
---
<br>
# Step2: ユーザーの認可/認証
このステップでは作成した Cognito UserPool でユーザーのサインアップ、サインイン、トークンの取得を行います。
このステップでは直前の *Step1* で取得した `UserPoolClientId`、 `CognitoUserPoolId`を使用します。
> もし失くしてしまった場合は [Cognito のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/cognito/users/?region=ap-northeast-1) から *ServerlessToDoUserPool* を開き、*全般設定 > アプリクライアント* から *アプリクライアント ID* を、*全般設定* から *ユーザープール ID* を確認することができます。
## サインアップ (新規登録)
ユーザーを新規登録します。
### 手順
1. 以下の値をシェル変数に代入し、`aws cognito-idp sign-up` コマンドを実行します。
`CLIENT_ID`: アプリクライアントID `UserPoolClientId`
`USER_NAME`: ユーザー名
`USER_EMAIL`: 受取可能なメールアドレス
`PASSWORD`: パスワード
```shell
CLIENT_ID=
USER_NAME=
USER_EMAIL=
PASSWORD=
aws cognito-idp sign-up \
--client-id ${CLIENT_ID} \
--username ${USER_NAME} \
--password ${PASSWORD} \
--user-attribute "Name=email,Value=${USER_EMAIL}"
```
2. 以下が出力されたら、Verification Code が送信されているので、メールを確認します。
```json
{
"UserConfirmed": false,
"CodeDeliveryDetails": {
"Destination": "****@****.com",
"DeliveryMedium": "EMAIL",
"AttributeName": "email"
},
"UserSub": "********-****-****-****-************"
}
```
3. メールで受け取った Verification Code を代入し、`aws cognito-idp confirm-sign-up` コマンドを実行します。
`CLIENT_ID`: アプリクライアントID `CognitoUserPoolClientId`
`USER_NAME`: ユーザー名
`VERIFY_CODE`: Verification Code
```shell
CLIENT_ID=
USER_NAME=
VERIFY_CODE=
aws cognito-idp confirm-sign-up \
--client-id ${CLIENT_ID} \
--username ${USER_NAME} \
--confirmation-code ${VERIFY_CODE}
```
### 確認
1. 以下の値を代入し、`aws cognito-idp list-users` コマンドを実行します。
`USER_NAME`: ユーザー名
`USERPOOL_ID`: ユーザープールID
```shell
USER_NAME=
USERPOOL_ID=
aws cognito-idp list-users --user-pool-id ${USERPOOL_ID} \
--filter "username='${USER_NAME}'" \
--query 'Users[0].UserStatus'
```
2. 出力されたユーザーのステータスが `CONFIRMED` になっていることを確認できたら、登録が完了しています。
```json
"CONFIRMED"
```
## トークンの取得
サインインし、トークンを取得します。
### 手順
1. 以下の値を書き換え、`aws cognito-idp admin-initiate-auth` コマンドを実行します。
`CLIENT_ID`: アプリクライアントID `CognitoUserPoolClientId`
`USER_NAME`: ユーザー名
`PASSWORD`: パスワード
```shell
CLIENT_ID=
USER_NAME=
PASSWORD=
TOKEN=$(aws cognito-idp initiate-auth \
--client-id ${CLIENT_ID} \
--auth-flow USER_PASSWORD_AUTH \
--auth-parameters "USERNAME=${USER_NAME},PASSWORD=${PASSWORD}" \
--query "AuthenticationResult.IdToken" | sed "s/\"//g") && echo $TOKEN
```
```
ey...
```
ID トークンが取得できました。
ID トークンのデフォルトの有効期限は 1 時間です。
---
<br>
# Step3: アプリのデプロイ
このセクションでは serverless-todo API の CI/CD 環境を CodePipeline で実装します。デプロイには CloudFormation を使用します。
このステップでは *Step1* で取得した `CognitoUserPoolArn` を使用します。
>もし失くしてしまった場合は [Cognito のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/cognito/users/?region=ap-northeast-1) から *ServerlessToDoUserPool* を開き、全般設定* から *ユーザープール ID* を確認することができます。
## USER_POOL_ARN を指定する
API はリクエストと同時に受け取ったトークンを、Cognito ユーザープールに確認しに行き、ステートレスに認証を行います。*Step1* で作成したユーザープールの ARN を API に教えてあげましょう。
### 手順
1. `.chalice/config.json` を開き、`USER_POOL_ARN` の値編集します。
`local`、`dev` ステージそれぞれの `USER_POOL_ARN` の値を、*Step1* で取得した `CognitoUserPoolArn` の値に置き換えてください。
```json=101
# 必要な箇所のみに省略して表示しています
{
"stages": {
"local": {
"environment_variables": {
"USER_POOL_ARN": "arn:aws:cognito-idp:*"
}
},
"dev": {
"environment_variables": {
"USER_POOL_ARN": "arn:aws:cognito-idp:*"
}
}
}
}
```
2. 後の手順で CodeCommit を通じてデプロイを行うため、変更したファイルをコミットします。
```shell
git add -A .
git commit -m "Updated USER_POOL_ARN"
```
## CodePipeline を構成する
CloudFormation に `ServerlessToDoPipeline` スタックを作成し CodePipeline のデプロイを行います。
### 手順
1. AWS CLI を使用して`release/pipeline.json` テンプレートをデプロイします。
このコマンドは、展開に数分かかる場合があります。
```shell
aws cloudformation deploy --stack-name ServerlessToDoPipeline \
--template-file release/pipeline.json \
--capabilities CAPABILITY_IAM
```
```
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - ServerlessToDoPipeline
```
### 確認
1. 以下のコマンドを実行し、CloudFormation の出力を確認します。
```shell
aws cloudformation describe-stacks \
--stack-name ServerlessToDoPipeline \
--query 'Stacks[0].Outputs'
```
```json
[
{
"OutputKey": "CodeBuildRoleArn",
"OutputValue": "arn:aws:iam::*:role/ServerlessToDoPipeline-CodeBuildRole-*"
},
{
"OutputKey": "CFNDeployRoleArn",
"OutputValue": "arn:aws:iam::*:role/ServerlessToDoPipeline-CFNDeployRole-*"
},
{
"OutputKey": "S3ApplicationBucket",
"OutputValue": "serverlesstodopipeline-applicationbucket-*"
},
{
"OutputKey": "DynamoDBTableName",
"OutputValue": "serverless-todo-backend-*"
},
{
"OutputKey": "CodePipelineRoleArn",
"OutputValue": "arn:aws:iam::*:role/ServerlessToDoPipeline-CodePipelineRole-*"
},
{
"OutputKey": "SourceRepoURL",
"OutputValue": "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/serverless-todo-backend"
},
{
"OutputKey": "S3PipelineBucket",
"OutputValue": "serverlesstodopipeline-artifactbucketstore-*"
}
]
```
2. `SourceRepoURL` を次の手順で使用するためメモしておきます。
---
## ローカル側を設定する
作成した CodePipeline にソースコードを Push できるようにするため、Git の設定を行います。
### 手順
1. CodeCommit リモートリポジトリを Git に登録します。
`SourceRepoURL` を前の手順で確認したものに置き換え、以下のコマンドを実行します。
```shell
git remote add codecommit <SourceRepoURL>
```
2. CodeCommit に認証するための `credential-helper` を構成します。
次の行を `.git/config` ファイルの末尾に追加します。
```=101
[credential]
helper =
helper = !aws codecommit credential-helper $@
UseHttpPath = true
```
### 確認
1. CodeCommit リモートリポジトリが Git に登録されていることを確認します。
```shell
git remote -v
```
```shell
codecommit https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/serverless-todo-backend (fetch)
codecommit https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/serverless-todo-backend (push)
```
2. `credential-helper` が正しく設定されていることを確認します。
macOSユーザーは、osxkeychainエントリが出力の最初の行として表示される場合があります。出力の最後の2行が、以下の出力と一致すること確認します。
```shell
git config -l | grep helper
```
```shell
credential.helper=osxkeychain
credential.helper=
credential.helper=!aws codecommit credential-helper $@
```
3. codecommit リモートリポジトリから問題なくフェッチできることを確認します。
```shell
git fetch codecommit && echo $?
```
```shell
0
```
## CI/CD パイプラインを実行する
これまでのセクションで、CodePipeline の構成し、CI/CD パイプラインを構築できました。
以降、リモートリポジトリに変更をプッシュするたびに、CodeCommit から CodeBuild にて テスト/ビルド が行われ、
テストをパスすれば CloudFormation が新たなスタックを作成しアプリを自動的にデプロイします。
### 手順
1. ソースコードを Push します。
```shell
git push codecommit main
```
### 確認
1. [CodePipeline のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/codesuite/codepipeline/pipelines/serverless-todo-backendPipeline/view) から `serverless-todo-backendPipeline` を確認します。
>変更をプッシュしてからパイプラインが開始されるまでに数分かかる場合があります。パイプラインがまだ開始されていない場合は、数分待ってからページを更新してください。パイプラインが開始されると、デプロイ完了まで約5分かかります。
## エンドポイントの確認
最後にデプロイされた API のエンドポイントを確認します。
1. 以下のコマンドを実行し、APIの `EndpointURL` を確認します。
> 指定するスタックは、`アプリ名` に `BetaStack` サフィックスをつけたものです。
> ex. `serverless-todo-backendBetaStack`
```shell
aws cloudformation describe-stacks --stack-name serverless-todo-backendBetaStack \
--query 'Stacks[0].Outputs'
```
```json
[
{
"OutputKey": "APIHandlerArn",
"OutputValue": "arn:aws:lambda:ap-northeast-1:*:function:serverless-todo-backendBetaStack-APIHandler-*"
},
{
"OutputKey": "APIHandlerName",
"OutputValue": "serverless-todo-backendBetaStack-APIHandler-*"
},
{
"OutputKey": "RestAPIId",
"OutputValue": "b1gi2pp9z1"
},
{
"OutputKey": "EndpointURL",
"OutputValue": "https://b1gi2pp9z1.execute-api.ap-northeast-1.amazonaws.com/api/"
}
]
```
続いてエンドポイントの検証を行う場合は [serverless-todo API: Reference](https://serverlesstodo.docs.apiary.io/) を参照してください。
---
> お疲れさまです!:tada:
> デプロイをお試し頂いた方、またこのドキュメントをお読み頂いた方、
> 誠にありがとうございます!:sparkles:
> [name=Taiki Takayama] [time=Thu, Dec 3, 2020 17:49 PM] [color=#907bf7]
---
<br>
# デプロイの削除の方法
## Cognito ユーザープールを削除する
### 手順
以下のコマンドを実行し、`ServerlessToDoAuthCognitoUserPool` スタックを削除します。
```shell
aws cloudformation delete-stack --stack-name ServerlessToDoAuthCognitoUserPool
```
### 確認
1. [CloudFormation のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/cloudformation/home) を開き、削除したスタックがなくなっていることを確認します。
## アプリとパイプラインを削除する
アプリ、パイプラインの順に削除を行います。
### 手順
1. 以下のコマンドを実行し、`serverless-todo-backendBetaStack` スタックを削除します。
```shell
aws cloudformation delete-stack --stack-name serverless-todo-backendBetaStack
```
2. 以下のコマンドを実行し、`ServerlessToDoPipeline` スタックを削除します。
```shell
aws cloudformation delete-stack --stack-name ServerlessToDoPipeline
```
### 確認
1. [CloudFormation のマネジメントコンソール](https://ap-northeast-1.console.aws.amazon.com/cloudformation/home) を開き、削除したスタックがなくなっていることを確認します。
> 削除時にスタックのステータスが `DELETE_FAILED` になる場合は、`ServerlessToDoPipeline` が生成した S3 バケットを手動で削除してからもう一度コマンドを実行します。