AWS CodeStarとCloud9によるPython Lambda開発

# CodeStarとは？
AWSの既存の開発ツール群をかき集めて簡単に立ち上げられるように体系化したものです。
まさにStar（ヒトデ）のようにあらゆるものをかき集めた訳ですね。
かき集められたツールは大体下記の通りです。  

|項目  |値  |
|---|---|
|Cloud9 |ブラウザ上で動くコードエディタ（IDE）。天国超えたような至福感という意味です。これを使ってコードを書くわけですがVSCodeやテキストエディタを使用する事も可能です。
|CodeCommit　|Gitのリポジトリ。GitHubも使用可能です。    
|CloudWatch |CodeCommitの変化をCodePipelineに通知するEvent通達用のツール。
|CodePipeline　|Gitのリポジトリへの更新をきっかけに発動するフロー管理。
|CodeBuild |PipeLineから起動するGitで管理されたコードのビルド。
|CloudFormation |Infrastructure as Code! ビルドされたものをLambda（等）にデプロイするツール。

* Cloud9でコードを書いて  
* CodeCommitにコミット・プッシュ  
* CloudWatch経由でCodePipelineが動く  
* CodeBuildでビルド  
* ビルドが通ったらCloudFormationで実際のLambdaがデプロイされる  
簡単に（？）言うとこういう訳ですね。

そもそもCodeStarで選んだものによってデプロイの仕方が変わり、中にはCodeDeployAgentなるものを　インスタンスに入れておいてデプロイするようなものもありますのでこの記事の内容は全く保証できませんが、これらの開発の実体をアジャイルで解明していきます。
尚、本稿はわかりやすくする為AWS以外のツールは使用せず、Python Lambda開発に絞っています。

# 何故Pythonか？
PythonはZen（禅）の思想を持っています。わかりやすくコード量が少なく書ける。同じ事に対する複数記法が少ない。特にMLの分野で多用され、シェルも脅かし始めています（Perl嫌い派に受ける）。個人的には好きです。
玉に瑕なのはバージョンが２系と３系で分かれてしまっているところでしょうか。  

# 最初の一択
CodeStarにて、新規プロジェクトを選択し、Python のウェブサービス Lambdaを選択します。  
次々に繰り出される選択肢は全て先に上げたAWSのサービスを選択します。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/ddb4bc74-2bc2-e64b-47fd-e0c1b481fe4e.png)

# 作成されたコードの俯瞰
## 概要
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/33c07533-c5a3-eda6-7b5a-9c39eb1d0437.png)
作成されるコードは、至極単純なものです。API Gateway経由でHTTPSのREST（GET/POST）を呼び出すと、Lambdaが動作し、index.pyのhandlerのコードが動いてHTTPのステータスコード200と、"Hello World"とtimestampの含まれたJSONをBodyに返します。  
但しこのコードをCI/CDする為に作成される前出のリソースの全体像を把握するのは非常に大変です。順を追って見ていきましょう。  

## cloud9
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/38061d22-f4ba-db12-8ed0-dbe75ce18265.png)

Cloud9はEC2で起動したインスタンス上で動く開発環境です。
ディレクトリ構造が確認できるペイン、ソースのエディタ、インスタンスにsshでつないだコンソールで成り立っています。  
インスタンスには aws コマンドやgitコマンド、dockerが導入済みです。
この環境自体もCloudFormationのtemplateで作成されます。  
ec2-userでログインしており、AWSによって　現在ログインしているユーザーのクレデンシャルが ~/.aws/credentials に予め仕込まれています。このクレデンシャルはセキュリティ向上の為自動でローテーションされます。
現在ログインしているアカウント権限でawsコマンドや、pythonのboto3でのAWS用APIが実行できます。
EC2のコンソールでこのインスタンスを確認する事ができます。

## テストコード
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/6682cec8-f8d7-a4d8-49f8-89026ac17696.png)
python は言語仕様としてunittestの仕組みを内包しており、unittestモジュールを使用する事によって実現できます。  
python -m unittest discover というコマンドは指定されたディレクトリ配下のテスト全てを実行してくれます。  
これはユニットテストですのでLambdaを実行している訳ではなく、index.py のhandler関数そのものを呼び出して戻り値等を確認しています。

## CodeCommit
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/609c1a0a-9b4b-3caf-49d3-d3a80595019b.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/c15f7af1-e562-f7f1-49df-079435ab48fc.png)

Cloud9環境上のコードの、GitのリポジトリがCodeCommitです。図を細かく見るとわかりますが、ファイルはCloud9にあるものと同じです。  
このGitで管理されたソースがCloud9の環境にClone（ローカルコピー）されているわけです。  
 
## CloudWatch
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/47593dd6-712f-8fca-fba8-946181748c48.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/ff65d151-a0dd-d1a6-fcc6-d29425b8ab8e.png)
CodeCommitのReferenceUpdateのイベントをきっかけにCodePipeLineを起動するイベントがCodeStarによって自動で設定されています。   
Cloud9のコンソール上で、git commit（変更確定）し、git push（変更をCodeCommitと同期）すると、このイベントが走り出します。

