

# スケールおよび負荷分散されたアプリケーションを作成する
<a name="walkthrough-autoscaling"></a>

このチュートリアルでは、スケールおよび負荷分散されたアプリケーションの設定に役立つスタックを作成します。チュートリアルでは、スタックの作成に使用するサンプルテンプレートを提供します。このサンプルテンプレートは、Auto Scaling グループ、Application Load Balancer、ロードバランサーと Auto Scaling グループへのトラフィックを制御するセキュリティグループ、およびスケーリングアクティビティに関する通知を発行する Amazon SNS 通知設定をプロビジョニングします。

このテンプレートは、1 つ以上の Amazon EC2 インスタンスと Application Load Balancer を作成します。このテンプレートからスタックを作成した場合、AWS リソースに対する料金が発生します。

## フルスタックテンプレート
<a name="example-templates-autoscaling-full-stack-template"></a>

テンプレートから始めましょう。

**YAML**

```
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  InstanceType:
    Description: The EC2 instance type
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium
  KeyName:
    Description: Name of an existing EC2 key pair to allow SSH access to the instances
    Type: AWS::EC2::KeyPair::KeyName
  LatestAmiId:
    Description: The latest Amazon Linux 2 AMI from the Parameter Store
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
  OperatorEmail:
    Description: The email address to notify when there are any scaling activities
    Type: String
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 0.0.0.0/0
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  Subnets:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: At least two public subnets in different Availability Zones in the selected VPC
  VPC:
    Type: AWS::EC2::VPC::Id
    Description: A virtual private cloud (VPC) that enables resources in public subnets to connect to the internet
Resources:
  ELBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: ELB Security Group
      VpcId: !Ref VPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        CidrIp: 0.0.0.0/0
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EC2 Security Group
      VpcId: !Ref VPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        SourceSecurityGroupId:
          Fn::GetAtt:
          - ELBSecurityGroup
          - GroupId
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref SSHLocation
  EC2TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 15
      HealthyThresholdCount: 5
      Matcher:
        HttpCode: '200'
      Name: EC2TargetGroup
      Port: 80
      Protocol: HTTP
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: '20'
      UnhealthyThresholdCount: 3
      VpcId: !Ref VPC
  ALBListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref EC2TargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: 80
      Protocol: HTTP
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      Subnets: !Ref Subnets
      SecurityGroups:
        - !GetAtt ELBSecurityGroup.GroupId
  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties: 
      LaunchTemplateName: !Sub ${AWS::StackName}-launch-template
      LaunchTemplateData:
        ImageId: !Ref LatestAmiId
        InstanceType: !Ref InstanceType
        KeyName: !Ref KeyName
        SecurityGroupIds: 
          - !Ref EC2SecurityGroup
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            yum update -y
            yum install -y httpd
            systemctl start httpd
            systemctl enable httpd
            echo "<h1>Hello World!</h1>" > /var/www/html/index.html
  NotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Endpoint: !Ref OperatorEmail
          Protocol: email
  WebServerGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      LaunchTemplate:
        LaunchTemplateId: !Ref LaunchTemplate
        Version: !GetAtt LaunchTemplate.LatestVersionNumber
      MaxSize: '3'
      MinSize: '1'
      NotificationConfigurations:
        - TopicARN: !Ref NotificationTopic
          NotificationTypes: ['autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR', 'autoscaling:EC2_INSTANCE_TERMINATE', 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR']
      TargetGroupARNs:
        - !Ref EC2TargetGroup
      VPCZoneIdentifier: !Ref Subnets
```

**JSON**

