

# 在 Amazon EC2 上部署应用程序
<a name="deploying.applications"></a>

您可以使用 CloudFormation 在 Amazon EC2 实例上自动安装、配置和启动应用程序。这样能让您轻松复制部署和更新现有安装而无需直接连接到该实例，从而为您节省大量时间和工作量。

CloudFormation 包括一组基于 `cloud-init` 的帮助程序脚本（`cfn-init`、`cfn-signal`、`cfn-get-metadata` 和 `cfn-hup`）。您可从 CloudFormation 模板中调用这些帮助程序脚本来在使用相同模板的 Amazon EC2 实例上安装、配置和更新应用程序。有关更多信息，请参阅《Amazon CloudFormation 模板参考指南**》中的 [CloudFormation 帮助程序脚本参考](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-helper-scripts-reference.html)。

在[入门教程](gettingstarted.walkthrough.md)中，您使用 `UserData` 和基础 bash 脚本创建了一个简单的 Web 服务器。虽然顺利创建了“Hello World”这样的简单页面，但实际应用程序通常需要更复杂的配置，包括：
+ 按照正确的顺序安装多个软件包。
+ 使用特定内容创建复杂的配置文件。
+ 启动服务并将其配置为自动运行。
+ 错误处理和验证设置过程。

与 `UserData` 中的基础 bash 脚本相比，CloudFormation 的帮助程序脚本提供了一种更稳健、更易于维护的方式来配置 EC2 实例。`cfn-init` 帮助程序脚本可以从模板的元数据中读取配置数据，并将其系统地应用于您的实例。

在本教程中，您将学习如何使用 `cfn-init` 帮助程序脚本以及如何监控引导过程。

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

