SAMとCodePipelineでサーバーレスのCI/CDを構築する

AWSのSAMとCodePipelineを使用して、サーバーレス環境でのCI/CDを構築していきます。CodePipelineはCloudFormationは使用せずマネジメントコンソールから作成していきます。
###全体像
以下のような構成でパイプラインを構築していきます。
![sam_black_belt.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/ee18d1a5-fa45-9377-65ab-ebb6fee4853c.jpeg)
出典：[Amazon Web Services ブログ](https://aws.amazon.com/jp/blogs/news/webinar-bb-aws-serverless-application-model-2019/)

###構築手順
####前提
- SAMで必要なコードはgitにプッシュ済み（template.ymlとLambdaのソースコード）
- CloudFormationによるスタックは新規作成済み

上記を前提とし、templateやソースコードをgitにプッシュした際に自動でデプロイまで行ってくれる仕組みを構築していきます。なお全体像で引用している画像にはSource、Build、Deployのステージが定義されていますが、その記載の通りに説明していきます。

####パイプラインの新規作成（Source〜Buildまで）
CodePipelineの初期画面から「パイプラインの作成」をスタート。
パイプラインの設定はお好きな名前をつけて次へ。
![スクリーンショット_codepipeline01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/41f8af1d-ba19-29b4-7714-16b098aa8384.png)
ソースステージの選択は、ご自身で使用するものを入力して次へ。
![スクリーンショット_codepipeline02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/a5b315b9-c47d-6049-91e9-c96a765ffbdc.png)
ビルドステージを追加します。プロバイダーは「AWS CodeBuild」を選択し、「プロジェクトを作成する」で新たに作成します。
![スクリーンショット_codepipeline03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/c84ab7eb-bc9d-8817-fbaf-10e97a25e77c.png)
CodeBuildで新たにプロジェクトを作成していきます。プロジェクト名はお好きなものを入力いただいたのち、環境を設定していきます。CodeBuildはビルドのたびに新規Dockerコンテナで実行されるため、そのコンテナのイメージを設定します。今回は以下のように設定しました。![スクリーンショット_codepipeline04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/c62d3827-66bb-9cae-e6d2-fcce490f24ca.png)
サービスロールも既存のものではなく、今回新たに作成しました。
Buildspecに関して、「buildspecファイルを使用する」を選択した場合は、gitリポジトリにbuildspec.ymlをプッシュしておきます。CodeBuildではこのファイルの記載に則って処理を実行してくれます。今回は以下のようなシンプルな形にしています。s3-bucketはご自身のものを指定してください。

```buildspec.yml
version: 0.2
phases:
  install:
    runtime-versions:
        python: 3.8
  build:
    commands:
      - sam package --template-file template.yml --s3-bucket your-bucket-name --output-template-file packaged-template.yml
artifacts:
  files:
    - packaged-template.yml
```
CodeBuildの入力が完了したら、CodePipelineの入力画面に戻るので次に進んだのち、デプロイステージの入力では「導入段階はスキップ」し、一度パイプラインの作成を完了します。デプロイステージは後で設定します。
これでパイプラインが実行されますが、CodeBuildのサービスロールを新たに作成した場合は、おそらく「Build」のステージで失敗します。これは作成されたサービスロールではアーティファクト格納先のS3バケットへのアクセス権がないためなので、IAMロールの画面からアクセスできるように修正してあげてください。
####パイプラインにDeployステージを追加
これまででS3バケットにパッケージの格納まではできているので、これをデプロイしていきます。デプロイはCloudFormationの[change set](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html)を使用して行います。簡単に言うと、前回との差分セットを作成してそれを実行することでスタック更新を行うといった流れです。なので「Change setを生成する」アクションと「Change setを実行する」アクションを定義していきます。
作成したパイプラインの画面から「編集」を選択し、一番下の「ステージを追加する」ボタンを押してDeployステージを追加していきます。「アクショングループを追加する」を押下し、以下のように入力します。「入力アーティファクト」はBuildステージで出力アーティファクトに設定したものを選択。
![スクリーンショット_codepipeline05-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/7ca32a0f-347f-58a0-f6c0-475d74e624fa.png)
「スタック名」はすでに作成済みのスタックを選択、「セット名を変更する」はお好きな名前を設定、「テンプレート」の「アーティファクト名」はさきほど追加したもの、「ファイル名」はbuildspec.ymlのartifactsで記載した名称。今回の例だと「packaged-template.yml」です。「能力-オプショナル」では「CAPABILITY_IAM」を追加、「ロール名」はCloudFormationのサービスロールを選択します。なければIAM画面で要作成です。
![スクリーンショット_codepipeline06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/3d827b31-d935-5da1-3979-ef4c6a43c2b1.png)
これでChange setの生成は完了です。次にChange setの実行をするためのアクションを定義します。もう一度「アクショングループを追加する」を押下し、以下のように入力します。
![スクリーンショット_codepipeline07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051954/52b02e10-eade-9d0b-20cb-1f612115e085.png)
これで完了です。あとはソースに何かしらの変更をしてgitにプッシュすればデプロイされるはずです。

###さいごに
いろいろ入力してパイプラインを構築してきましたが、実はCodeStarを使えば一瞬で作成されます。ですが、環境を分けるためにブランチごとにパイプラインを作りたいと思い、自分で構築してみた次第です。