EC2 のオートスケーリング設定 (ハンズオン)

## はじめに
この記事はAWS　Hands on for BeginnersのEC2 Auto Scaling基礎編を参考に記事にしました。


## 1.AWS Cloudformation を利用してリソースを構築
ハンズオンに必要なリソースをCloudformationによって構築する。
CloudformationはAWS環境のコードによる管理を実現することができ、テンプレートで定義した環境を作成・変更・削除できる。
これを利用することで下記の項目を手作業でやる手間なく一括で構築できる。

・Amazon VPC
・サブネット
・インターネットゲートウェイ
・ルートテーブル
・セキュリティーグループ
・Application Load Balancer,ターゲットグループ
事前準備で出来上がるリソース↓

![AWS Cloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/a88e5ac3-18c0-1c09-9727-e8a61f072c20.png)

マネジメントコーンソール　からAWSCloudformation→スタックの作成を選択する。

テンプレートの指定→テンプレートファイルのアップロードを選択

![スクリーンショット 2022-07-17 14.37.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/76c03ac0-f31f-b55c-feb1-f7f25e5864d9.png)

以下に設定ファイルに記述するコードを示す。

```json:h4b-template.json
{
  "AWSTemplateFormatVersion" : "2022-07-14",

  "Description" : "This template is for 'AWS Hands-on for Beginners Amazon EC2 Auto Scaling'.",

  "Resources" : {

    "VPC" : {
      "Type" : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock" : "10.0.0.0/16",
        "EnableDnsSupport" : true,
        "EnableDnsHostnames" : true,
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-vpc" } ]
      }
    },

    "PublicSubnet1" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "CidrBlock" : "10.0.0.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "MapPublicIpOnLaunch" : true,
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-subnet1" } ]
      }
    },
    
    "PublicSubnet2" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "CidrBlock" : "10.0.1.0/24",
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" }}]},
        "MapPublicIpOnLaunch" : true,
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-subnet2" } ]
      }
    },

    "InternetGateway" : {
      "Type" : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-igw" } ]
      }
    },

    "AttachGateway" : {
       "Type" : "AWS::EC2::VPCGatewayAttachment",
       "Properties" : {
         "VpcId" : { "Ref" : "VPC" },
         "InternetGatewayId" : { "Ref" : "InternetGateway" }
       }
    },

    "RouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
      "Properties" : {
        "VpcId" : {"Ref" : "VPC"},
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-route-table" } ]
      }
    },

    "Route" : {
      "Type" : "AWS::EC2::Route",
      "DependsOn" : "AttachGateway",
      "Properties" : {
        "RouteTableId" : { "Ref" : "RouteTable" },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "GatewayId" : { "Ref" : "InternetGateway" }
      }
    },

    "SubnetRouteTableAssociation1" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "PublicSubnet1" },
        "RouteTableId" : { "Ref" : "RouteTable" }
      }
    },
      
    "SubnetRouteTableAssociation2" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "PublicSubnet2" },
        "RouteTableId" : { "Ref" : "RouteTable" }
      }
    },

    "ALBSecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "GroupDescription" : "Enable http access",
        "GroupName" : "h4b-alb-sg",
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"}
         ],
         "Tags" : [ {"Key" : "Name", "Value" : "h4b-alb-sg" } ]
      }
    },


    "EC2SecurityGroup" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : { "Ref" : "VPC" },
        "GroupDescription" : "Enable http access from ALB Security Group",
        "GroupName" : "h4b-ec2-sg",
        "SecurityGroupIngress" : [
          { "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0" },
          { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupId" : { "Ref" : "ALBSecurityGroup" }}
         ],
         "Tags" : [ {"Key" : "Name", "Value" : "h4b-ec2-sg" } ]
      }
    },
    
    "ALBTargetGroup" : {
      "Type" : "AWS::ElasticLoadBalancingV2::TargetGroup",
      "Properties" : {
        "HealthCheckEnabled" : true,
        "HealthCheckIntervalSeconds" : 30,
        "Matcher" : {
          "HttpCode" : "200"
        },
        "Name" : "h4b-tg",
        "Port" : 80,
        "Protocol" : "HTTP",
        "TargetGroupAttributes" : [{
          "Key" : "deregistration_delay.timeout_seconds",
          "Value" : "120"
        }],
        "VpcId" : { "Ref" : "VPC" },
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-tg"} ]
      }
    },
    
    "ALB" : {
      "Type" : "AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties" : {
        "IpAddressType" : "ipv4",
        "Name" : "h4b-alb",
        "Scheme" : "internet-facing",
        "SecurityGroups" : [{ "Ref" : "ALBSecurityGroup" }],
        "Subnets" : [ { "Ref" : "PublicSubnet1" }, {"Ref" : "PublicSubnet2"} ],
        "Tags" : [ {"Key" : "Name", "Value" : "h4b-alb"} ],
        "Type" : "application"
      }
    },
    
    "ALBListener" : {
      "Type" : "AWS::ElasticLoadBalancingV2::Listener",
      "Properties" : {
        "DefaultActions" : [{
          "TargetGroupArn" : { "Ref" : "ALBTargetGroup" },
          "Type" : "forward"
        }],
        "LoadBalancerArn" : { "Ref" : "ALB" },
        "Port" : 80,
        "Protocol" : "HTTP"
      }
    }

  }

}

```

