CodeBuild+CodeDeploy+CodePipelineでEC2に自動デプロイしてみた

# やってみたこと概要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/c16ee1af-2d4a-c07a-c122-5b332c3771b2.png)

1. githubリポジトリが更新されるとパイプラインのSourceが実行される
    * デプロイするソース：[vue-chat](https://github.com/butorisa/vue-chat)
    * Sourceの成果物はS3の「codepipeline-ap-northeast-1-…」バゲット
`vue-chat/SourceArti`に出力
1. vue-chat/SourceArtiに出力されたソースをCodeBuildがビルド
    * 同バゲット`vue-chat/BuildArtif`にビルド済みソースを出力
1. vue-chat/BuildArtifのビルド済みソースをCodeDeployが受け取りEC2に配置
2. 配置されたソース内のappspec.ymlの内容が実行されてデプロイ完了

# CodeBuild

AWSマネジメントコンソールでCodeBuildを選択しビルドプロジェクトを作成

githubのvue-chatリポジトリをビルドする設定
![](https://storage.googleapis.com/zenn-user-upload/3b6hto0d5vzxkpgerexnjwe1ufml)

### Buildspec
Buildspecは「ビルドコマンドの挿入」を選択し、以下のコマンドを記述

```yml
version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 10
  pre_build:
    commands:
      - npm update -g npm
      - npm install
  build:
    commands:
      - npm run build
artifacts:
  files:
    - '**/*'
```

* phases
	* ビルド工程を記述する宣言
* install
	* ビルド環境を宣言
* pre_build
	* node.jsをCodeBuildのビルド環境にインストール
* build
	* npmビルド実行
* artifacts
	* ビルドしたソースを出力する宣言
* files
    * 出力するソース（`'**/*'`はソース一式　本来は`'dist/*'`が良さそう）

CodeBuildびアーティファクトの設定はマネジメントコンソールからもできるが
「セマンスティックバージョニングの有効化」にチェックをつけると
上記のBuildspecの内容が優先される
![スクリーンショット 2020-10-18 22.20.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/2a69a9ef-adf1-11c6-cbd0-918abfd7405d.png)


### IAMロール（CodeBuild）
CodeBuildのサービスロールに「AmazonS3OutpostsReadOnlyAccess」を追加して
ビルド済みソースをS3にアップロードできるようにする
![スクリーンショット 2020-10-18 20.50.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/072d9999-f520-a62c-15d8-fe5490a379fd.png)

サービスロールはCodeBuild-ビルドプロジェクト-環境に記載されている
![スクリーンショット 2021-12-20 0.20.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/5b8adad9-fb73-c812-a11e-7a484b067e12.png)


### ログ（CodeBuild）
CodeBuildのビルド実行ログはS3に出力するようにした
![スクリーンショット 2020-10-18 22.24.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/5dbb1e3b-773d-fccb-ff0f-41ab7663f6cd.png)

CodeBuildでビルド実行するとS3には圧縮されたログファイルが出力される
![スクリーンショット 2020-10-18 22.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/389f7fe7-04bc-283d-aacf-df0566772f4b.png)


# デプロイするEC2を作成
AmazonLinux2でEC2インスタンスを作成
![スクリーンショット 2020-10-18 21.34.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/94db6484-cff7-e19b-0955-9d0383fe5012.png)

### IAMロール（EC2）
CodeBuildがS3に出力したビルド済みソースをEC2に配置するために「AmazonS3ReadOnlyAccess」を設定
![スクリーンショット 2020-10-18 21.39.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/ac7bed69-a746-e742-3528-f33ee216fe4f.png)

### CodeDeploy Agentインストール
CodeDeployからEC2にデプロイができるようにEC2にagentライブラリをインストール
下記コマンドは[EC2デプロイのためにCodeDeployを導入する](https://qiita.com/yukofeb/items/e077fc8755416c904032)から引用しています

```
# ec2-userで実行
$ sudo yum update
$ sudo yum install ruby
$ sudo yum install aws-cli
$ cd /home/ec2-user
$ aws s3 cp s3://aws-codedeploy-ap-northeast-1/latest/install . --region ap-northeast-1
$ chmod +x ./install
$ sudo ./install auto
$ sudo service codedeploy-agent status
```

### アプリケーション起動に必要なライブラリをインストール
今回はVue.jsプロジェクトを起動するのでvue-cliをEC2にインストール

```
$ npm install -g @vue/cli
```

# CodeDeploy
デプロイプロジェクトを作成
![スクリーンショット 2021-12-20 0.21.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/9d7f1d2c-f3d5-22c1-f547-d1dfab68660a.png)

### IAMロール（CodeDeploy）
CodeDeployのサービスロールは
CodeBuildで出力したビルド済みソースを受け取るため「AmazonS3ReadOnlyAccess」と
EC2にソースを配置するため「AmazonEC2FullAccess」を設定
（AmazonEC2RoleforAWSCodeDeployだとPermissionErrorになってしまった）

![スクリーンショット 2020-10-18 21.25.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/e4c721a5-7d8c-a385-7bba-eac76621426e.png)

# githubプロジェクトにデプロイ設定
CodeDeployでデプロイするためにプロジェクトにデプロイ工程を記述したファイルを作成
![スクリーンショット 2020-10-18 22.05.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/83a6a4fa-3393-94a6-506a-8ad69456c7fc.png)

### appspec.yml
デプロイするプロジェクトのルートディレクトリにappspec.ymlを作成

```appspec.yml

version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html
hooks:
  ApplicationStart:
    - location: /scripts/codedeploy_start.sh
      timeout: 180
```

* files.destination
    * S3のソースを配置する場所
* ApplicationStart.location
    * アプリケーション配置後の処理を記述したshファイルを指定

### アプリケーション起動shファイル
appspec.ymlで指定した「codedeploy_start.sh」を作成する
npmコマンドでVue.jsアプリケーションを実行するだけ

```codedeploy_start.sh
#!/bin/bash

npm run serve
```

# CodePipeline
上記で作成・設定した内容でパイプラインを作成
![スクリーンショット 2020-10-18 22.18.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/b1c81c02-f66d-87a1-660a-a204816fa050.png)

# パイプライン実行

これでリポジトリに変更をプッシュするだけでデプロイできちゃうのか(*ﾟ▽ﾟ*)ワクワク

#### しかし、現実は
CodeDeployが失敗。。。
![スクリーンショット 2020-10-19 0.05.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/ffbbeb0d-5cf3-be60-f483-d07ee7cb78d7.png)

エラーを見てみると`npm run serve`した時にpackage.jsonが見つからなかった模様
![スクリーンショット 2020-10-19 0.06.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530205/3a1b73da-5782-9538-48b6-ab44fb5fdace.png)

appspec.ymlからcodedeploy_start.shを実行した時のカレントディレクトリは`/`なので
codedeploy_start.shで`cd 配置したソースのディレクトリ`を記述する必要がある

配置したソースのディレクトリにはパイプライン実行毎に振られるランダムなIDが含まれているのでどのように記述すれば良いか調査中
（配置ディレクトリ例：`/opt/codedeploy-agent/deployment-root/3ee0a546-27db-4534-a055-098b9173f625/d-4ARZ3L0Q6/deployment-archive/vue-chat`）