AWSで始めるCI/CD 〜Code系サービス解説〜

## はじめに
みなさんCI/CDのツールって何を使っていますか？？
『Jenkins』『Circle CI』『GitLab』その他諸々色々ありますよね。
今回取り上げるのはAWSのサービスを使ったCI/CDです。

AWSでCI/CDを構築するにはCode型のサービス、通称Code兄弟が必要になります。
ちなみにCode兄弟は以下のサービスをまとめてそのように呼んでいます。
『CodeCommit』『CodeBuild』『CodeDeploy』『CodePipeline』
※ Code兄弟は僕が勝手にそう読んでいるだけで公式ではありません笑

今回の記事では、AWSで構築するCI/CDの仕組みや、その時出てくるサービス（Code兄弟）の紹介していきます！
長くなってしまったので2つに分けました。
※ハンズオンというよりは、各サービスやAWSでのCI/CDの仕組みを書いた記事になりますので、ご注意ください。

- [AWSで始めるCI/CD 〜Code兄弟達の紹介〜（本記事）](https://qiita.com/hiroaki-u/items/b527264093eeb1e406e2)
- [AWSで始めるCI/CD 〜CI/CDの仕組み〜](https://qiita.com/hiroaki-u/items/ac0c1fb00b78af208af8)

それぞれ単発で読んでも理解できると思いますが、2つとも読んでいただけるとより理解が深まるかなと思います（というのは建前で両方読んでいただけると著者が喜びます笑）
本記事ではCode兄弟達がどのような役割なのか、ライフサイクル含めて書いています。

それではまずCode兄弟達を簡単に見ていきましょう！！

## Code兄弟達の概要

#### CodeCommit
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/7cf4843e-a554-3de3-0c21-75bdda62d1ec.jpeg" width="10%">

AWSのGitホスティングサービスです。
簡単にいうとGithubのようなものですね。
Githubのように幅広い機能はありませんが、他のAWSサービスとの連携が楽です。
結構シンプルなサービスなので、今回の記事では詳細には述べません。


#### CodeBuild
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/3597da51-6d95-35ea-947b-509db7394eed.jpeg" width="10%">


CodeBuildは自動テストやビルドを実行してくれるサービスです。
DockerImageから環境を立ち上げて、S3やCodeCommit, Githubからソースコードを取得した後にビルドやテストを実行してくれます。

#### CodeDeploy
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/646b64a5-a46d-d2c9-d1bb-d1c43f3e6495.jpeg" width="10%">


CodeDeployはデプロイを実行してくれるサービスです。
S3またはGithubにあるソースコードを、EC2やLambda, オンプレミス環境にデプロイしてくれます。
またECSにてBlue/Greenデプロイを実行する時にもCodeDeployを使って実行します。

#### CodePipeline
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/98e7418e-3e3a-454e-dac7-1e612c0189ac.jpeg" width="10%">

CodePipelineはCI/CDを管理してくれるサービスです。
CodeBuildの処理が終わればCodeDeployに処理を渡す等をしてくれます。

## CodeBuild, CodeDeploy, CodePipelineの説明

それではここからCodeBuild, CodeDeploy, CodePipelineに関して詳しく述べていきます。
※CodeCommitはそんなに複雑なサービスではないので説明を割愛します。

#### CodeBuild
先ほども記載しましたが、CodeBuildは自動テストやビルドを実行してくれるサービスです。
ではどのように処理が行われるのか、ライフサイクルの各フェーズをみていきます。

CodeBuildは以下のようなフェーズで処理が実行されます。

|フェーズ|説明|補足|
|:--|:--|:--|
|SUBMITTED|CodeBuildにビルドの依頼がくるステップです。この後CodeBuildが動きます。|-|
|QUEUED|queueに入ります。他のビルドがある場合は、待ちの状態です。|-|
|PROVISIONING|ビルド環境を立ち上げます|CodeBuildがデフォルトで用意しているDockerImageもしくは、自身で用意したDockerImageどちらも使えます。|
|DOWNLOAD_SOURCE|ソースコードを各ソースプロバイダーから取得します。|ソースプロバイダーはS3, CodeCommit, Github等が当たります。|
|INSTALL|ライブラリ等のインストールをしていきます。|ビルド環境でのパッケージのインストールにのみ使用することが推奨されています|
|PRE_BUILD|ビルド前の準備をします。|このフェーズを使用して Amazon ECRにサインインしたり、npmの依存関係をインストールする等ができます|
|BUILD|ビルドをします。メインのアクションです。||
|POST_BUILD|ビルド後の処理を実行します。|Maven を使用してビルドアーティファクトを JAR または WAR ファイルにパッケージ化する、Dockerイメージを Amazon ECR にプッシュする等ができます。|
|UPLOAD_ARTIFACTS|ビルドのアーティファクトファイルを指定の場所にアップロードします。| アーティファクトファイルはCI/CDにおいて、次の処理に渡すファイルのようなものです。 |
|FINALIZING|CodeBuildの処理を完了する処理です。|CodeBuildのビルド環境を閉じる等しています。|
|COMPLETED|CodeBuildの処理を全て完了したフェーズです。|-|


実行計画はbuildspec.ymlというファイルに記載していきます。
※ファイル名は必ずしも上記の名前にしなくても良いですが、公式ドキュメントには上記ファイル名で説明がされているので、本記事でも上記の名前を用いていきます。

buildspec.ymlは以下のようなパラメーターを設定してきます。

```yml:buildspec.yml
version: 0.2

# 各種コマンドを実行するユーザーを指定する。指定がない場合はrootユーザーが使われる。
run-as: Linux-user-name

# ビルド環境の設定。シェルや環境変数の設定を行う。指定しなくても良い
# 環境変数はkey, valueで直接指定もできるが、Systems Managerのパラメーターストアの値を用いることもできる
env: 

# プロキシサーバーにてCodeBuildを実行する際に指定する。指定しない場合はCodeBuildのデフォルトのまま実行される
proxy:

# バッチビルドの設定を行う。指定しない場合はバッチビルドが実行されない。
batch:

# 各種ビルドフェーズに関する設定
# 各フェーズにてrun-as（実行するユーザー）, on-failure（失敗したら次のフェーズにいくかどうか）, commands（実行コマンド）, finally（必ず_failureでも_実行するコマンド）等を設定
phases:
  # パッケージのインストールのコマンドを設定。
  install:
  # ビルド前に実行するコマンドを設定。
  pre_build:
  # ビルド時に実行するコマンドを設定
  build:
  # ビルド後の実行するコマンドを設定
  post_build:

# CodeBuildのレポート機能の設定。指定がない場合は、レポートが出力されない（ログとは異なるので注意）
reports:

# CodeBuildの出力をするための設定。出力先や出力ファイル等を指定する
artifacts:

# キャッシュの利用に関する設定。指定がない場合は特にキャッシュの利用がされない
# CodeBuildがS3キャッシュバケットへアップロードするための設定をする。
cache:
```

buildspec.ymlのパラメーターは一見多いですが、自動テストだけ実行したい等あればかなり記述は少なくて済みます。
例えば、PHPUnit(Laravel使用時)を使ってテストする場合はこうなります。
※環境変数が必要であれば、CodeBuildにて設定も可能です。

```yaml:buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - composer install
  build:
    commands:
      - php artisan test --env=test

artifacts:
  files:
    - '**/*'
```

結構シンプルですよね！
DockerImageをビルドしたりECRにpushしたりすると記述量も増えますが、やることが少ないと設定ファイルもシンプルなんですよね〜

ということで、CodeBuildのライフサイクルと設定ファイルを見てきました。
お次はCodeDeployのライフサイクルや設定ファイルを見ていきます。


#### CodeDeploy
先ほども記載しましたが、CodeDeployはデプロイを実行してくれるサービスです。
そのままですね笑

デプロイについては、ロードバランサーがデプロイグループに含まれるかどうかでフェーズがやや異なります。
ロードバランサーがデプロイグループに入っている時は、デプロイ中ロードバランサーからサーバーへの通信を停止させることができます。
※ デプロイグループとは、デプロイ対象をまとめたグループになります。

ライフサイクルのフェーズは以下の通りで、ロードバランサーが含まれるのが左の図、含まれるのが右の図です。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/f5881b85-a8ba-2c9b-0204-59c03180daba.png">

※図の引用：『[AppSpec の「hooks」セクション](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html)』

各フェーズを詳しく見ていきます。

- 基本的なライフサイクル

|ライフサイクルフェーズ|説明|イベント時にスクリプトが実行可能か|
|:--|:--|:--|
|ApplicationStop|前回のリビジョンのスクリプトを停止します。|◯|
|DownloadBundle|CodeDeployの一時的なディレクトリにファイルをコピーします。|✕|
|BeforeInstall|Install直前のインスタンスでタスクを実行できます。|◯|
|Install|CodeDeployの一時的なディレクトリから、デプロイ先のディレクトリにファイルをコピーします。|✕|
|AfterInstall|Install直後のインスタンスでタスクを実行できます。|◯|
|ApplicationStart|ApplicationStop で停止したサービスを再起動するために使用します。|◯|
|ValidateService|デプロイが正常に完了したことを検証します。|◯|

- ロードバランサーがデプロイグループにある時に生じるライフサイクル

|ライフサイクルフェーズ|説明|イベント時にスクリプトが実行可能か|
|:--|:--|:--|
|BeforeBlockTraffic|ロードバランサーから登録解除される前のインスタンスでタスクを実行できます。|◯|
|BlockTraffic|ロードバランサーからインスタンスに対するアクセスがブロックされます。|✕|
|AfterBlockTraffic|ロードバランサーから登録解除された後のインスタンスでタスクを実行できます。|◯|
|BeforeAllowTraffic|ロードバランサーに登録される前のインスタンスでタスクを実行できます。|◯|
|AllowTraffic|ロードバランサーからインスタンスへのアクセスが許可されます。|✕|
|AfterAllowTraffic|ロードバランサーに登録された後のインスタンスでタスクを実行できます。|◯|

*※イベント時のスクリプトについて、各ライフサイクルのイベントについて、自身で用意したスクリプトを実行することができます。*

CodeDeployではappspec.ymlというファイルに設定を記載します。
以下簡単に書いていますが、もっと詳細に知りたいという方は、『[AppSpec ファイル構造](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure.html)』『[AWS CodeDeploy の AppSpec を読み解く](https://dev.classmethod.jp/articles/code-deploy-appspec/)』を参考にしてみてください。

```yaml:appspec.yml
version: 0.0

# OSの設定をしていきます。
os: operating-system-name

# インスタンスにコピーするファイルについて指定します。
files:
  source-destination-files-mappings

# インスタンスへのコピー中に特別なアクセス権限をファイルのfilesセクションに適用する方法を指定します
permissions:

# デプロイライフサイクルのイベントにフックして実行するスクリプトをしていします。
hooks:
```

ちなみに、CodeBuild同様例を書いてみます。
例えば、デプロイ元ファイルの全ファイルをEC2の`/var/www/html`配下にデプロイしたい且つ、デプロイ終了後に`after_install.sh`を実行したい時、以下のような記述になります。

```yaml:appspec.yml
version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html

hooks:
  AfterInstall:
    - location: after_install.sh
      timeout: 120
      runas: root
```

ということで、ここまででCodeDeployを見てきました。
最後にCodePiplineを見ていきます！

#### CodePipeline
CodePipelineはCI/CDを管理してくれるサービスです。
CodePipelineが実際の処理をしてくれるというよりは、各サービスに処理を依頼してCI/CDを成立させるのが役割になります。まあ管理職のような立場ですね笑

CI/CDに関して、CodePipelineが管理できるサービスはこんな感じです。
結構色々なサービスを使えます！
※デプロイについては、記載しているサービス以外にも使用可能サービスがあります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/aa3634d3-2a7a-21ff-c8f2-c9c3e064d56f.jpeg" width="60%">

CodePipelineが実行する各フェーズをステージと呼びます。
例えば、ビルドのステージやデプロイのステージという風に呼びます。



CodePipelineがCI/CDを実行する際には、いくつかのルールがあります。
※図の引用『[パイプライン実行の仕組み](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/concepts-how-it-works.html)』

- ルール 1: 実行の処理中はステージがロックされる

各ステージは一度に1つの実行しか処理できないため、進行中のステージはロックされます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/7f0dfe79-a6da-71e1-ff64-44ece0b1619c.jpeg" width="60%">


- ルール 2: 後続の実行は、ステージのロックが解除されるまで待機する

例えば、パイプラインに2つの処理が走っている時（処理1, 処理2とします）、処理1がビルドステージにあったら処理2はビルドステージに移行できないイメージです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/a421abdf-c364-a216-158b-16c411adeba6.jpeg" width="60%">


- ルール 3: 待機中の実行はより最近の実行によって置き換えられる


例えば、パイプラインに3つの処理が走っている（処理1, 処理2, 処理3）とします。
処理2が待機中で処理3が前ステージを終えると、待機の優先順位が処理3>処理2になります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/799854/1050af5b-e0ba-c4d6-6ce4-3ff98703fdac.jpeg" width="60%">

CodeBuildとCodeDeployと組み合わせた説明は[AWSで始めるCI/CD 〜CI/CDの仕組み〜](https://qiita.com/hiroaki-u/items/ac0c1fb00b78af208af8)にて説明しておりますので、良かったら見ていってください！
ということで、本記事でのCodePipelineのご紹介は以上になります。

## おわり

一通りCode兄弟の役割やライフサイクルの詳細を見ていきました。
案外内部では色々な処理がなされていましたよね！
これらのサービスを使ってCI/CDを構築する時の仕組みは[AWSで始めるCI/CD 〜CI/CDの仕組み〜](https://qiita.com/hiroaki-u/items/ac0c1fb00b78af208af8)をご参照ください！
最後まで読んでいただきありがとうございました！


## 参考文献
#### CodeBuild
- [Build Phase](https://docs.aws.amazon.com/codebuild/latest/APIReference/API_BuildPhase.html)
- [AWS CodeBuild におけるビルドの詳細の表示](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/view-build-details.html)
- [CodeBuild のビルド仕様に関するリファレンス](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html)
- [バッチビルドのビルド仕様 (buildspec) のリファレンス](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/batch-build-buildspec.html)

#### CodeDeploy
- [CodeDeployって何ですか](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/welcome.html)
- [AWS CodeDeploy の AppSpec を読み解く](https://dev.classmethod.jp/articles/code-deploy-appspec/)
- [CodeDeployのApplicationStopイベントフックはどう実行される?](https://dev.classmethod.jp/articles/codedeploy-applicationstop-hook-not-executed-for0first-deployment/)
- [AWS CodeDeploy のよくある質問](https://aws.amazon.com/jp/codedeploy/faqs/)
- [AppSpec の「hooks」セクション](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html)
- [AppSpec ファイル構造](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure.html)

#### CodePipeline
- [アクション構造リファレンス](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/action-reference.html)
- [パイプライン実行の仕組み](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/concepts-how-it-works.html)