

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 建置擴展和負載平衡的應用程式
<a name="walkthrough-autoscaling"></a>

在此逐步解說中，您將建立可協助您設定已擴展和已負載平衡應用程式的堆疊。逐步解說提供您將用於建立堆疊的範例範本。範例範本佈建 Auto Scaling 群組、Application Load Balancer、控制負載平衡器和 Auto Scaling 群組流量的安全群組，以及用以發布擴展活動相關通知的 Amazon SNS 通知組態。

此範本會建立一或多個 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 Machine Image (AMI)。如果未指定，您的執行個體會使用 維護的公有 AWS Systems Manager 參數，透過 Amazon Linux 2 AMI 啟動 AWS。如需詳細資訊，請參閱《AWS Systems Manager 使用者指南》**中的[尋找公有參數](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-finding-public-parameters.html)。
+ `OperatorEmail`：您要傳送擴展活動通知的電子郵件地址。
+ `SSHLocation`：可用於對執行個體進行 SSH 存取的 IP 地址範圍。
+ `Subnets`：至少兩個公有子網路位於不同的可用區域。
+ `VPC`：您帳戶中的虛擬私有雲端 (VPC)，可讓公有子網路中的資源連線至網際網路。
**注意**  
您可以使用預設 VPC 和預設子網路，以允許執行個體存取網際網路。在使用自己的 VPC 的情況下，請確定您的 VPC 有一個子網路映射到您正在使用之區域的每個可用區域。必須至少有兩個可用的公有子網路，您才能建立負載平衡器。

此範本的下一部分會指定 `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` 包含 TCP 輸入規則，以允許從連接埠 80 上的*所有 IP 地址*進行存取 ("CidrIp" : "0.0.0.0/0")。

[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 輸入規則。[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` 指定 EC2 執行個體連接埠 (80) 和協定 (HTTP)，`ApplicationLoadBalancer` 向該連接埠和協定路由流量而 Elastic Load Balancing 使用它們來檢查 EC2 執行個體的運作狀態。
+ `HealthCheckIntervalSeconds` 指定 EC2 執行個體在運作狀態檢查間具有 30 秒的間隔。`HealthCheckTimeoutSeconds` 的定義為 Elastic Load Balancing 等待來自運作狀態檢查目標回應的時間長度 (此範例中為 15 秒)。在逾時期間過後，Elastic Load Balancing 便會將 EC2 執行個體的運作狀態檢查標記為不良。當 EC2 執行個體連續三次運作狀態檢查失敗時 (`UnhealthyThresholdCount`)，Elastic Load Balancing 將停止將流量路由到該 EC2 執行個體，直到其連續五次運作狀態檢查的結果為狀態良好為止 (`HealthyThresholdCount`)。此時，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` 將 `LatestAmiId` 輸入參數的值做為要使用的 AMI。
+ `KeyName` 將 `KeyName` 輸入參數的值做為要使用的 EC2 金鑰對。
+ `SecurityGroupIds` 獲取具有邏輯名稱 `EC2SecurityGroup` 安全群組 ID，該安全群組充當您的 EC2 執行個體的虛擬防火牆，以控制傳入的流量。
+ `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) 資源 `WebServerGroup`
+ `MinSize` 及 `MaxSize` 設定 Auto Scaling 群組中 EC2 執行個體的最小及最大數。
+ `TargetGroupARNs` 將接受具有邏輯名稱 `EC2TargetGroup` 的目標群組 ARN。當此 Auto Scaling 群組擴展時，它會自動向此目標群組註冊和取消註冊執行個體。
+ `VPCZoneIdentifier` 將 `Subnets` 輸入參數的值做為公有子網路的清單，EC2 執行個體將在該清單中建立。

## 步驟 1：啟動堆疊
<a name="example-templates-autoscaling-launch-stack"></a>

啟動堆疊之前，請檢查您是否具有使用下列所有服務的 AWS Identity and Access Management (IAM) 許可：Amazon EC2、Amazon EC2 Auto Scaling AWS Systems Manager、Elastic Load Balancing、Amazon SNS 和 CloudFormation。

下列程序涉及從檔案上傳範例堆疊範本。在本機電腦上打開文字編輯器，然後新增其中一個範本。儲存檔案，並將其命名為 `sampleloadbalancedappstack.template`。

**啟動堆疊範本**

1. 登入 AWS 管理主控台 並在 https：//[https://console.aws.amazon.com/cloudformation](https://console.aws.amazon.com/cloudformation/) 開啟 CloudFormation 主控台。

1. 選擇 **Create stack (建立堆疊)**、**With new resources (standard) (使用新資源 (標準))**。

1. 在**指定範本**下，選擇**上傳範本檔案**，然後選擇**選擇檔案**以上傳 `sampleloadbalancedappstack.template` 檔案。

1. 選擇**下一步**。

1. 在**指定詳細資訊**頁面上，輸入堆疊名稱 (例如 **SampleLoadBalancedAppStack**)。

1. 在**參數**下，檢閱堆疊的參數並為無預設值的所有參數提供值，包括 **OperatorEmail**、**SSHLocation**、**KeyName**、**VPC** 和 **Subnets**。

1. 選擇 **Next** (下一步) 兩次。

1. 在**檢視** 頁面上，檢視和確認的設定。

1. 選擇**提交**。

   您可以在狀態欄的 CloudFormation 主控台中檢視堆疊**的狀態**。當 CloudFormation 成功建立堆疊時，您會收到 **CREATE\$1COMPLETE** 狀態。
**注意**  
在建立堆疊之後，您必須先確認訂閱，電子郵件地址才能開始接收通知。如需詳細資訊，請參閱《*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\$1IN\$1PROGRESS**。當 CloudFormation 完成刪除堆疊時，會從清單中移除堆疊。

使用此逐步解說的範例範本建置您自己的堆疊範本。如需詳細資訊，請參閱《Amazon EC2 Auto Scaling 使用者指南》**中的[教程：設定擴展和負載平衡的應用程式](https://docs.aws.amazon.com/autoscaling/ec2/userguide/tutorial-ec2-auto-scaling-load-balancer.html)。