**Topics**
+ [先决条件](#bootstrapping-tutorial-prerequisites)
+ [了解引导的概念](#bootstrapping-tutorial-understand-concepts)
+ [从简单的引导示例开始](#bootstrapping-tutorial-simple-example)
+ [添加文件和命令](#bootstrapping-tutorial-add-complexity)
+ [增强网络安全](#bootstrapping-tutorial-security-group)
+ [完整的引导模板](#bootstrapping-tutorial-complete-template)
+ [使用控制台创建堆栈。](#bootstrapping-tutorial-create-stack)
+ [监控引导过程](#bootstrapping-tutorial-validate-bootstrap)
+ [测试引导的 Web 服务器](#bootstrapping-tutorial-test-web-server)
+ [引导问题排查](#bootstrapping-tutorial-troubleshooting)
+ [清理 资源](#bootstrapping-tutorial-clean-up)
+ [后续步骤](#bootstrapping-tutorial-next-steps)

## 先决条件
<a name="bootstrapping-tutorial-prerequisites"></a>
+ 您必须已完成 [创建第一个堆栈](gettingstarted.walkthrough.md) 教程或具有 CloudFormation 基础知识的同等经验。
+ 您必须具有对 Amazon Web Services 账户的访问权限，且该账户需要拥有有权使用 Amazon EC2 和 CloudFormation 的 IAM 用户或角色，或者拥有管理用户访问权限。
+ 必须拥有可访问互联网的虚拟私有云（VPC）。本教程模板需要默认 VPC，新版本 Amazon Web Services 账户自动附带该默认 VPC。如果您没有默认 VPC，或者已将其删除，请参阅“[创建第一个堆栈](gettingstarted.walkthrough.md)”教程中的疑难解答部分，了解其他解决方案。

## 了解引导的概念
<a name="bootstrapping-tutorial-understand-concepts"></a>

在创建模板之前，我们先了解一下有助于引导顺利完成的关键概念。

### `cfn-init` 帮助程序脚本
<a name="bootstrapping-tutorial-cfn-init-overview"></a>

CloudFormation 提供 Python 帮助程序脚本，可用于在 Amazon EC2 实例中安装软件和启动服务。`cfn-init` 脚本可以从模板的元数据中读取配置数据，并将其应用于实例。

过程如下所述：

1. 在 EC2 资源的 `Metadata` 部分中定义配置。

1. 从 `UserData` 脚本中调用 `cfn-init`。

1. `cfn-init` 读取元数据并应用配置。

1. 根据规范配置实例。

### 元数据结构
<a name="bootstrapping-tutorial-metadata-structure"></a>

该配置是在 EC2 实例中的特定结构中进行定义。

```
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Metadata:                       # Metadata section for the resource
      AWS::CloudFormation::Init:    # Required key that cfn-init looks for
        config:                     # Configuration name (you can have multiple)
          packages:                 # Install packages
          files:                    # Create files
          commands:                 # Run commands
          services:                 # Start/stop services
```

`cfn-init` 脚本将以特定顺序处理这些部分：packages、groups、users、sources、files、commands，然后是 services。

## 从简单的引导示例开始
<a name="bootstrapping-tutorial-simple-example"></a>

我们先从最简单的引导示例开始，该示例仅安装和启动 Apache。

```
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:                 # Install Apache web server
            yum:
              httpd: []
          services:                 # Start Apache and enable it to start on boot
            systemd:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      UserData: !Base64             # Script that runs when instance starts
        Fn::Sub: |
          #!/bin/bash
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}
```

这个简单的示例演示了核心概念：
+ `packages` 部分使用 yum 安装 `httpd` 软件包。这也适用于 Amazon Linux 和其他使用 yum 的 Linux 发行版。
+ `services` 部分用于确保 `httpd` 自动启动和运行。
+ `UserData` 会安装最新的引导工具并调用 `cfn-init`。

## 添加文件和命令
<a name="bootstrapping-tutorial-add-complexity"></a>

现在，我们来改进示例，在 EC2 实例的 `/var/log` 目录中添加自定义网页和日志文件。

### 创建文件
<a name="bootstrapping-tutorial-files-section"></a>

`files` 部分可让您在实例上创建包含特定内容的文件。直竖线 (`|`) 允许您将文字文本块（HTML 代码）作为文件内容 (`/var/www/html/index.html`) 传递。

```
files:
  /var/www/html/index.html:
    content: |
      <body>
        <h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>
      </body>
```

### 运行命令
<a name="bootstrapping-tutorial-commands-section"></a>

`commands` 部分可让您在引导过程中运行 shell 命令。此命令会在 EC2 实例的 `/var/log/welcome.txt` 位置创建日志文件。要查看该文件，您需要 Amazon EC2 密钥对以进行 SSH 访问，以及 IP 地址范围以便以 SSH 方式连接实例（此处未介绍）。

```
commands:
  createWelcomeLog:
    command: "echo 'cfn-init ran successfully!' > /var/log/welcome.txt"
```

## 增强网络安全
<a name="bootstrapping-tutorial-security-group"></a>

由于我们正在设置 Web 服务器，因此需要允许 Web 流量（HTTP）传输到 EC2 实例。为此，我们将创建一个安全组，以便来自您的 IP 地址的入站流量通过端口 80。EC2 实例还需要将流量发送到互联网，以便实现软件包更新安装等目的。默认情况下，安全组会允许所有出站流量。然后，我们使用 `SecurityGroupIds` 属性将此安全组与 EC2 实例关联。

```
WebServerSecurityGroup:
  Type: AWS::EC2::SecurityGroup
  Properties:
    GroupDescription: Allow HTTP access from my IP address
    SecurityGroupIngress:
      - IpProtocol: tcp
        Description: HTTP
        FromPort: 80
        ToPort: 80
        CidrIp: !Ref MyIP
```

## 完整的引导模板
<a name="bootstrapping-tutorial-complete-template"></a>

现在，我们把所有部分合在一起。这就是之前介绍的所有概念整合而成的完整模板。

```
AWSTemplateFormatVersion: 2010-09-09
Description: Bootstrap an EC2 instance with Apache web server using cfn-init

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: 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 from my IP address
      SecurityGroupIngress:
        - IpProtocol: tcp
          Description: HTTP
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref MyIP

  WebServer:
    Type: AWS::EC2::Instance
    Metadata:
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
          files:
            /var/www/html/index.html:
              content: |
                <body>
                  <h1>Congratulations, you have successfully launched the AWS CloudFormation sample.</h1>
                </body>
          commands:
            createWelcomeLog:
              command: "echo 'cfn-init ran successfully!' > /var/log/welcome.txt"
          services:
            systemd:
              httpd:
                enabled: true
                ensureRunning: true
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: !Ref InstanceType
      SecurityGroupIds:
        - !Ref WebServerSecurityGroup
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash
          yum install -y aws-cfn-bootstrap
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServer --region ${AWS::Region}
      Tags:
        - Key: Name
          Value: Bootstrap Tutorial Web Server

Outputs:
  WebsiteURL:
    Value: !Sub 'http://${WebServer.PublicDnsName}'
    Description: EC2 instance public DNS name
```

## 使用控制台创建堆栈。
<a name="bootstrapping-tutorial-create-stack"></a>

以下过程涉及从文件上传示例堆栈模板。在本地计算机上打开文本编辑器并添加模板。使用文件名 `samplelinux2stack.template` 保存该文件。

**启动堆栈模板**

1. 登录到 Amazon Web Services 管理控制台 并打开 Amazon CloudFormation 控制台 [https://console.aws.amazon.com/cloudformation](https://console.amazonaws.cn/cloudformation/)。

1. 依次选择**创建堆栈**和**使用新资源（标准）**。

1. 在**指定模板**下，选择**上传模板文件**，然后选择**选择文件**，上传 `samplelinux2stack.template` 文件。

1. 选择**下一步**。

1. 在**指定堆栈详细信息**页面上，将堆栈命名为 **BootstrapTutorialStack**。

1. 在**参数**下，执行以下操作。
   + **LatestAmiId**：保留默认值。
   + **InstanceType**：选择 **t2.micro** 或 **t3.micro** 作为 EC2 实例类型。
   + **MyIP**：输入带 `/32` 后缀的公有 IP 地址。

1. 选择两次**下一步**，然后选择**提交**即可创建堆栈。

## 监控引导过程
<a name="bootstrapping-tutorial-validate-bootstrap"></a>

引导过程比简单的 EC2 启动需要更长的时间，因为引导过程中需要安装和配置其他软件。

**监控引导进度**

1. 在 CloudFormation 控制台中，选择堆栈并打开**事件**选项卡。

1. 注意 `WebServer CREATE_IN_PROGRESS` 事件。引导过程在实例启动后开始。

1. 引导过程通常需要花费几分钟的时间。完成时，您可以看到 `WebServer CREATE_COMPLETE`。

如果想知道引导过程中发生了什么，可以查看实例日志。

**查看引导日志（可选）**

1. 打开 [EC2 控制台](https://console.amazonaws.cn/ec2/)，找到您的实例。

1. 选择实例，然后依次选择**操作**、**监控和故障排除**、**获取系统日志**，即可查看引导过程。

1. 如果日志没有即刻出现，请稍等片刻，然后刷新页面。

## 测试引导的 Web 服务器
<a name="bootstrapping-tutorial-test-web-server"></a>

当堆栈显示 `CREATE_COMPLETE` 时，请测试 Web 服务器。

**测试 Web 服务器**

1. 在 CloudFormation 控制台中，转到您堆栈的**输出**选项卡。

1. 单击 **WebsiteURL** 值，在新选项卡中打开 Web 服务器。

1. 您应看到自定义网页和消息 `Congratulations, you have successfully launched the AWS CloudFormation sample`。

**注意**  
如果页面没有立即加载，请稍等片刻，然后重试。即使堆栈已显示 `CREATE_COMPLETE`，引导过程可能仍在完成。

## 引导问题排查
<a name="bootstrapping-tutorial-troubleshooting"></a>

如果引导过程失败或您的 Web 服务器无法运行，以下是常见问题和解决方案。

### 常见问题
<a name="bootstrapping-tutorial-common-issues"></a>
+ **堆栈创建失败**：查看**事件**选项卡以获取相应的错误消息。
+ **无法访问 Web 服务器**：验证 `MyIP` 参数中您的 IP 地址是否正确。别忘了在末尾加上 `/32`。
+ **引导过程失败**：实例可能会启动但 `cfn-init` 失败。按照“监控”章节所述查看系统日志。

## 清理 资源
<a name="bootstrapping-tutorial-clean-up"></a>

为了避免持续产生费用，您可以删除堆栈及其资源来进行清除。

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

1. 打开 [ CloudFormation 控制台](https://console.amazonaws.cn/cloudformation/)。

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

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

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

## 后续步骤
<a name="bootstrapping-tutorial-next-steps"></a>

恭喜您！现在您已经成功地学会如何使用 CloudFormation 引导 EC2 实例。您现在已经知道：
+ 如何使用 `cfn-init` 帮助程序脚本
+ 如何构建用于引导的元数据
+ 如何安装软件包、创建文件、运行命令和管理服务
+ 如何监控引导问题

继续学习：
+ 了解如何更新正在运行的堆栈并使用 `cfn-hup` 帮助程序脚本。有关更多信息，请参阅 [更新 CloudFormation 堆栈](updating.stacks.walkthrough.md)。
+ 了解如何引导 Windows 堆栈。有关更多信息，请参阅 [引导基于 Windows 的 CloudFormation 堆栈](cfn-windows-stacks-bootstrapping.md)。
+ 使用多个配置集探索更复杂的引导情境。有关更多信息，请参阅**《Amazon CloudFormation 模板参考指南》中的 [cfn-init](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-init.html) 和 [AWS::CloudFormation::Init](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/aws-resource-init.html)。
+ 了解如何使用 `cfn-signal` 报告引导完成状态。有关更多信息，请参阅《Amazon CloudFormation 模板参考指南》**中的 [cfn-signal](https://docs.amazonaws.cn/AWSCloudFormation/latest/TemplateReference/cfn-signal.html)。