```
{
  "AWSTemplateFormatVersion":"2010-09-09",
  "Parameters":{
    "InstanceType":{
      "Description":"The EC2 instance type",
      "Type":"String",
      "Default":"t3.micro",
      "AllowedValues":[
        "t3.micro",
        "t3.small",
        "t3.medium"
      ]
    },
    "KeyName":{
      "Description":"Name of an existing EC2 key pair to allow SSH access to the instances",
      "Type":"AWS::EC2::KeyPair::KeyName"
    },
    "LatestAmiId":{
      "Description":"The latest Amazon Linux 2 AMI from the Parameter Store",
      "Type":"AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>",
      "Default":"/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
    },
    "OperatorEmail":{
      "Description":"The email address to notify when there are any scaling activities",
      "Type":"String"
    },
    "SSHLocation":{
      "Description":"The IP address range that can be used to SSH to the EC2 instances",
      "Type":"String",
      "MinLength":9,
      "MaxLength":18,
      "Default":"0.0.0.0/0",
      "ConstraintDescription":"Must be a valid IP CIDR range of the form x.x.x.x/x."
    },
    "Subnets":{
      "Type":"List<AWS::EC2::Subnet::Id>",
      "Description":"At least two public subnets in different Availability Zones in the selected VPC"
    },
    "VPC":{
      "Type":"AWS::EC2::VPC::Id",
      "Description":"A virtual private cloud (VPC) that enables resources in public subnets to connect to the internet"
    }
  },
  "Resources":{
    "ELBSecurityGroup":{
      "Type":"AWS::EC2::SecurityGroup",
      "Properties":{
        "GroupDescription":"ELB Security Group",
        "VpcId":{
          "Ref":"VPC"
        },
        "SecurityGroupIngress":[
          {
            "IpProtocol":"tcp",
            "FromPort":80,
            "ToPort":80,
            "CidrIp":"0.0.0.0/0"
          }
        ]
      }
    },
    "EC2SecurityGroup":{
      "Type":"AWS::EC2::SecurityGroup",
      "Properties":{
        "GroupDescription":"EC2 Security Group",
        "VpcId":{
          "Ref":"VPC"
        },
        "SecurityGroupIngress":[
          {
            "IpProtocol":"tcp",
            "FromPort":80,
            "ToPort":80,
            "SourceSecurityGroupId":{
              "Fn::GetAtt":[
                "ELBSecurityGroup",
                "GroupId"
              ]
            }
          },
          {
            "IpProtocol":"tcp",
            "FromPort":22,
            "ToPort":22,
            "CidrIp":{
              "Ref":"SSHLocation"
            }
          }
        ]
      }
    },
    "EC2TargetGroup":{
      "Type":"AWS::ElasticLoadBalancingV2::TargetGroup",
      "Properties":{
        "HealthCheckIntervalSeconds":30,
        "HealthCheckProtocol":"HTTP",
        "HealthCheckTimeoutSeconds":15,
        "HealthyThresholdCount":5,
        "Matcher":{
          "HttpCode":"200"
        },
        "Name":"EC2TargetGroup",
        "Port":80,
        "Protocol":"HTTP",
        "TargetGroupAttributes":[
          {
            "Key":"deregistration_delay.timeout_seconds",
            "Value":"20"
          }
        ],
        "UnhealthyThresholdCount":3,
        "VpcId":{
          "Ref":"VPC"
        }
      }
    },
    "ALBListener":{
      "Type":"AWS::ElasticLoadBalancingV2::Listener",
      "Properties":{
        "DefaultActions":[
          {
            "Type":"forward",
            "TargetGroupArn":{
              "Ref":"EC2TargetGroup"
            }
          }
        ],
        "LoadBalancerArn":{
          "Ref":"ApplicationLoadBalancer"
        },
        "Port":80,
        "Protocol":"HTTP"
      }
    },
    "ApplicationLoadBalancer":{
      "Type":"AWS::ElasticLoadBalancingV2::LoadBalancer",
      "Properties":{
        "Scheme":"internet-facing",
        "Subnets":{
          "Ref":"Subnets"
        },
        "SecurityGroups":[
          {
            "Fn::GetAtt":[
              "ELBSecurityGroup",
              "GroupId"
            ]
          }
        ]
      }
    },
    "LaunchTemplate":{
      "Type":"AWS::EC2::LaunchTemplate",
      "Properties":{
        "LaunchTemplateName":{
          "Fn::Sub":"${AWS::StackName}-launch-template"
        },
        "LaunchTemplateData":{
          "ImageId":{
            "Ref":"LatestAmiId"
          },
          "InstanceType":{
            "Ref":"InstanceType"
          },
          "KeyName":{
            "Ref":"KeyName"
          },
          "SecurityGroupIds":[
            {
              "Ref":"EC2SecurityGroup"
            }
          ],
          "UserData":{
            "Fn::Base64":{
              "Fn::Join":[
                "",
                [
                  "#!/bin/bash\n",
                  "yum update -y\n",
                  "yum install -y httpd\n",
                  "systemctl start httpd\n",
                  "systemctl enable httpd\n",
                  "echo \"<h1>Hello World!</h1>\" > /var/www/html/index.html"
                ]
              ]
            }
          }
        }
      }
    },
    "NotificationTopic":{
      "Type":"AWS::SNS::Topic",
      "Properties":{
        "Subscription":[
          {
            "Endpoint":{
              "Ref":"OperatorEmail"
            },
            "Protocol":"email"
          }
        ]
      }
    },
    "WebServerGroup":{
      "Type":"AWS::AutoScaling::AutoScalingGroup",
      "Properties":{
        "LaunchTemplate":{
          "LaunchTemplateId":{
            "Ref":"LaunchTemplate"
          },
          "Version":{
            "Fn::GetAtt":[
              "LaunchTemplate",
              "LatestVersionNumber"
            ]
          }
        },
        "MaxSize":"3",
        "MinSize":"1",
        "NotificationConfigurations":[
          {
            "TopicARN":{
              "Ref":"NotificationTopic"
            },
            "NotificationTypes":[
              "autoscaling:EC2_INSTANCE_LAUNCH",
              "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
              "autoscaling:EC2_INSTANCE_TERMINATE",
              "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
            ]
          }
        ],
        "TargetGroupARNs":[
          {
            "Ref":"EC2TargetGroup"
          }
        ],
        "VPCZoneIdentifier":{
          "Ref":"Subnets"
        }
      }
    }
  }
}
```