## CodePipeline
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/f5de59e2-286e-18d2-454c-314731d79680.png)

CodePipeLineはパイプラインに従って CodeBuildと　CloudFormationを呼び出します。

## CodeBuild
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/c28577fa-a112-c234-dd79-0dfb824dab3e.png)
---------------------
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/ca1c8b7d-9d6d-54cd-735c-f23ea26eb2f0.png)

CodeBuildはリポジトリにあるbuildspec.ymlに従ってビルド前のユニットテストや、ビルドを行います。  
ビルド時のログや履歴が一目瞭然です。  

## buildspec.yml
```yaml

version: 0.2

phases:
  install:
    commands:

      # Upgrade AWS CLI to the latest version
      - pip install --upgrade awscli

  pre_build:
    commands:

      # Discover and run unit tests in the 'tests' directory. For more information, see <https://docs.python.org/3/library/unittest.html#test-discovery>
      - python -m unittest discover tests
  
  build:
    commands:

      # Use AWS SAM to package the application by using AWS CloudFormation
      - aws cloudformation package --template template.yml --s3-bucket $S3_BUCKET --output-template template-export.yml

artifacts:
  type: zip
  files:
    - template-export.yml
```
buildspec.ymlでは、ビルド前に AWSClientを先にインストールし、pythonでユニットテストを行い、CloudFormationでパッケージ作成しています。  
CloudFormationでは、Lambdaのデプロイ用にソースをzipにしてS3に出力し、そのzipをLambdaのCodeUriとして指し示したCloudformationのtemplate template-export.ymlを作成しています。その大元になるのがtemplate.ymlです。これはデプロイの概要を示しています。

## template.yml
```yaml
AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::Serverless-2016-10-31
- AWS::CodeStar

Parameters:
  ProjectId:
    Type: String
    Description: CodeStar projectId used to associate new resources to team members

# Enable blue/green deployments using this Globals section. For instructions, see the AWS CodeStar User Guide:
# https://docs.aws.amazon.com/codestar/latest/userguide/how-to-modify-serverless-project.html?icmpid=docs_acs_rm_tr
#
# Globals:
#   Function:
#     AutoPublishAlias: live
#     DeploymentPreference:
#       Enabled: true
#       Type: Canary10Percent5Minutes

Resources:
  HelloWorld:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: python3.6
      Role:
        Fn::ImportValue:
          !Join ['-', [!Ref 'ProjectId', !Ref 'AWS::Region', 'LambdaTrustRole']]
      Events:
        GetEvent:
          Type: Api
          Properties:
            Path: /
            Method: get
        PostEvent:
          Type: Api
          Properties:
            Path: /
            Method: post
```
template.ymlは、CloudFormationのテンプレートです。
AWS Serverless Application Model (SAM)によって記述されています。CloudFormationでAPI GatewayやLambdaのリソースをつらつら書くのを簡略化して、AWS::Serverless::Functionを書くだけでAPI GatewayとLambdaが両方作成されるものと考えてください。

## デプロイ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/6a41b671-d2a8-3ada-6bce-2e50b92dc157.png)

CloudFormationには、変更セット（ChangeSet）というものがあります。元々のtemplateはそのままに、ChangeSetをtemplateに加えて実行する事で、デプロイ資源等の情報を新しくしてtemplateを実行する事ができます。 上図は先程のCodePipelineのDeploy部分を編集モードにした図ですが、ここでビルド時に出力したテンプレートを指定する事により、資源がデプロイされる事になります。  
Pipelineの次のプロセス、ExecuteChange側で変更したtemplateを実行します。

## CloudFormation

![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/ab69ce3a-add6-f390-30fe-5e2bb7c72094.png)

CloudFormationのコンソールにて、作成されたリソースを確認する事ができます。  

* awscodestar-pytest-lambda がLambdaを作成するtemplate
* aws-cloud9-pytest-a943～ がcloud9の環境を整備するtemplate
* awscodestar-pytest がCodestar全体を整備するtemplate　
となりますので、 デプロイに失敗した場合は一番上のtemplateのエラーメッセージを確認する事で失敗の原因を探る事ができます。
  
# Deploy成果の確認
## Lambda
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/7c477c67-ca35-cce4-cf5e-32fc7c359e02.png)
作成されたLambdaは、単体でコンソールからテストできます。

## API Gateway
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/6a2e0303-768c-0ff0-07b1-8d29a37942dc.png)
こちらはAPI Gatewayです。同じくHTTP呼び出しにてテストできます。

## 呼び出し
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/112bf41e-f2d8-ad2b-1b52-dd0f78387492.png)
ステージングしてデプロイしたAPIは、ブラウザ等でテストできます。

# 長旅の終わりに
## CodeStarコンソール！！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/192988/1dc41fe7-cb97-e618-aa56-c6e045d7ff30.png)
ここまでつらつらと関連するリソースに関して解説してきましたが、それらの全てを呼び出せるタイル形式のダッシュボードがCodeStar コンソールです。  
なかなか大変ですね。  

# 参考
## SAM関連
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/serverless-deploy-wt.html#serverless-pack
https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html
https://github.com/awslabs/serverless-application-model