CodeDeployを使ってアプリケーションをEC2インスタンスへデプロイする

# はじめに
CodeDeployを使ってEC2インスタンスへアプリケーションをデプロイしたいと思います。
基本的にはコマンドラインを利用しますが、一部難しい部分があるためそこはコンソール操作で行います。


# 前提条件
以下の準備ができている上で作業を行います。

- **GitHub アカウント：** アプリケーションのアップロード先を用意するのに必要です。
- **EC2インスタンス：** アプリケーションのデプロイ先で利用します。
  - IAMロールがアタッチされていること。
  - sshとhttpアクセスができること。
- **コマンドインストール**
  - **gitコマンド：** リポジトリへプッシュするのに必要です。
  - **aws-cli：** CodeDeployやIAMロールを作成するのに利用します。


# 構成
![スクリーンショット 2021-04-24 9.26.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/232d63cd-55c7-79de-85dc-27ec39bf1fb0.png)


# 作業
まずはGitHub関連の設定を行い、その後にCodeDeployの設定を行なっていきます。

## GitHub リポジトリの準備
GitHubへログインし **[ New ]** をクリックします。
![スクリーンショット 2021-04-22 21.56.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/410dce8b-1ba1-5d44-de5c-323f67ce5d7c.png)
**Repository name** に `CodeDeployGitHubDemo` を入力し、**Public** を選択して **[ Create repository ]** をクリックします。
![スクリーンショット 2021-04-22 21.57.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/f2e55172-8724-ebe6-9a5a-81074c1b0f5d.png)
コマンドラインでリポジトリの初期コミットを行います。

```bash:作業ディレクトリの用意
$ mkdir /tmp/CodeDeployGitHubDemo
$ cd /tmp/CodeDeployGitHubDemo
```

```bash:READMEの作成
$ touch README.md
```

```bash:init
$ git init
```

```bash:add
$ git add README.md
```

```bash:commit
$ git commit -m "My first commit"
```

```bash:remote
$ git remote add origin https://github.com/************/CodeDeployGitHubDemo.git
```

```bash:push
$ git push -u origin master
```
以上でリポジトリの準備が完了です。


## アプリケーションをGitHubリポジトリへアップロード
今回はAWSで提供しているサンプルアプリケーションを利用します。
作業は先ほどgitで準備をしたディレクトリで行います。
まず、アプリケーションをダウンロードします。

```bash:アプリケーションのダウンロード
$ aws s3 cp s3://aws-codedeploy-ap-northeast-1/samples/latest/SampleApp_Linux.zip . --region ap-northeast-1
```

リポジトリへアップロードをします。

```bash:展開
$ unzip SampleApp_Linux.zip
$ rm SampleApp_Linux.zip
```

```bash:add
$ git add .
```

```bash:commit
$ git commit -m "Added sample app"
```

```bash:push
$ git push
```
以上でアップロードが完了です。

また、CodeDeployでは `appspec.yml` というファイルが必要になります。
今回ダウンロードしたコンテンツにはこのファイルが存在するため、そのまま利用します。

```yaml:appspec.yml
version: 0.0
os: linux
files:
  - source: /index.html
    destination: /var/www/html/
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
```
ファイルの詳細説明は割愛しますが、簡単に説明すると **apacheをインストール** して **index.html** を配置しています。


## CodeDeployエージェントのインストール
インスタンスにサインインし、エージェントをインストールします。
まずはエージェントをインストールするために必要なパッケージのインストールです。

```bash:必要パッケージのインストール
$ sudo yum install ruby
$ sudo yum install wget
```

エージェントインストールツールのダウンロードを行います。

```bash:インストールツールのダウンロード
$ wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
--2021-04-22 05:30:49--  https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com (aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com) をDNSに問いあわせています... 52.219.16.215
aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com (aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com)|52.219.16.215|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 17231 (17K) []
`install' に保存中