## テンプレートのチュートリアル
<a name="example-templates-autoscaling-description"></a>

このテンプレートの最初の部分では、`Parameters` を指定します。CloudFormation がスタックを正常にプロビジョニングするには、各パラメーターに実行時に値を割り当てる必要があります。テンプレートで後で指定されるリソースは、これらの値を参照し、データを使用します。
+ `InstanceType`: Amazon EC2 Auto Scaling がプロビジョニングする EC2 インスタンスのタイプ。指定しない場合は、デフォルトの `t3.micro` が使用されます。
+ `KeyName`: インスタンスへの SSH アクセスを許可する既存の EC2 キーペア。
+ `LatestAmiId`: インスタンスの Amazon マシンイメージ (AMI)。指定しない場合、インスタンスは、AWS によって維持される AWS Systems Manager パブリックパラメータを使用して、Amazon Linux 2 AMI で起動されます。詳細については、「AWS Systems Manager ユーザーガイド」の「[パブリックパラメータの検索](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html)」を参照してください。
+ `OperatorEmail`: スケーリングアクティビティの通知を送信するメールアドレス。
+ `SSHLocation`: インスタンスへの SSH 接続に使用できる IP アドレス範囲。
+ `Subnets`: 少なくとも 2 つのパブリックサブネットが異なるアベイラビリティーゾーンに存在している。
+ `VPC`: パブリックサブネット内のリソースがインターネットに接続できるようにするアカウント内の仮想プライベートクラウド (VPC)。
**注記**  
デフォルトの VPC とデフォルトのサブネットを使用して、インスタンスがインターネットにアクセスできるようにすることができます。後者の場合は、VPC に、作業中のリージョンの各アベイラビリティーゾーンにマッピングされたサブネットがあることを確認してください。ロードバランサーを作成するには、2 つ以上のパブリックサブネットが必要です。

このテンプレートの次の部分では、`Resources` を指定します。このセクションでは、スタックリソースとそのプロパティを指定します。

[https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html)リソース `ELBSecurityGroup` 
+ `SecurityGroupIngress` には、ポート 80 上のすべての IP アドレス ("CidrIp" : "0.0.0.0/0") からのアクセスを許可する TCP イングレスルールが含まれています。

