EC2 に Auto Scaling の設定 と Cl/CD (CodePipeline + CodeDeploy + LambdaによるAMIの自動更新) を導入 ①

# はじめに
EC2にAuto Scaling設定を行い、Cl/CD (GitHub + CodePipeline + CodeDeploy + AMIの自動更新) を導入することで、自動デプロイを実現しましたので、手順をまとめます。

また、CodeDeploy後、`最新のソースを反映したEC2のAMIを作成し、Auto Scaling の起動テンプレートにAMIを反映する`Lambdaを作成し、Codepipelineのステージに加えることでAMIの反映も自動化させました。




# 構築図
![スクリーンショット 2022-08-26 23.01.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/59d5bfe8-fdf9-9308-2977-75851971a8d0.png)

# 事前構築
- vpcやsubnetなど、ネットワーク層作成
- EC2やelbは、作成しても、作成していなくてもよいです。
    - 今回は、分かりやすいように、EC2にNginxを入れるだけのシンプルなサーバーにします。
        - 既に作成のEC2でもよいです。nginxでなくてもよいです。


![スクリーンショット 2022-08-25 23.50.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/bd8d5eb8-945a-9061-0dec-07cc96428376.png)

# EC2 nginxをインストール
```terminal]
// ssh接続
% ssh -i xxxx.pem ec2-user@パブリックIP（またはDNS）

// nginxをインストール
$ sudo amazon-linux-extras install nginx1

// nginxを起動
$ sudo systemctl start nginx

// 自動起動設定
$ sudo systemctl enable nginx

$ cd /usr/share/nginx/html

$ ls
404.html  50x.html  icons  index.html  nginx-logo.png  poweredby.png

```
EC2のパブリックIPでブラウザからアクセスすると、ウェブサイトが見れます。
![スクリーンショット 2022-08-25 0.26.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/4e92eed1-d96a-81f5-ce8e-6d2a00575a4c.png)


# IAMロールを作成
IAMロールは、CodeDeployにアタッチする用とEC2にアタッチする用２つ作成します。
## CodeDeploy作成時に使用するIAMロール作成
- 一般的なユースケース:`CodeDeploy`
![スクリーンショット 2022-08-25 0.43.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/d4a11754-64d6-4256-da50-01ae91e547f9.png)

- アタッチするAWS管理ポリシー
    - `AWSCodeDeployRole`
![スクリーンショット 2022-08-25 0.43.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/b35ee960-246c-2684-0d28-09f763ea8874.png)

CodeDeploy作成時に、このRoleを選択します。

## EC2にアタッチする用のIAMロール作成
- 一般的なユースケース:`EC2`
![スクリーンショット 2022-08-25 0.38.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/056d82ae-3658-0bef-aee9-0d0ca3ba006d.png)
- アタッチするAWS管理ポリシー
    - `AmazonS3FullAccess`
    - `AWSCodeDeployRole`
![スクリーンショット 2022-08-25 0.40.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/7efe750f-deac-7fd6-840a-a027a4ed20f3.png)

`AmazonS3FullAccess`は、Codepipelineで、S3へlogをアップする際に必要になりますので、EC2にアタッチします。

IAMロール作成後、EC2にアタッチしましょう。

# EC2にCodeDeployのagentをインストールし、AMI作成
下記記事を参考に、EC2にCodeDeployのagentをインストールします。

https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html



```terminal
$ cd

$ sudo yum install -y ruby

$ sudo yum install -y wget
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
パッケージ wget-1.14-18.amzn2.1.x86_64 はインストール済みか最新バージョンです
何もしません

$ wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install

$ chmod +x ./install

$ sudo ./install auto

$ sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID 3246
sudo service codedeploy-agent status
```
以下のコマンドに関しては、EC2が東京リージョンに存在する場合のURLになります。
- `wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install`

リージョンのURLはこちらを参照してください

https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names

# 起動テンプレートを作成
起動テンプレートを作成前に、NginxをインストールしたEC2のAMIを取ります。
![スクリーンショット 2022-08-25 18.47.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/4d2e2a8f-aee3-7ba4-f793-d60ca539f357.png)

