

# 创建第一个堆栈
<a name="gettingstarted.walkthrough"></a>

本文演示使用 AWS 管理控制台 创建第一个 CloudFormation 堆栈的过程。学习本教程后，您将会了解如何配置基础 AWS 资源、监控堆栈事件和生成输出。

在本示例中，CloudFormation 模板采用 YAML 格式编写。YAML 是一种人类可解读的格式，广泛用于将基础架构定义为代码。您对 CloudFormation 的了解越来越多后，可能还会遇到其他 JSON 格式的模板，但是本教程选择使用 YAML，因为它的可读性好。

**注意**  
CloudFormation 使用免费，但您需要为自己创建的 Amazon EC2 和 Amazon S3 资源付费。如果您不熟悉 AWS，可以利用[免费套餐](https://aws.amazon.com/free/)来最大限度地降低或避免在学习过程产生费用。

**Topics**
+ [先决条件](#getting-started-prerequisites)
+ [使用控制台创建 CloudFormation 堆栈](#getting-started-create-stack)
+ [监控堆栈创建](#getting-started-monitor-stack-creation)
+ [测试 Web 服务器](#getting-started-test-web-server)
+ [问题排查](#getting-started-troubleshooting)
+ [清理](#getting-started-clean-up)
+ [后续步骤](#getting-started-next-steps)

## 先决条件
<a name="getting-started-prerequisites"></a>
+ 您必须具有对 AWS 账户的访问权限，且该账户需要拥有有权使用 Amazon EC2、Amazon S3 和 CloudFormation 的 IAM 用户或角色，或者拥有管理用户访问权限。
+ 必须拥有可访问互联网的虚拟私有云（VPC）。本演练模板需要默认 VPC，新版本 AWS 账户自动附带该默认 VPC。如果您没有默认 VPC，或者已将其删除，请参阅本主题中的疑难解答章节，了解其他解决方案。

## 使用控制台创建 CloudFormation 堆栈
<a name="getting-started-create-stack"></a>

**使用控制台创建 Hello world CloudFormation 堆栈**

1. 打开 [ CloudFormation 控制台](https://console.aws.amazon.com/cloudformation/)。

1. 选择**创建堆栈**。

1. 在**创建堆栈**页面上，选择**从基础架构编辑器构建**，然后选择**在基础架构编辑器中创建**。这会将您转至 CloudFormation 控制台模式下的基础架构编辑器，您可以在其中上传和验证示例模板。

1. 要创建和验证示例模板，请执行以下操作：

   1. 选择**模板**。然后，将下列 CloudFormation 模板复制粘贴到模板编辑器：

      ```
      AWSTemplateFormatVersion: 2010-09-09
      Description: CloudFormation Template for WebServer with Security Group and EC2 Instance
      
      Parameters:
        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'
      
        InstanceType:
          Description: WebServer EC2 instance type
          Type: String
          Default: t2.micro
          AllowedValues:
            - t3.micro
            - t2.micro
          ConstraintDescription: must be a valid EC2 instance type.
          
        MyIP:
          Description: Your IP address in CIDR format (e.g. 203.0.113.1/32).
          Type: String
          MinLength: '9'
          MaxLength: '18'
          Default: 0.0.0.0/0
          AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$'
          ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
      
      Resources:
        WebServerSecurityGroup:
          Type: AWS::EC2::SecurityGroup
          Properties:
            GroupDescription: Allow HTTP access via my IP address
            SecurityGroupIngress:
              - IpProtocol: tcp
                FromPort: 80
                ToPort: 80
                CidrIp: !Ref MyIP
      
        WebServer:
          Type: AWS::EC2::Instance
          Properties:
            ImageId: !Ref LatestAmiId
            InstanceType: !Ref InstanceType
            SecurityGroupIds:
              - !Ref WebServerSecurityGroup
            UserData: !Base64 |
              #!/bin/bash
              yum update -y
              yum install -y httpd
              systemctl start httpd
              systemctl enable httpd
              echo "<html><body><h1>Hello World!</h1></body></html>" > /var/www/html/index.html
      
      Outputs:
        WebsiteURL:
          Value: !Join
            - ''
            - - http://
              - !GetAtt WebServer.PublicDnsName
          Description: Website URL
      ```

      在继续下一步之前，我们花些时间来了解一下模板和一些关键的 CloudFormation 概念。
      + **`Parameters`** 部分声明在创建堆栈时可传递给模板的值。稍后在模板中指定的资源会引用这些值并使用这些数据。如果要指定不想存储在模板内的信息，使用参数就是非常有效的办法。这种方法也可以用于指定对正在部署的特定应用程序或配置可能具有唯一性的信息。
      + 模板会定义以下参数：
        + **`LatestAmiId`** – 从 AWS Systems Manager Parameter Store 检索最新的 Amazon Linux 2 AMI ID。
        + **`InstanceType`** – 允许选择 EC2 实例类型（默认：`t2.micro`，允许：`t3.micro`、`t2.micro`）。
        + **`MyIP`** – 指定 HTTP 访问权限的 IP 地址范围（默认：0.0.0.0/0，允许来自任意 IP 的访问）。
      + **`Resources`** 部分包含要使用该模板创建的 AWS 资源的定义。资源声明是立即指定这些所有配置设置的一种有效方法。如果您将资源声明放入模板，您将可以使用该模板创建和配置所有的声明资源，从而创建堆栈。您也可以使用相同模板创建新的堆栈，来启动相同的资源配置。
      + 此模板创建以下资源：
        + **`WebServerSecurityGroup`** – EC2 安全组，允许来自指定 IP 范围的端口 80 上的入站 HTTP 流量。
        + **`WebServer`** – 具有以下配置的 EC2 实例：
          + 使用最新的 Amazon Linux 2 AMI
          + 应用选定的实例类型
          + 将 `WebServerSecurityGroup` 添加到 `SecurityGroupIds`属性
          + 包括用于安装 Apache HTTP 服务器的用户数据脚本
      + 在每个资源和参数声明的开头都指定逻辑名称。例如，`WebServerSecurityGroup` 是分配给 EC2 安全组资源的逻辑名称。然后，系统会使用 `Ref` 函数来按资源和参数在模板其他部分中的逻辑名称来引用资源和参数。如果一个资源引用另一个资源，两者之间会形成依赖关系。
      + **`Outputs`** 部分定义堆栈创建后返回的自定义值。您可以使用输出值在堆栈中返回来自资源的信息，例如资源标识符或 URL。
      + 该模板定义了一个输出：
        + **`WebsiteURL`** – 已部署 Web 服务器的 URL（使用 EC2 实例的公有 DNS 名称构建）。`Join` 函数可以将固定 `http://` 和可变 `PublicDnsName` 组合成一个字符串，从而轻松输出 Web 服务器的完整 URL。

   1. 选择**验证**以确保 YAML 代码有效，然后再上传模板。

   1. 接下来，选择**创建模板**以创建模板并将其添加到 S3 存储桶。

   1. 在开启的对话框中，记下 S3 存储桶的名称，之后便可删除。然后，选择**确认并继续前往 CloudFormation**。这会将您转至 CloudFormation 控制台，现在模板的 S3 路径已在控制台中指定。

1. 在**创建堆栈**主页上，选择**下一步**。

1. 在**指定堆栈详细信息**页面的**堆栈名称**字段中，输入名称。堆栈名中不得含有空格。对于本示例，请使用 **MyTestStack**。

1. 在**参数**下，指定参数值，如下所示：
   + **LatestAmiId**：此值默认设定为最新的 Amazon Linux 2 AMI。
   + **InstanceType**：选择 **t2.micro** 或 **t3.micro** 作为 EC2 实例类型。
**注意**  
如果您是 AWS 新用户，您可以使用免费套餐在 12 个月内免费启动和使用 `t2.micro` 实例（在 `t2.micro` 不可用的区域，您可以通过免费套餐使用 `t3.micro` 实例）。
   + **MyIP**：使用 `/32` 后缀指定实际公有 IP 地址。在 CIDR 表示法中使用 `/32` 后缀来指定允许使用单个 IP 地址。这基本上意味着仅允许流入和流出此特定 IP 地址的流量，而不允许其他 IP 地址的流量。

1. 选择**下一步**两次，前往**检查和创建**页面。在本教程中，您可以保留**配置堆栈选项**页面的默认值。

1. 审查堆栈信息。如果对设置满意，请选择 **Submit (提交)**。

## 监控堆栈创建
<a name="getting-started-monitor-stack-creation"></a>

选择**提交**后，CloudFormation 将开始创建模板中指定的资源。您的新堆栈 (**MyTestStack**) 将显示在 **CloudFormation** 控制台顶部的列表中。状态应为 `CREATE_IN_PROGRESS`。您可以通过查看事件了解堆栈的详细状态。

**想要查看堆栈的事件**

1. 在 CloudFormation 控制台上，选择列表中的堆栈 **MyTestStack**。

1. 在堆栈详细信息窗格中，选择 **Events (事件)** 选项卡。

   控制台每 60 秒自动使用最新事件刷新事件列表。

**Events (事件)** 选项卡显示堆栈创建过程中的每个重要步骤（按每个事件的时间排序，最新事件位于最上面）。

第一个事件 (在事件列表最底部) 为堆栈创建过程的开始：

`2024-12-23 18:54 UTC-7 MyTestStack CREATE_IN_PROGRESS User initiated`

下面是标志所有资源创建开始和完成的事件。例如，创建 EC2 实例后会产生以下条目：

`2024-12-23 18:59 UTC-7 WebServer CREATE_COMPLETE`

`2024-12-23 18:54 UTC-7 WebServer CREATE_IN_PROGRESS Resource creation initiated`

当 CloudFormation 报告它已开始创建资源时，将记录 `CREATE_IN_PROGRESS` 事件。在资源创建成功时，将记录 `CREATE_COMPLETE` 事件。

当 CloudFormation 成功创建了堆栈时，您将会在 **Event (事件)** 选项卡顶部看到下列事件：

`2024-12-23 19:17 UTC-7 MyTestStack CREATE_COMPLETE`

如果 CloudFormation 无法创建资源，它将报告 `CREATE_FAILED` 事件，并（在默认情况下）回滚堆栈、删除已创建的所有资源。**状态原因**列显示已导致失败的问题。

创建堆栈后，您可以前往**资源**选项卡查看创建的 EC2 实例和安全组。

## 测试 Web 服务器
<a name="getting-started-test-web-server"></a>

成功创建堆栈后，在 CloudFormation 控制台中前往**输出**选项卡。找到 **WebsiteURL** 字段。字段中会包含 EC2 实例的公有 URL。

打开浏览器并前往 **WebsiteURL** 下列出的 URL。您会在浏览器中看到一条简单的 "Hello World\$1" 消息。

这表示您的 EC2 实例正在运行 Apache HTTP 服务器并提供基本网页。

## 问题排查
<a name="getting-started-troubleshooting"></a>

如果您在创建堆栈期间遇到回滚，这可能是缺少 VPC 所致。解决办法如下。

### 没有可用的默认 VPC
<a name="getting-started-troubleshooting-no-default-vpc"></a>

本演练中的模板需要默认 VPC。如果因为 VPC 或子网可用性错误而出现堆栈创建失败的情况，这可能是因为账户中没有默认 VPC。您有以下选项：
+ **创建新的默认 VPC**：可以通过 Amazon VPC 控制台创建新的默认 VPC。有关说明，请参阅《Amazon VPC 用户指南》**中的[创建默认 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/work-with-default-vpc.html#create-default-vpc)。
+ **修改模板以指定子网**：如果您有非默认 VPC，则可以修改模板以明确指定 VPC 和子网 ID。将以下参数添加到模板：

  ```
    SubnetId:
      Description: The subnet ID to launch the instance into
      Type: AWS::EC2::Subnet::Id
  ```

  然后，更新 `WebServer` 资源以包含子网 ID：

  ```
    WebServer:
      Type: AWS::EC2::Instance
      Properties:
        ImageId: !Ref LatestAmiId
        InstanceType: !Ref InstanceType
        SecurityGroupIds:
          - !Ref WebServerSecurityGroup
        SubnetId: !Ref SubnetId
        UserData: !Base64 |
          #!/bin/bash
          yum update -y
          yum install -y httpd
          systemctl start httpd
          systemctl enable httpd
          echo "<html><body><h1>Hello World!</h1></body></html>" > /var/www/html/index.html
  ```

  创建堆栈时，您需要指定一个可以访问互联网的子网才能确保 Web 服务器可供访问。

## 清理
<a name="getting-started-clean-up"></a>

为了保证您不为不需要的服务承担费用，您可以通过删除堆栈和它的资源进行清理。您也可以删除存储堆栈模板的 S3 存储桶。

**想要删除堆栈和它的资源**

1. 打开 [ CloudFormation 控制台](https://console.aws.amazon.com/cloudformation/)。

1. 在**堆栈**页面上，选择您创建的堆栈名称旁的选项（**MyTestStack**），然后选择**删除**。

1. 当系统提示进行确认时，选择 **Delete（删除）**。

1. 在**事件**选项卡上监控堆栈删除过程的进度。**MyTestStack** 的状态更改为 `DELETE_IN_PROGRESS`。当 CloudFormation 完成删除堆栈后，它会将从列表中移堆栈除。

如果您已完成此示例模板的使用，不再需要 Amazon S3 存储桶，请将其删除。您必须先清空存储桶，然后才能删除存储桶。清空存储桶将删除存储桶中的所有对象。

**清空和删除 Amazon S3 存储桶**

1. 打开 [Amazon S3 控制台](https://console.aws.amazon.com/s3/)。

1. 在控制台左侧的导航窗格中，选择 **Buckets（存储桶）**。

1. 在**存储桶**列表中，选择要为本教程创建的存储桶名称旁的选项，然后选择**清空**。

1. 在**清空存储桶**页面上，通过在文本字段中键入 **permanently delete** 来确认要清空存储桶，然后选择**清空**。

1. 在**清空存储桶：状态**页面上监控存储桶清空过程的进度。

1. 要返回到存储桶列表，请选择**退出**。

1. 选择存储桶名称旁的选项，然后选择**删除**。

1. 在系统提示进行确认时，键入存储桶的名称，然后选择**删除存储桶**。

1. 在**存储桶**清单上监控存储桶删除过程的进度。Amazon S3 完成存储桶删除后，会将存储桶从列表中移除。

## 后续步骤
<a name="getting-started-next-steps"></a>

恭喜您！您已成功创建了堆栈、监控了堆栈的创建并使用了堆栈的输出。

继续学习：
+ 详细了解模板以便自己创建模板。有关更多信息，请参阅 [使用 CloudFormation 模板](template-guide.md)。
+ 试试参加 [CloudFormation 入门](https://catalog.us-east-1.prod.workshops.aws/workshops/df7f72cf-4f10-4664-acb6-b30dc8d4bcf0/en-US)研习会，获得更多模板创建动手实践。
+ 有关 [CloudFormation 入门](https://catalog.us-east-1.prod.workshops.aws/workshops/df7f72cf-4f10-4664-acb6-b30dc8d4bcf0/en-US)的简短版本，请参阅[在 Amazon EC2 上部署应用程序](deploying.applications.md)。本主题同样描述了使用 CloudFormation 帮助程序脚本 `cfn-init` 的情境，但是用于引导 Amazon EC2 实例。