100%[==============================================================================================================================>] 17,231      --.-K/s 時間 0s      
```
今回は東京リージョンですが、もし他のリージョンの場合は `aws-codedeploy-ap-northeast-1` と `ap-northeast-1` の部分を以下を参考に変更してください。
[地域別のリソースキットバケット名](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names)

インストールを行います。

```bash:実行権限付与
$ chmod +x ./install
```

```bash:エージェントインストール
$ sudo ./install auto
```
インストールが完了したら以下のコマンドで起動していることを確認しておきます。

```bash:インストール確認
$ sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID 7801
```
以上でCodeDeployエージェントのインストールが完了ですが、たまにうまく起動していない場合があるのでログを確認しておくと良いです。

```bash:codedeploy-agent.log
$ tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log
```
もし、以下のエラーが出力されていた場合、エージェントがIAMロールをうまく認識できずに起動している状態になります。

```text:ERRORログ
2021-04-22 11:27:13 ERROR [codedeploy-agent(6387)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Missing credentials - please check if this instance was started with an IAM instance profile
```
IAMロールがインスタンスにアタッチされていることを確認した上でエージェントの再起動をしてください。
今回はS3アクセスが不要なため、ロールに必要な権限はありませんが、付与されていないとエージェントエラーとなりCodeDeployを実行した際に失敗となってしまいます。


## CodeDeploy で利用するサービスロールの作成
まず、ロールを作成するのに必要な信頼ポリシーを用意します。

``` bash:信頼ポリシーの作成
$ vim trust-policy.json
```

```text:trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "codedeploy.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```
ポリシーを作成したらサービスロールを作成します。

```bash:サービスロールの作成
$ aws iam create-role \
  --role-name CodeDeployGitHubDemo-Role \
  --assume-role-policy-document file://trust-policy.json
```

CodeDeploy で利用するポリシーをアタッチします。

```bash:ポリシーのアタッチ
$ aws iam attach-role-policy \
  --role-name CodeDeployGitHubDemo-Role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
```

以上でロールの準備ができました。


## CodeDeploy の設定
デプロイするためのアプリケーションとデプロイグループの作成を行います。

### アプリケーションの作成
アプリケーション名は `CodeDeployGitHubDemo-App` で作成します。

```bash:アプリケーションの作成
$ aws deploy create-application --application-name CodeDeployGitHubDemo-App
```
![スクリーンショット 2021-04-21 16.16.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/9a7fe759-6a9e-5a7a-376c-42edcf972539.png)


### デプロイグループの作成
アプリケーションを作成したらデプロイグループの作成です。
デプロイグループ名は `CodeDeployGitHubDemo-DepGrp` にします。
また、対象インスタンスを指定するためのタグキーに `CodeDeploy` を指定し、バリューを `Demo` を設定します。
これで、CodeDeployタグにDemoという値が設定されているインスタンスに対してデプロイ処理が行われるようになります。

```bash:デプロイグループの作成
$ aws deploy create-deployment-group \
  --application-name CodeDeployGitHubDemo-App \
  --ec2-tag-filters Key=CodeDeploy,Type=KEY_AND_VALUE,Value=Demo \
  --deployment-group-name CodeDeployGitHubDemo-DepGrp \
  --service-role-arn arn:aws:iam::123456789012:role/CodeDeployGitHubDemo-Role
```
![スクリーンショット 2021-04-21 17.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/14a3742c-b95f-bf95-8b8e-8c3e8e0b50da.png)


### デプロイの作成
GitHub連携を行う都合上、初めはコンソールから行う必要があります。
まずは **[ デプロイの作成 ]** をクリックします。
![スクリーンショット 2021-04-21 17.18.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/645f0ed4-a172-e5f6-35c5-79b83f35fcb1.png)
先ほど作成した **デプロイグループ** を指定し、**リビジョンタイプ** のところではGitHubを指定します。
**GitHubトークン名** に先ほどアップロードしたGitHubのアカウントを入力すると **GitHubに接続** がクリックできるようになるためクリックします。
![スクリーンショット 2021-04-21 22.14.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/baf9a5e1-e5b2-82cb-4cb7-90bf9e789d44.png)
すると以下のポップアップが表示されるため **[ Authorize aws-codesuite ]** をクリックします。
![スクリーンショット 2021-04-21 22.14.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/94b1d602-1fb3-649b-982c-20751fcf05cc.png)
次に **[ 確認 ]** をクリックします。
![スクリーンショット 2021-04-21 22.15.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/b6ec6f74-f677-5cab-f5d5-688dedeafb8a.png)
成功すると **リポジトリ名** と **コミットID** が表示されるので入力し、一番下にある **[ デプロイの作成 ]** をクリックして完了です。
![スクリーンショット 2021-04-21 22.16.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/2807a959-0173-a0cd-be38-8d054a6f70dd.png)
以下のような画面へ遷移し、**進行中** が **成功** になれば無事にデプロイ完了となります。
![スクリーンショット 2021-04-21 22.16.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/a0f8bf2c-8663-2208-2929-9853d97eda0e.png)
ブラウザから対象インスタンスへアクセスすると以下の画面が確認できます。
![スクリーンショット 2021-04-22 10.44.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/a758c955-3fb5-ee3d-90ce-1f460ec99ec3.png)
また、一度GitHub連携できていれば２回目以降はコマンドで実行可能になります。

```bash:
$ aws deploy create-deployment \
  --application-name CodeDeployGitHubDemo-App \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --deployment-group-name CodeDeployGitHubDemo-DepGrp \
  --description "My GitHub deployment demo" \
  --github-location repository=************/CodeDeployGitHubDemo,commitId=7e0a45963967c307d837477e74f5d34798a65e68
```


# おわりに
今回、S3を利用しないためIAMロールは不要と思ったのですがないとうまく動かないことがわかりました。
基本を知ることで、一つ一つの設定について理解を深めることができて良かったです。