起動テンプレートを作成します。
- 起動テンプレート名とテンプレートバージョンの説明を記載します
AMIは、先程作成したAMIを指定します。
![スクリーンショット 2022-08-25 18.49.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/5499e28a-8c5a-e147-b90a-a579e0320c03.png)

- インスタンスタイプ、キーペアを指定します。
![スクリーンショット 2022-08-25 23.15.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/0b75fd78-e807-a59d-1690-c1afbcb02672.png)
- サブネットは`起動テンプレートの設定に含めない`を選択します。
- セキュリティーグループは、既存のものを選択します。
- ネットワークインターフェイスを追加します。
    - `パブリック IP の自動割り当て`を`有効化`します。CodeDeploy後、ソースが反映されるか確認するためです。他はデフォルトのままです。
    ![スクリーンショット 2022-08-25 23.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/54ebd984-bbc1-309a-0f88-d6ff19cb14fc.png)
- ストレージは、AMIのEBSが指定されているはずなので、デフォルトのままにします。
![スクリーンショット 2022-08-26 21.55.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/80e412c0-4cbf-e937-fa3d-b213e28209c5.png)
- `高度の詳細から`IAMロールは、EC2にアタッチしているものを選択します。他はデフォルトのままです。
![スクリーンショット 2022-08-25 18.52.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/58f7db90-e009-95c7-557b-0f3defcedd48.png)

他は、デフォルトのままにして、起動テンプレートを作成します。

# Auto Scalingグループを作成
- Auto Scalingグループ名:`nginx`
- 起動テンプレート:`nginx`
- バージョン:`Latest` 
    - Defalutではなく、必ずLatestにしましょう。起動テンプレートの最新のバージョンが反映されるようになります。
![スクリーンショット 2022-08-25 22.08.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/a63a50dc-d47d-dffe-d01a-3ccea34bd97f.png)
- VPCとSubnetを選択します。
![スクリーンショット 2022-08-25 19.00.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/de430e6f-4895-a335-e1b7-47898486cb82.png)
- ロードバランサーとターゲットグループを作成していない場合、ここで作成します。
- ヘルスチェックのタイプで`ELB`をチェックしておりません.
一旦チェックせずに、AutoScalingを起動します。成功した場合に限り、チェックをつけてもよいです。
    - ロードバランサーのスキームは、`internet-facing`を選択します。`internal(内部)`ではダメです。
    - サブネットは、パブリックサブネットを選択します。
![スクリーンショット 2022-08-25 23.42.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/1848ae36-070f-fc8d-7983-5a8b3320e99a.png)
- グループサイズとスケーリングポリシーは、適当に決めました。
    - 今回は、CPUが50%を超えると、インスタンス数が増えます。
![スクリーンショット 2022-08-25 19.03.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/e3f0e188-553e-2758-786e-da41ca84d20f.png)
- 今回、通知はしません。
![スクリーンショット 2022-08-25 19.03.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/ddecb3db-1b6f-bcba-df21-7e852c2c3720.png)
- タグも追加しません。
![スクリーンショット 2022-08-25 19.03.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/b042c94c-c438-5245-bb4b-a7a91a189e74.png)

これで、１つインスタンスが起動するはずです。

ブラウザからelbのDNS名(nginx-elb-アカウントID.ap-northeast-1.elb.amazonaws.com)で
アクセスすると、nginxのデフォルトが表示されるか確認しましょう。

ブラウザで表示されない場合、EC2とELBのセキュリティーグループを確認しましょう。

## ターゲットグループの修正
ターゲットグループはデフォルトだと、`登録解除の遅延`は300秒になっており、CodeDeployの速度に影響が出るため、10秒に変更します。
![スクリーンショット 2022-08-25 23.32.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/b520b6fc-b0a5-4cc8-8098-efa3f4f1f292.png)


また、同じ理由で、ヘルスチェックの`正常と非正常のしきい値`を5回から最低の2回にしました。
![スクリーンショット 2022-08-25 23.34.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/bcd57736-5508-b01b-d758-3f5b1f75931e.png)