ファイルをアップロードして次へを選択し、スタックの名前を```h4b-stack```にする。

![スクリーンショット 2022-07-17 14.42.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/6af49f8a-4dbd-7d9a-4e00-0a9eee832d2e.png)

これ以降の設定は任意で設定し、スタックの作成を選択する。

## 2.Amazon AutoScalingのコンポーネント

Amazon AutoScalingコンポーネントは大きく分けて以下の２つである。

・起動テンプレート
・オートスケーリンググループ

### 起動テンプレート
オートスケーリングによって起動されるインスタンスの起動情報を設定するテンプレート

起動情報とは...
- Amazon Machine image(AMI)
- インスタンスタイプ
- ネットワーク設定　など


### オートスケーリンググループ
スケーリングの設定を行うコンポーネント

設定内容
- どの構成テンプレートを使用するか
- 何台構成にするか
- スケールアウトする台数
- スケールインする台数
- なにをトリガーにスケールするか

## 3.スケジュールスケーリングの設定
一度きりの実行や毎日、毎週といった実行が可能。


![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/830e0563-65aa-efba-3a4b-343af42c0f40.png)


### 起動テンプレートの作成
マネジメントコンソールからEC2→起動テンプレート→テンプレートを作成を選択

ここでは以下のように設定した。
起動テンプレート名:h4b-template
AMI：クイックスタートタブ→AmazonLinux→Amazon Linux2 AMI
インスタンスタイプ：t2.micro
セキュリティーグループ：h4b-ec2-sg(EC2用のセキュリティーグループ(先ほどのCloudformationで作成済み))
リソースタグ：キーをName、値はh4b-instance
高度な設定：Cloudwatch モニタリング有効化
ユーザーデータ：下のコードを貼り付ける。事前に以下のコマンドが実行された状態でEC2が立ち上がる。
```
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo amazon-linux-extras install epel -y
sudo yum install stress -y
sudo systemctl start httpd
sudo echo `hostname` > /var/www/html/index.html
sudo echo "ClientAliveInterval 60" >> /etc/ssh/sshd_config
sudo echo "ClientAliveCountMax 120" >> /etc/ssh/sshd_config
sudo systemctl restart sshd.service
```

### オートスケーリンググループの作成
マネジメントコンソール→EC2　→オートスケーリンググループ→オートスケーリンググループの作成を選択