[https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html)リソース `EC2SecurityGroup` 
+ `SecurityGroupIngress` には、1) `SSHLocation` 入力パラメータ用に指定した IP アドレス範囲からの SSH アクセス (ポート 22) を許可する TCP イングレスルール、および 2) ロードバランサーのセキュリティグループを指定することによってロードバランサーからのアクセスを許可する TCP イングレスルールという 2 つのイングレスルールが含まれています。[GetAtt](resources-section-structure.md#resource-properties-getatt) 関数は、論理名 `ELBSecurityGroup` を持つセキュリティグループの ID を取得するために使用されます。

[AWS::ElasticLoadBalancingV2::TargetGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-targetgroup.html) リソース `EC2TargetGroup`
+ `Port`、`Protocol`、および `HealthCheckProtocol` は、`ApplicationLoadBalancer` がトラフィックをルーティングし、Elastic Load Balancing が EC2 インスタンスのヘルスをチェックするために使用する EC2 インスタンスのポート (80) とプロトコル (HTTP) を指定します。
+ `HealthCheckIntervalSeconds` は、EC2 インスタンスのヘルスチェックの間隔が 30 秒であることを指定します。`HealthCheckTimeoutSeconds` は、ヘルスチェックターゲットからのレスポンスを Elastic Load Balancing が待機する時間です (この例では 15 秒)。タイムアウトの時間が経過すると、Elastic Load Balancing は、EC2 インスタンスのヘルスチェックを異常としてマークします。EC2 インスタンスが 3 回連続してヘルスチェックに失敗すると (`UnhealthyThresholdCount`)、Elastic Load Balancing は、そのインスタンスが 5 回連続してヘルスチェックに合格するまで (`HealthyThresholdCount`)、その EC2 インスタンスへのトラフィックのルーティングを停止します。その時点で、Elastic Load Balancing は、そのインスタンスが正常であるとみなし、そのインスタンスへのトラフィックのルーティングを再開します。
+ `TargetGroupAttributes` は、ターゲットグループの登録解除の遅延の値を 20 秒に更新します。デフォルトでは、Elastic Load Balancing は登録解除プロセスを完了するまで 300 秒間待機します。

[AWS::ElasticLoadBalancingV2::Listener](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-listener.html) リソース `ALBListener`
+ `DefaultActions` は、ロードバランサーがリッスンするポート、ロードバランサーがリクエストを転送するターゲットグループ、およびリクエストのルーティングに使用されるプロトコルを指定します。

[AWS::ElasticLoadBalancingV2::LoadBalancer](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-elasticloadbalancingv2-loadbalancer.html) リソース `ApplicationLoadBalancer`
+ `Subnets` は、`Subnets` 入力パラメータの値を、ロードバランサーノードが作成されるパブリックサブネットのリストとして受け取ります。
+ `SecurityGroup` は、ロードバランサーノードが着信トラフィックを制御するための仮想ファイアウォールとして機能するセキュリティグループの ID を取得します。[GetAtt](resources-section-structure.md#resource-properties-getatt) 関数は、論理名 `ELBSecurityGroup` を持つセキュリティグループの ID を取得するために使用されます。

[AWS::EC2::LaunchTemplate](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-launchtemplate.html) リソース `LaunchTemplate`
+ `ImageId` は、使用する AMI として `LatestAmiId` 入力パラメータの値を受け取ります。
+ `KeyName` は、使用する EC2 キーペアとして `KeyName` 入力パラメータの値を受け取ります。
+ `SecurityGroupIds` は、EC2 インスタンスが着信トラフィックを制御するための仮想ファイアウォールとして機能する、論理名 `EC2SecurityGroup` を持つセキュリティグループの ID を取得します。
+ `UserData` は、インスタンスが稼働を開始した後に実行される設定スクリプトです。この例では、スクリプトは Apache をインストールし、index.html ファイルを作成します。

[AWS::SNS::Topic](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-sns-topic.html) リソース `NotificationTopic`
+ `Subscription` は、スケーリングアクティビティがある場合、`OperatorEmail` 入力パラメータの値を通知の受信者のメールアドレスとして受け取ります。

[AWS::AutoScaling::AutoScalingGroup](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-autoscaling-autoscalinggroup.html) resource `WebServerGroup`
+ `MinSize` および `MaxSize` には、Auto Scaling グループでの EC2 インスタンスの最小数と最大数を設定します。
+ `TargetGroupARNs` は、論理名 `EC2TargetGroup` を持つターゲットグループの ARN を取得します。この Auto Scaling グループがスケールすると、このターゲットグループに対するインスタンスの登録および登録解除が自動的に行われます。
+ `VPCZoneIdentifier` は、`Subnets` 入力パラメータの値を、EC2 インスタンスを作成できるパブリックサブネットのリストとして受け取ります。

## ステップ 1: スタックを起動する
<a name="example-templates-autoscaling-launch-stack"></a>

スタックを起動する前に、Amazon EC2、Amazon EC2 Auto Scaling、AWS Systems Manager、Elastic Load Balancing、Amazon SNS、および CloudFormation のすべてのサービスを使用するための AWS Identity and Access Management (IAM) 許可があることを確認してください。

次の手順では、ファイルからサンプルスタックテンプレートをアップロードします。ローカルマシンでテキストエディタを開き、いずれかのテンプレートを追加します。次に、`sampleloadbalancedappstack.template` という名前でファイルを保存します。

**スタックテンプレートを起動するには**

1. AWS マネジメントコンソール にサインインし、CloudFormation コンソール ([https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/)) を開きます。

1. **[スタックの作成]** を選択し、**[新しいリソースの使用 (標準)]** を選択します。

1. **[テンプレートを指定]** で、**[テンプレートファイルをアップロード]**、**[ファイルを選択]** を選択して `sampleloadbalancedappstack.template` ファイルをアップロードします。

1. [**次へ**] を選択します。

1. **[スタックの詳細を指定]** ページで、スタック名 (例: **SampleLoadBalancedAppStack**) を入力します。

1. **[パラメータ]** で、スタックのパラメータを確認し、**[OperatorEmail]**、**[SSHLocation]**、**[KeyName]**、**[VPC]**、**[Subnets]** など、デフォルト値がないすべてのパラメータの値を指定します。

1. **[次へ]** を 2 回選択します。

1. **[レビュー]** ページで、設定を確認します。

1. [**Submit**] を選択してください。

   スタックのステータスは、CloudFormation コンソールの **[ステータス]** 列で確認できます。CloudFormation がスタックを正常に作成すると、**[CREATE\_COMPLETE]** ステータスが表示されます。
**注記**  
スタックを作成した後、メールアドレスで通知の受信を開始するには、サブスクリプションを確認する必要があります。詳細については、「Amazon EC2 Auto Scaling ユーザーガイド」の「[Auto Scaling グループのスケール時に Amazon SNS 通知を受け取る](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-sns-notifications.html)」を参照してください。

## ステップ 2: サンプルリソースをクリーンアップする
<a name="example-templates-autoscaling-clean-up"></a>

未使用のサンプルリソースについて課金されないようにするには、スタックを削除します。

**スタックを削除するには**

1. CloudFormation コンソールで、**[SampleLoadBalancedAppStack]** スタックを選択します。

1. **[削除]** を選択します。

1. 確認メッセージで、**[スタックを削除]** を選択します。

   **[SampleLoadBalancedAppStack]** のステータスが **[DELETE\_IN\_PROGRESS]** に変わります。CloudFormation がスタックの削除を完了すると、リストからスタックが削除されます。

このチュートリアルのサンプルテンプレートを使用して、独自のスタックテンプレートを構築します。詳細については、「*Amazon EC2 Auto Scaling ユーザーガイド*」の「[チュートリアル: スケーリングとロードバランシングを使用するアプリケーションを設定する](https://docs.aws.amazon.com/autoscaling/ec2/userguide/tutorial-ec2-auto-scaling-load-balancer.html)」を参照してください。