これで、CodeDeploy時のデプロイ速度が格段に早くなります。
こちらの記事を参考にしました。

https://qiita.com/tomozo6/items/1c436f594e2cce486153

## 負荷をかけて Auto Scaling の動作確認
検証作業なので、スキップしてもよいです。

Auto Scalingのグループサイズの最大容量を3し、
yesコマンドで負荷をかけた後、EC2インスタンスが3になっているか確認してみましょう。
terminalのタブを２つ用意し、２つのタブどちらもEC2にSSH接続します。
片方は以下のコマンドを実行します。
```terminal
$ yes dev/null &
```

もう片方のterminalは、EC2インスタンスが3になっていることを確認した後、killコマンドで停止しましょう。
$ top
// yesコマンドのPIDを確認します。

$ kill <PID>
```
その後、EC2がスケールインし、EC2インスタンスが1になっているか確認します。

# GitHubにappspec.ymlをアップ

元々Githubのリポジトリにあるものは、index.htmlのみです。
```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <p>CodeDeploy success!!</p>
  </body>
</html>
```
このリポジトリに`appspec.yml`を加えます。
`appspec.yml`は、CodeDeployの指示書になります。
今回は以下の記述をします。

```yml:appspec.yml
version: 0.0
os: linux
files:
  - source: /
    destination: /usr/share/nginx/html
file_exists_behavior: OVERWRITE
permissions:
  - object: /usr/share/nginx/html
    pattern: '**'
    owner: ec2-user
    group: nginx
    mode: 644
    type:
      - file
  - object: /usr/share/nginx/html
    pattern: '**'
    owner: ec2-user
    group: nginx
    mode: 755
    type:
      - directory
```

例えば、EC2で Laravel + apacheの場合、以下のappspec.ymlになりました。
```yml:appspec.yml
version: 0.0
os: linux
files:
  - source: /
    destination: /usr/share/nginx/html
file_exists_behavior: OVERWRITE
permissions:
  - object: /usr/share/nginx/html
    pattern: "**"
    owner: ec2-user
    group: apache
    except: [/usr/share/nginx/html/storage]
    type:
      - file
    mode: 644
  - object: /usr/share/nginx/html
    pattern: "**"
    owner: ec2-user
    group: apache
    except: [/usr/share/nginx/html/storage]
    type:
      - directory
    ode: 755
  - object: /usr/share/nginx/html/storage
    pattern: "**"
    owner: ec2-user
    group: apache
    type:
      - file
    mode: 775
  - object: /usr/share/nginx/html/storage
    pattern: "**"
    owner: ec2-user
    group: apache
    type:
      - directory
    mode: 775