設定内容
Auto Scaling グループ名:h4b-autoscaling-group
起動テンプレート：h4b-template(先ほどつくったもの)
次へ
↓
VPC：h4b-vpc（Cloudformationで設定したもの）
アベイラビリティーゾンとサブネット：h4b-subnet1,h4b-subnet2(アベイラビリティーゾンが異なる２つ選択)
次へ
↓
既存のロードバランサーへアタッチ
既存のロードバランサーターゲットグループ：h4b-tg
次へ
↓
希望する容量：１
最小キャパシティー：１
最大キャパシティー：４
↓
次へ
↓
次へ
↓
オートスケーリンググループを作成を選択


作成したオートスケーリンググループをクリックし、詳細タブやアクティビティータブを見るときちんと実行されているのが確認できる。

![スクリーンショット 2022-07-17 15.26.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/4eca55ec-84f3-7de6-3bb3-3e0b48c7c468.png)

### スケジュールの設定
マネジメントコンソールからEC2→Auto Scalingグループ→オートスケーリングタブ→予定されたアクションを作成する。
![スクリーンショット 2022-07-17 15.30.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/8c9a9a93-5f98-49c6-fbb5-90bec7b72c07.png)

設定内容
名前：h4b-schedule
希望する容量：２
最小キャパシティー：２
最大キャパシティー４
開始時刻：（例）2022年7月17日　１５：３８（５分後を目安にするといいみたい）

再度、作成したオートスケーリンググループをクリックし、詳細タブやアクティビティータブを見るときちんと実行されているのが確認できる。

## 4.動的スケーリング
動的スケーリング実行するためにはスケーリングポリシーを作成する必要がある。
スケーリングポリシーには３種類のポリシーがある
- ターゲット追跡スケーリング
- ステップスケーリング
- シンプルなスケーリング

今回はターゲット追跡スケーリングを使用する。
ターゲット追跡スケーリングは設定したターゲット値を維持するようにスケールイン、スケールアウトする。

![AWS Cloud (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/d908d267-f06c-ad06-fa17-0b19fa71eb00.png)

### ターゲット追跡スケーリングの設定
マネジメントコンソールからEC2→Auto Scalingグループ→オートスケーリングタブ→動的スケーリングポリシーを作成する。

設定内容
ポリシータイプ：ターゲット追跡スケーリング
ターゲット値：８０

マネジメントコンソールからCloudWatchLogs→アラームで現在出ているアラームを確認できる。

### 負荷をかけてスケールアウト確認
マネジメントコンソールからEC2→インスタンスを選択する。
該当インスタンス２つにssh接続し、```stress -c 1```←このコマンドを実行する。


この挙動もCloudWatchLogsから確認できる。

### 負荷を止めてスケールインを確認
ssh接続した画面に戻り、ctr-Cでコマンドを中止する。

しばらく待つとh4bインスタンスが2台に減少することを確認できる。

##異常なインスタンスの置き換え
EC2のインスタンス画面から、h4bインスタンスを選択し削除するとスケジュールスケーリングで設定したインスタンスの台数に戻っていることが確認できる。


## 5.リソースの削除
以下の順番でリソースを削除する。

オートスケーリンググループの削除
↓
起動テンプレートの削除
↓
CloudFormationのスタックの削除



## 補足
スケーリングによってインスタンスが増減するため、特定のサーバーに依存するようなステートフルな設計ではなくステートレスな設計が求められる。
例えば）セッション管理,ログ管理など


![AWS Cloud (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040882/752c4546-820f-5b87-9b17-69bec7556cd1.png)


## Next Action
- [Black Belt：Amazon EC2 Auto Scaling and AWS Auto Scaling](https://aws.amazon.com/jp/blogs/news/webinar-bb-amazon-ec2-auto-scaling-and-aws-auto-scaling-2019/)

- [インスタンスの更新に基づくAuto Scalingインスタンスの置き換え](https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-instance-refresh.html)

- [AWS Well-Architectedフレームワーク信頼性の柱障害を軽減または耐えるために分散システムでの操作を設計する](https://docs.aws.amazon.com/ja_jp/wellarchitected/latest/reliability-pillar/design-interactions-in-a-distributed-system-to-mitigate-or-withstand-failures.html)