【CodePipeline・CodeDeploy】リモートブランチにpushするだけで、EC2に自動デプロイする（ハンズオン）

## 概要
GitHubで管理しているブランチにpushするだけで、自動でサーバーにデプロイする方法をご紹介します。
ハンズオンなので、深く考えなくても構築できるはずです。

## 図解
完成図は↓のようなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/c85ee946-353b-f668-79a6-836f6004eb7f.png)


①ローカルのブランチをGitHubにpushする
②GitHubの対象のブランチの変更をトリガーとして、CodePipelineが走る
②対象のEC2インスタンスにデプロイする

自動デプロイが実現すれば、ファイルをいちいちサーバーにコピーしなくても、pushするだけでコードの変更が反映されるようになります。

## 作業の流れ
### 事前準備
#### デプロイ先のEC2インスタンスを立ち上げる
今回デプロイしたいEC2インスタンスを立ち上げておきます。
インスタンスの起動方法は<a href="https://qiita.com/shogo30/items/d2e0fa2e7ecafc690952">こちら</a>の記事をご参照ください。

### CodeDeployの設定
<details>
  <summary>CodeDeployにアタッチするIAMロールの作成</summary>

  #### IAMロールの作成
  IAM > ロール > ロールを作成　をクリックする
  ![image (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/80d3511c-bbd8-2036-4116-2af3e4fdf7a6.png)

  **ユースケース**は**CodeDeploy**を選択する
  ![image (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/44deebe8-e24d-a192-38f2-91aa2ae6c43c.png)

  ポリシーに**AWSCodeDeployRole**があることを確認して「次へ」
![image (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/5016a9fb-019d-25b8-5083-1e4c48c3ebbd.png)

適当にロール名をつける。これは後に使用するのでわかりやすいものにする。
![image (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/1480061b-48ae-b51d-e65f-b3c61a145cda.png)

ロールを作成したら**信頼関係**タブを開き、ポリシーを確認する
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "codedeploy.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```
これでOK。

</details>

<details>
  <summary>アプリケーションの作成</summary>
  
  #### アプリケーションの作成
  AWSのCodeDeploy > アプリケーション > アプリケーションの作成をクリック
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/83c3cdb3-a9cb-2a49-a3f4-0db154e2cb0d.png)

  アプリケーション名を任意の名前でつける
  **コンピューティングプラットフォーム**は、今回はEC2にデプロイするので**EC2/オンプレミス**を選択
  
  ![image (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/39b13b7f-f8c5-d397-aa94-f06b6c79fcef.png)

</details>

<details>
  <summary>デプロイグループの作成</summary>

  #### デプロイグループの作成
  先ほど作成したアプリケーションをクリックして、**デプロイグループ**タグから**デプロイグループの作成**をクリック
  
![image (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/9460e3b9-f3d4-93db-f1e0-b9dd3e41aff9.png)

デプロイグループ名はわかりやすいものにし、**サービスロール**に先ほど作成したIAMロールを選択する
![image (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/1b71d321-a6df-29f9-3986-ca71cda1fc06.png)

**デプロイタイプ**では、今回は**インプレース**を選択する

**環境設定**では、対象のEC2にデプロイするので**Amazon EC2インスタンス**を選択し、
キー : Name
値 : EC2インスタンスの名前（deploy-testで作成済み）
にする。

今回はインスタンス一つにデプロイするが、複数のインスタンスがある場合はここで全て選択する。![image (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/e20496d0-cb7f-43dc-8b84-8c79ec4c0aa0.png)

Load balancerタグの**ロードバランシングを有効にする**と、デプロイ中に対象インスタンスにトラフィックが行かないようにすることができる。
デプロイ中はファイルの変更が行われているので、アクセスするタイミングによってはエラーになることがある。
今回は気にしないのでチェックを外しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/06ad0484-b30a-fbed-1631-c0e82496382e.png)

デプロイグループの作成をクリック
</details>

### CodePipelineの設定

<details>
  <summary>CodePipelineの設定</summary>
  
デベロッパー用ツール > CodePipeline > パイプライン でパイプラインを作成するをクリック
  ![image (15).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/ef4b4bd7-ffa2-bb0c-d51f-1259af43a1aa.png)
#### パイプラインの設定を選択する
わかりやすいパイプライン名をつける
**パイプラインタイプ**はどちらでもいいです
機能や料金体系が異なります。<a href="https://aws.amazon.com/jp/codepipeline/pricing/">参考</a>
今回は**v1**を選択します。
![image (16).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/7e09ef15-3fa8-83a7-0ebf-1b2ba22c7946.png)

**サービスロール**は**新しいサービスロール**を選択します
![image (17).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/fc9f8927-cf16-21ae-7053-3b198f8b84ef.png)

#### ソースステージを追加する
パイプラインが走るトリガーとなるソースを設定します。
今回はGitHubのdeploy_testリポジトリのmainブランチの変更をトリガーにします。
**ソースプロバイダー**で**GitHub(バージョン2)**を選択し、**GitHubに接続する**をクリックします。
![image (18).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/6b925406-d400-1353-bead-2e572e3b1e9d.png)

↓の画面が開き、接続名を適当なものにして、「GitHubに接続する」をクリックします
![image (19).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/10d4fcaa-5f8f-ee13-a835-7e786419f428.png)

GitHubにAWSが接続することを許可します。
![image (20).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/f5a9a666-a35b-566a-49de-9e8e27974548.png)

「新しいアプリをインストールする」をクリック
![image (21).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/f2ef719c-0d02-f4a8-4b42-564a75ebd472.png)

AWS Connector for Githubをインストールします
![image (22).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/fdb8c119-2bff-52fd-4318-2c234e83d260.png)

すると、接続したGitHubのリポジトリが選択できるので、今回使用する「deploy_test」の「main」ブランチを選択します。
![image (23).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/7701f18a-3089-8d3b-38c8-808aa690d7a3.png)

#### ビルドステージを追加する
CodeBuildでは、ソースコードをコンパイルし、ユニットテストを実行したりできます。
今回はデプロイするだけなので、ビルドステージをスキップします。

#### デプロイステージを追加する
どこにデプロイするのかを設定します。
**デプロイプロバイダー**は、**AWS CodeDeploy**を使用します。
アプリケーション名とデプロイグループには、先ほど作成したアプリケーションを選択します。
![image (24).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/ee447ca8-5aec-681f-a960-12ab6a7ca17c.png)

最後に設定内容を確認し、パイプラインを作成します。

</details>

### EC2インスタンスの設定

<details>
  <summary>IAMロールの作成</summary>
  EC2インスタンスに適切なIAMロールをアタッチしないとデプロイできないので、指定されたIAMポリシーを持つIAMロールを作成する。

  #### IAMポリシーの作成
IAM > ポリシー　からIAMポリシーを作成する
  ![image (25).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/69a97eb9-57af-4960-55f0-0ef122561055.png)

「アクセス許可を指定」ページでJSONを選択し、
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}
```
とする

  ![image (26).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/089bab9a-f543-e402-372d-82f0dc71ecba.png)

わかりやすい名前をつけて保存する。
![image (27).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/359c5a7d-a43c-fec5-604a-477ff8e23eb8.png)

#### IAMロールの作成
先ほど作成したIAMポリシーからIAMロールを作成する。
IAM > ロール　> ロールを作成
![image (28).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/8c153032-9f62-dd55-da1a-d38f9ed27f0b.png)

ユースケースはEC2を選択
![image (29).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/344275d2-edbb-35ef-7ef3-30c2f0bccf37.png)

**許可を追加**で、先ほど作成した**CodeDeployDemo-EC2-Permissions**を選択
![image (30).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/a02a6fcc-2efb-a28c-0fc6-5d12fcab08dd.png)

適当に命名して保存する
![image (31).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/eec2b2c9-ef2e-ed9f-362a-6f322e830824.png)

</details>

<details>
  <summary>EC2の設定</summary>

  #### EC2にIAMロールをアタッチする
  先ほど作成したIAMロールを対象のEC2インスタンスにアタッチする
  EC2のコンソール画面で対象のインスタンスを選択し、アクション > セキュリティ > IAMロールを変更　をクリック  
  ![image (32).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/c6644342-33dd-af62-8d5a-81fad235bab6.png)

IAMロールを変更で、先ほど作成したIAMロールを選択してIAMロールの更新をする
![image (33).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/7b740bf9-2ca9-b7f6-8735-cf79b16ee5f4.png)

#### CodeDeployエージェントをインスタンスにインストールする
EC2にsshして、CodeDeployエージェントをインストールする
```
sudo yum update
sudo yum install ruby
sudo yum install wget
```

ホームディレクトリに移動する
```
cd /home/ec2-user
```
CodeDeploy エージェントのインストーラをダウンロードする
```
# リージョンごとに変わる
wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install
```
東京リージョンの場合
```
wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
```

install ファイルに実行権限を設定する。
```
chmod +x ./install
```
CodeDeploy エージェントの最新バージョンをインストールする

```
sudo ./install auto
```
サービスが実行されているかどうかを確認する
```
systemctl status codedeploy-agent
```
Active: active (running)となっていたらOK

なっていなかったら

```
systemctl start codedeploy-agent
```
とする

#### appspec.ymlの作成
デプロイの処理について記述する、appspec.ymlというファイルを作成する
最低限デプロイに必要なのは↓
```
version: 0.0

os: linux 

files:
  - source: /
    destination: /home/ec2-user/
```

このappspec.ymlというファイルを、ルートディレクトリ直下に作成する

**files**の**source**に、どのファイルをデプロイするかを指定する。
/とすれば、すべてのファイルがデプロイの対象になる。
index.htmlだけをデプロイ対象にしたい場合は、/index.htmlとする

**destination**に、インスタンスのどのディレクトリにデプロイするかを指定する。
今回は **/home/ec2-user/** にファイル群を保存することにする



詳細は<a href="https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/application-revisions-appspec-file.html#add-appspec-file-server" >こちら</a>


</details>


## 実際にデプロイしてみる
これで準備は完了です。
では早速mainブランチをpushしてみましょう。
mainブランチに変更が加えられたので、それがトリガーになり設定したパイプラインが走ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/5ac5638c-1a38-359d-7b36-aa181f8e882b.png)

この状態でしばらく待つと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/003cda4a-0b5d-831c-4172-c36d5b9a38ff.png)
無事デプロイが成功していることが確認できました！！

サーバーにsshして確認すると、指定したディレクトリにローカルで作成したファイル群が置かれていることが確認できました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/39637acf-5c1d-5b17-7e4d-268b5755732e.png)

## 今回遭遇したエラー
### 数分待った後にデプロイが失敗する
デプロイが失敗し、↓のようなメッセージが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/efc18a1c-bcbe-472e-3181-9187d958808a.png)

```
The overall deployment failed because too many individual instances failed deployment, too few healthy instances are available for deployment, or some instances in your deployment group are experiencing problems.
```

View eventsからエラーメッセージを確認すると
```
CodeDeploy agent was not able to receive the lifecycle event. Check the CodeDeploy agent logs on your host and make sure the agent is running and can connect to the CodeDeploy server.
```
とあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935700/bfec22f7-0bef-16b3-4f6f-baff14673b20.png)

CodeDeployエージェントをインストールして起動させているはずなのに、「起動しているか確認してね」というメッセージが出ているのです。


また、CodeDeployのエラーログを確認すると
```
tail -100 /var/log/aws/codedeploy-agent/codedeploy-agent.log

# ↓結果
2024-02-23T07:29:45 ERROR [codedeploy-agent(26422)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Missing credentials - please check if this instance was started with an IAM instance profile
```
とあります。

これは、CodeDeployエージェントをインストールした後に、EC2のIAMロールを更新したことが原因です。

なのでインスタンスにsshして、再度エージェントを起動させましょう。

```
sudo systemctl restart codedeploy-agent.service
```