```

- `source`は、デプロイするリポジトリのパスを指定します。

- `destination`は、リビジョン（GitHubのソース）をサーバーにデプロイする際の、サーバーのパスを指定します。

- `file_exists_behavior: OVERWRITE`は、デプロイ先のソースを上書きします。
デプロイ対象がEC2の場合、リビジョンをデプロイする以前から存在していたファイルをCodeDeployのリビジョン対象にしたいことがあります。しかしそのままだとalready exists.とエラーを吐いてデプロイが失敗しますが、この記述によって上書きされ、エラーを回避できます。

詳細はこちらの記事をみてください

https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-files.html

https://open-groove.net/ci-cd/aws-codedeploy-remove-revision/

appspec.ymlをアップすると、GitHubのリポジトリは以下の構成になります。シンプルですね。
![スクリーンショット 2022-08-25 23.28.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/235cdfb1-78dc-3544-7287-14214ad313c0.png)



# CodeDeployを設定
## アプリケーションの作成
CodeDeployのアプリケーションの作成をクリックします。
アプリケーション名を記入し、プラットフォームは、EC2を選択します。

![スクリーンショット 2022-08-25 22.38.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/465ad16f-71cc-1991-5b67-32d9f57958a7.png)
## デプロイグループの作成
- デプロイグループ名:`nginx`
- サービスロール:`CodeDeployRole`(IAMロール作成で作成したRoleです。)
- デプロイタイプ:`インプレース`
![スクリーンショット 2022-08-25 22.40.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/a34309d0-1a3c-47b7-611d-fd59ed29fd05.png)
- 環境設定:`Amazon EC2 Auto Scaling グループ`をチェックし、 `nignx`を選択します
- デプロイ設定:`CodeDeployDefault.OneAtTime`
    - １つずつEC2にデプロイします。
- Load balancer:`ロードバランシングを有効にする`をチェックします。
    - ターゲットグループも選択します。
![スクリーンショット 2022-08-25 22.40.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/c54fef0a-edbf-cf64-6014-d452cdd7bbc2.png)

## デプロイの作成
- デプロイグループ:`先程作成したデプロイグループ名`
- リビジョンタイプ：`Github`
    1. GitHub トークン名は、適当な名前を記入し、`Githubに接続`をクリックします。
    ![スクリーンショット 2022-08-25 22.49.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/4a50ad2c-da14-9d96-1621-25723c584d4f.png)
    1. `Authorize aws-codesuite`をクリックします
    ![スクリーンショット 2022-08-25 22.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/0df41c82-27e9-6844-6d48-789cda2d4395.png)
    1. `確認`をクリックします。
    ![スクリーンショット 2022-08-25 22.50.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/dd682b6d-0333-0a3b-15cf-c6fcef9d5d8d.png)
    1. 接続が完了すると、リポジトリとコミットIDの記入欄が出ますので、書きましょう
        - リポジトリ名は、`Githubのアカウント名 / リポジトリ名`です。
        ![スクリーンショット 2022-08-25 22.56.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/48f20dc4-f7ca-c071-70c4-bce825b48962.png)
    1. 追加デプロイ動作設定:`コンテンツの上書き`をチェックします。
    ![スクリーンショット 2022-08-25 22.56.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/37c0316a-8816-a517-8569-39c61aa90f6d.png)

デプロイ成功後、EC2にSSH接続してみます。
```terminal
$ cd /usr/share/nginx/html

//デプロイ前
$ ls -la
-rw-r--r-- 1 root root 3665  7月 12 01:09 404.html
-rw-r--r-- 1 root root 3708  7月 12 01:09 50x.html
drwxr-xr-x 2 root root   27  8月 24 15:20 icons
-rw-r--r-- 1 root root 3520  7月 12 01:09 index.html
-rw-r--r-- 1 root root  368  7月 12 01:09 nginx-logo.png
lrwxrwxrwx 1 root root   14  8月 24 15:20 poweredby.png -> nginx-logo.png

//デプロイ後
$ ls -la
-rw-r--r-- 1 root     root  3665  7月 12 01:09 404.html
-rw-r--r-- 1 root     root  3708  7月 12 01:09 50x.html
-rw-r--r-- 1 ec2-user nginx  353  8月 25 14:09 appspec.yml
drwxr-xr-x 2 root     root    27  8月 24 15:20 icons
-rw-r--r-- 1 ec2-user nginx  168  8月 25 14:09 index.html
-rw-r--r-- 1 root     root   368  7月 12 01:09 nginx-logo.png
lrwxrwxrwx 1 root     root    14  8月 24 15:20 poweredby.png -> nginx-logo.png
```

`index.html`が反映され、`appspec.yml`が追加されていることが分かります。

ブラウザからelbのDNS名(nginx-elb-アカウントID.ap-northeast-1.elb.amazonaws.com)で
アクセスすると、nginxのデフォルトではなくなり、index.htmlが反映されていますね。
![スクリーンショット 2022-08-25 23.45.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/6195ccc0-22c8-2ff9-47d2-03f4b22c7983.png)

ブラウザで表示されない場合、EC2とELBのセキュリティーグループを確認しましょう。

長くなったため、`CodePipelineを作成`以降は、次回にします。

https://qiita.com/hirai-11/items/1bc0b422a2b050d4f7af

# 参考記事



https://zenn.dev/kenryo/scraps/dbd41bc419932b

https://open-groove.net/ci-cd/aws-codedeploy-remove-revision/