AWS CodeDeployとCodePipelineを触ってみた

#きっかけ
[前回記事でAWS Copilotを触ってみて](https://qiita.com/takeh/items/23d7b3300dc008bb9dbc)色々便利だったので、Copilot Pipelineにも手を出してみようと思いました。
が、そもそもCodePipelineを触ったことがなかったので、まずこちらを触ってみることにしました。

#目標構成
ローカルで編集したindex.htmlファイルをGitHubにプッシュするだけで、自動でEC2内のindex.htmlファイルを更新し即座に公開内容に反映したい。

#準備
##EC2インスタンスの作成
CodeDeployで使うEC2インスタンスを作成しておきます。以下のものが必要になります。

- 以下の条件のVPC
 - インターネットゲートウェイがアタッチされている
 - `送信先：0.0.0.0/0`、`ターゲット：上記のインターネットゲートウェイ`のルートがルートテーブルに設定されている

- 以下の条件のロール
 - 一般的なユースケース EC2に、`AWSCodeDeployRole`ポリシーと`AmazonS3FullAccess`ポリシーが付与されたロール
 - ユースケースが`CodeDeploy`のロール

- 以下の条件のEC2インスタンス
 - 作成したVPCとサブネットの付与
 - 作成した`AWSCodeDeployRole`ポリシーと`AmazonS3FullAccess`ポリシーが紐づいているEC2ロールの付与
 - キーがNameのタグの付与（値は任意）
 - セキュリティーグループに`タイプ:HTTP`（ソースは初期値の0.0.0.0/0, ::/0のまま）の追加

##CodeDeployエージェントをEC2インスタンスにインストール
作成したEC2インスタンスにCodeDeployエージェントをインストールします。

```bash
$ ssh -i 『EC2作成時に指定したpemファイル』 ec2-user@『EC2のIPv4パブリックIP』  # 作成したEC2インスタンスにSSH接続
$ sudo yum update
$ sudo yum install ruby
$ sudo yum install wget  # すでにインストール済みの可能性あり
$ cd /home/ec2-user
$ wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install  # 下記コメント参照
$ chmod +x ./install
$ sudo ./install auto
```
上記のインストールの詳細は[Amazon Linux 用または RHEL 用の CodeDeploy エージェントをインストールします。 - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html)を確認してください。

6行目の`$ wget https://〜`の行はリージョンによってURLが変わってきます。
変更する必要がある箇所は以下の赤文字の箇所です。
$ wget https://<font color="Red">_bucket-name_</font>.s3.<font color="Red">_region-identifier_</font>.amazonaws.com/latest/install
リージョン毎の入れるべき値は[CodeDeploy リソースキットのリファレンス - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names)を確認してください。

##必要なファイルをGitHubに上げる
[AWSの公式サンプルファイルがGitHubに上がっている](https://github.com/aws-samples/aws-codedeploy-samples/tree/master/applications/SampleApp_Linux)ので今回はこれを利用します。
サンプルは以下のような構成になっています。

```bash
.
├── LICENSE.txt
├── appspec.yml    # CodeDeployに必須のファイルで、デプロイ時に実行する内容が書かれている
├── index.html     # 今回の更新対象のファイル
└── scripts        # デプロイ時に呼び出されるスクリプトが格納されている
    ├── install_dependencies
    ├── start_server
    └── stop_server
```

appspec.ymlの中身は以下のような形で、どのタイミングで何を実行するか指示するファイルです。
appspec.ymlには以下のルールがあります。

- CodeDeployに必須のファイル
- appspec.ymlのファイル名は固定
- appspec.ymlを格納する場所は同期させるフォルダのルート

詳しくは以下のサイトを確認してください。

- [CodeDeploy AppSpec File リファレンス - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file.html#appspec-reference-server)
- [AppSpec の「hooks」セクション - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-server)
- [AWS CodeDeploy の AppSpec を読み解く | Developers.IO](https://dev.classmethod.jp/articles/code-deploy-appspec/)

```bash
version: 0.0
os: linux
files:
  - source: /index.html             # 同期させる元
    destination: /var/www/html/     # 同期させる先（今回はEC2インスタンスの中身）
hooks:
  BeforeInstall:                    # 上記のファイルセクションで指定した場所にファイルをコピーする前
    - location: scripts/install_dependencies    # 必須項目。実行したいスクリプトの場所を指定
      timeout: 300                              # オプション。スクリプト実行時のタイムアウトを秒で指定
      runas: root                               # オプション。スクリプトの実行ユーザーを指定
    - location: scripts/start_server
      timeout: 300
      runas: root
  ApplicationStop:                  # アプリケーションのリビジョンが開始する直前
    - location: scripts/stop_server
      timeout: 300
      runas: root
```

スクリプトファイルはシンプルにこのような形です。（3ファイルまとめて）

```bash
### install_dependencies ###
#!/bin/bash
yum install -y httpd

### start_server ###
#!/bin/bash
service httpd start

### stop_server ###
#!/bin/bash
isExistApp=`pgrep httpd`
if [[ -n  $isExistApp ]]; then
    service httpd stop        
fi
```

# AWS CodeDeployの設定
AWSマネジメントコンソールからCodeDeployの設定を行います。

1. AWS マネジメントコンソールからCodeDeployに飛ぶ
2. 左のメニューから`アプリケーション`をクリックし、アプリケーション画面右上の`アプリケーションの作成`をクリックする
3. アプリケーションの作成画面で、以下を入力・選択し`アプリケーションの作成`をクリックする
 - アプリケーション名：任意の名前を入力
 - コンピューティングプラットフォーム：`EC2/オンプレミス`を選択

4. アプリケーションを作成して遷移した画面下部のデプロイグループエリア右上の`デプロイグループの作成`をクリックする
5. デプロイグループの作成画面で、以下を入力・選択し`デプロイグループの作成`をクリックする
 - デプロイグループ名：任意の名前を入力
 - サービスロール：本記事の始めに作成した、ユースケースがCodeDeployのロールを指定
 - 環境設定：`Amazon EC2 インスタンス`にチェックを入れ、EC2に設定したタグを指定
 - Load balancer：`ロードバランシングを有効にする`のチェックを外す

#CodeDeployの動作確認
CodeDeployの設定が終わったら動作確認をしてみます。

1. デプロイグループが作成できたら、その画面の右上の`デプロイの作成`をクリックする
2. Create deployment画面で、以下を選択・入力し`デプロイの作成`をクリックする
 - デプロイグループ：作成したデプロイグループを指定（自動で指定されているはず）
 - リビジョンタイプ：`アプリケーションは GitHub に格納されています`を選択
 - GitHub トークン名：検索入力欄にアカウントのエイリアスを入力し`GitHubに接続`をクリックする（未接続の場合のみ）
 - リポジトリ名：GitHubの『アカウント名』/『リポジトリ名』を入力（「/」前後にスペースは入れない）
 - コミットID：GitHubのCodeタブのコミット数リンク→最新コミット右のコピーボタンでコピーした値

　　![スクリーンショット 2020-07-24 21.09.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361666/f8e810e1-034f-9fe5-8dad-1d90f4158e7e.png)
デプロイの作成を行うとデプロイが開始され、デプロイのステータスが表示されます。
デプロイ処理中は`進行中`ステータスで、終わるまで時間がかかるのでステータスが`成功`になるまで少し待ちます。
表示されている画面一番下の`デプロイのライフサイクルイベント`の一覧のイベント列の`View events`をクリックすると`appspec.yml`のhooksで出てきたイベントの実行結果が確認できます。

##EC2のファイルの確認
デプロイが成功したので、EC2の`/var/www/html/`（appspec.ymlのdestinationで指定した場所）を確認するとindex.htmlが格納されています。

```bash
$ ssh -i 『EC2作成時に指定したpemファイル』 ec2-user@『EC2のIPv4パブリックIP』
$ cd /var/www/html/
$ ls
index.html    # ファイルが格納されている！
```

##ブラウザでの確認
EC2の`IPv4パブリック IP`の値をブラウザに貼り付けてアクセスすることで、index.htmlの内容を確認出来ます。

これでCodeDeployは動かせるようになりました :tada:
ただ毎回コミットIDを調べてデプロイを作成するのは手間なので、GitHubにプッシュしたらEC2インスタンスにアップされるまでを自動で行えるようCodePipelineで設定します。

#AWS CodePipelineの設定
AWSマネジメントコンソールからCodePipelineの設定を行います。

1. AWS マネジメントコンソールからCodePipelineに飛ぶ
2. パイプラインの一覧画面の右上の`パイプラインを作成する`をクリックする
3. パイプラインの設定を選択する画面で、以下を入力し`次へ`をクリックする
 - パイプライン名：任意の名前を入力
4. ソースステージを追加する画面で、以下を選択・入力し`次へ`をクリックする
 - ソースプロバイダー：GitHub
 - `GitHubに接続する`をクリック
 - リポジトリ名：GitHubの『アカウント名』/『リポジトリ名』を入力（「/」前後にスペースは入れない）
 - ブランチ：対象のブランチを選択

5. ビルドステージを追加する画面で、AWS CodeBuildを指定できます。
   が、今回は使わないので`ビルドステージをスキップ`をクリックする
6. デプロイステージを追加する画面で、以下を選択して`次へ`をクリックする
 - デプロイプロバイダー：`AWS CodeDeploy`を選択
 - アプリケーション名：CodeDeployで作成したものを選択
 - デプロイグループ ：CodeDeployで作成したものを選択
 7. レビュー画面で、内容を確認して`パイプラインを作成する`をクリックする

CodePipelineの設定が終わると、自動でGitHubからファイルを取得してデプロイが行われます。
ローカルのindex.htmlファイルを適当に編集してGitHubにプッシュし、ブラウザで確認してみましょう。
ばっちりローカルでの変更がブラウザで反映されている！:tada: ...はず。

#まとめ
サービス名の頭のAWSとAmazonはどう違うのだろう..

#We're hiring!
AIチャットボットを開発しています。
ご興味ある方は [Wantedlyページ](https://www.wantedly.com/projects/266837) からお気軽にご連絡ください！

# 参考
[Amazon Linux 用または RHEL 用の CodeDeploy エージェントをインストールします。 - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html)
[CodeDeploy リソースキットのリファレンス - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names)
[CodeDeploy AppSpec File リファレンス - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file.html#appspec-reference-server)
[AppSpec の「hooks」セクション - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-server)
[aws-samples / aws-codedeploy-samples - GitHub](https://github.com/aws-samples/aws-codedeploy-samples/tree/master/applications/SampleApp_Linux)
[AWS CodeDeploy の AppSpec を読み解く | Developers.IO](https://dev.classmethod.jp/articles/code-deploy-appspec/)
[【はじめてのCI/CD】AWSでやってみるDevOps最初の一歩、CodeDeploy、CodePipelineを使った自動デプロイのハンズオン - Youtube](https://www.youtube.com/watch?v=8mPm7jolnVk)