

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 向您的产品添加 CloudFormation 模板
<a name="cloudformation"></a>

AWS Marketplace 卖家可以使用 AWS CloudFormation 模板发布配送给 AWS Marketplace 买家的基于 AMI 的商品。在基于 AMI 的产品中添加 CloudFormation 模板后，您的买家无需手动配置资源和依赖关系即可部署您的解决方案。您可以使用这些模板定义集群或者产品的分布式架构，也可用于选择不同 AMI 组合或产品配置。单个 AMI 解决方案最多可以包含三个 CloudFormation 模板。

可以将 CloudFormation 模板配置为提供包含相关配置文件和 Lambda 函数的单个 Amazon 系统映像 (AMI)。此外，您必须为每个模板添加架构示意图。

**Topics**
+ [准备您的 CloudFormation 模板](#aws-cloudformation-template-preparation)
+ [架构示意图](#topology-diagram)
+ [转换现有产品的 CloudFormation 模板](#convert-cloudformation-templates)
+ [添加无服务器应用程序组件](cloudformation-serverless-application.md)

## 准备您的 CloudFormation 模板
<a name="aws-cloudformation-template-preparation"></a>

要构建 CloudFormation 模板，必须满足模板的先决条件并提供所需的输入和安全参数。提交 CloudFormation 模板时，请使用以下各节中的指南。

### 模板先决条件
<a name="template-prerequisites"></a>
+ 验证模板是否已通过 CloudFormation 控制台成功启动，** AWS 区域 且已为您的产品启用所有功能**。您可以使用该[TaskCat 工具](https://github.com/aws-quickstart/taskcat)来测试您的模板。
+ AMIs 您的 CloudFormation 模板中必须包含您要发布的产品的 AMI 或 AWS 托管的 AMI，例如最新的 Amazon Linux 2。请勿包含任何社区 AMI 或者您或任何其他第三方拥有和共享的 AMI。要使用 AWS 托管的 AMI，请使用 S [AWS ystems Manager 参数存储中的公共参数，而不是硬](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters.html)编码 AMI。 IDs例如，在指定 AMI ID 的 CloudFormation 模板中，您可以使用动态引用`ImageId: '{{resolve:ssm:/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id}}'`。
+ 生成模板，使其不必依赖于使用特定可用区 (AZ)。并非所有客户都能访问所有账户 AZs， AZs 而且不同账户的映射方式也不同。
+ 如果您在生成使用自动扩缩组的集群解决方案，我们建议您考虑到扩展事件。新节点应自动加入正在运行的集群。
+ 对于单节点产品，我们建议使用[自动扩缩组](https://docs.aws.amazon.com/autoscaling/latest/userguide/create-asg-from-instance.html)。
+ 在解决方案涉及含多个实例的集群时，如果您希望在集群之间降低网络延迟时和/或提升网络吞吐量，请考虑使用置放群组。
+ 为了便于 AWS Marketplace 团队审核并向客户透明，我们建议您在**UserData**栏目中添加评论。

### AMI 详情要求
<a name="ami-requirements-sse"></a>

**注意**  
如果您在卖家门户的[服务器产品](https://aws.amazon.com//marketplace/management/products/server)页面 CloudFormation上**使用创建亚马逊系统映像 (AMI) 或 AMI**，并且系统提示您下载[商品加载表](https://docs.aws.amazon.com//marketplace/latest/userguide/product-submission.html#aws-cloudformation-launched-product-free-or-paid-or-usage-based-paid-ami-product)，请[使用产品加载表单的 AMI 详情要求](#ami-requirements-product-load-form)改为参阅。

在指定将 AMI 部署到 EC2 实例的资源（例如[AWS::EC2::Instance[AWS::AutoScaling::LaunchConfiguration](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html)](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/aws-resource-ec2-instance.html)、和[AWS::EC2::LaunchTemplate](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/aws-resource-ec2-launchtemplate.html)资源）的`ImageId`属性时，必须引用[模板参数。](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/parameters-section-structure.html)参数类型必须是 `AWS::EC2::Image::Id`、`AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>` 或 `String`。

您可以将此模板参数命名为任何有效的参数名称。 AWS Marketplace 将您的模板复制到其自己的 Amazon S3 存储桶中，并将指定参数替换为[AWS Systems Manager 参数存储](https://docs.aws.amazon.com//systems-manager/latest/userguide/systems-manager-parameter-store.html)参数。 AWS Marketplace 还会更新描述和约束文本，使部署模板的买家能够清楚地看到正确的值。当买家部署您的模板时，该参数会解析为已发布产品的 AWS 区域特定 AMI ID。

以下模板示例说明了使用内置函数 [Ref](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html) 引用模板参数的 `ImageId` 属性。

YAML 示例：

```
Parameters:
  ImageId:
    Type: AWS::EC2::Image::Id
    Default: ami-example1234567890
Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
```

JSON 示例：

```
{
  "Parameters": {
    "ImageId": {
      "Type": "AWS::EC2::Image::Id",
      "Default": "ami-example1234567890"
    }
  },
  "Resources": {
    "MyInstance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": {
          "Ref": "ImageId"
        }
      }
    }
  }
}
```

如果您在[嵌套堆栈](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html)而非根堆栈中部署 EC2 实例，则 AMI ID 必须从根堆栈动态继承其值。编辑您的根堆栈和嵌套堆栈，确保在根堆栈中设置模板参数的值时，能够覆盖此嵌套堆栈中使用的 AMI ID。

### 使用产品加载表单的 AMI 详情要求
<a name="ami-requirements-product-load-form"></a>

**注意**  
如果您在卖家门户网站的[服务器产品](https://aws.amazon.com//marketplace/management/products/server)页面 CloudFormation上创建**亚马逊系统映像 (AMI) 或 AMI**，但系统没有立即提示您下载[产品加载表](https://docs.aws.amazon.com//marketplace/latest/userguide/product-submission.html#aws-cloudformation-launched-product-free-or-paid-or-usage-based-paid-ami-product)，请[AMI 详情要求](#ami-requirements-sse)改为查看。

AMIs 必须位于每个区域的映射表中。在 AMI 被克隆 IDs后， AWS Marketplace 团队会对其进行更新。您的源 AMI 必须位于 `us-east-1` 区域。其他区域可使用占位符。

YAML 示例：

```
Mappings: 
  RegionMap: 
      us-east-1: 
          ImageId: ami-0123456789abcdef0
      us-west-1: 
          ImageId: ami-xxxxxxxxxxxxxxxxx
      eu-west-1: 
          ImageId: ami-xxxxxxxxxxxxxxxxx
      ap-southeast-1: 
          ImageId: ami-xxxxxxxxxxxxxxxxx
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap 
        - RegionMap
        - !Ref AWS::Region
        - ImageId
```

### 对嵌套堆栈模板的要求
<a name="nested-stack-template-requirements"></a>

**注意**  
本节仅适用于未使用[产品加载表单](https://docs.aws.amazon.com//marketplace/latest/userguide/product-submission.html#aws-cloudformation-launched-product-free-or-paid-or-usage-based-paid-ami-product)的定价模式。对于*使用*产品加载表单的定价模式，嵌套堆栈 `TemplateURL` 属性只允许使用固定字符串。

如果您的模板包含[嵌套堆栈](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html)，则嵌套堆栈资源的 `TemplateURL` 属性必须引用 Amazon S3 存储桶名称、存储桶区域和 Amazon S3 对象密钥前缀的模板参数。其中，存储桶名称的参数名称必须为 `MPS3BucketName`，存储桶区域必须为 `MPS3BucketRegion`，对象键前缀必须为 `MPS3KeyPrefix`。

将这些参数的默认值设置为与存储嵌套模板的 Amazon S3 存储桶相对应。所有嵌套模板必须可公开访问。当您提交模板进行发布时，会将您的模板 AWS Marketplace 复制到其自己的 Amazon S3 存储桶中，并修改这三个参数的属性，使其默认值和允许值设置为与副本的存储位置相对应。 AWS Marketplace 还会更新描述和约束文本，使部署模板的买家能够清楚地看到正确的值。

如果您有多个级别的嵌套堆栈，则必须配置所有创建其他嵌套堆栈的嵌套堆栈，以便 `TemplateURL` 属性动态继承根堆栈中的 Amazon S3 存储桶名称、Amazon S3 存储桶区域和 Amazon S3 对象键的值。请编辑您的根堆栈和嵌套堆栈，确保在根堆栈中设置模板参数 `MPS3BucketName`、`MPS3BucketRegion` 和 `MPS3KeyPrefix` 的值时，能够覆盖此嵌套堆栈中用于创建更多嵌套堆栈的 URL 中对应的值。

以下模板示例说明了使用内置函数 [Fn::Sub](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html) 引用模板参数的 `TemplateURL` 属性。

YAML 示例：

```
AWSTemplateFormatVersion: '2010-09-09'
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: AWS Marketplace Parameters
        Parameters:
          - ImageId
          - MPS3BucketName
          - MPS3BucketRegion
          - MPS3KeyPrefix
Parameters:
  ImageId:
    Type: AWS::EC2::Image::Id
    Default: ami-example1234567890
    Description: The AMI that will be used to launch EC2 resources.
  MPS3BucketName:
    Type: String
    Default: sellerbucket
    Description: Name of the S3 bucket for your copy of the nested templates.
  MPS3BucketRegion:
    Type: String
    Default: us-east-1
    Description: AWS Region where the S3 bucket for your copy of the nested templates is hosted.
  MPS3KeyPrefix:
    Type: String
    Default: sellerproductfolder/
    Description: S3 key prefix that is used to simulate a folder for your copy of the nested templates.
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
  NestedStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub https://${MPS3BucketName}.s3.${MPS3BucketRegion}.${AWS::URLSuffix}/${MPS3KeyPrefix}nested-template.yaml
```

JSON 示例：

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Metadata": {
        "AWS::CloudFormation::Interface": {
            "ParameterGroups": [
                {
                    "Label": {
                        "default": "AWS Marketplace Parameters"
                    },
                    "Parameters": [
                        "ImageId",
                        "MPS3BucketName",
                        "MPS3BucketRegion",
                        "MPS3KeyPrefix"
                    ]
                }
            ]
        }
    },
    "Parameters": {
        "ImageId": {
            "Type": "AWS::EC2::Image::Id",
            "Default": "ami-example1234567890",
            "Description": "The AMI that will be used to launch EC2 resources."
        },
        "MPS3BucketName": {
            "Type": "String",
            "Default": "sellerbucket",
            "Description": "Name of the S3 bucket for your copy of the nested templates."
        },
        "MPS3BucketRegion": {
            "Type": "String",
            "Default": "us-east-1",
            "Description": "AWS Region where the S3 bucket for your copy of the nested templates is hosted."
        },
        "MPS3KeyPrefix": {
            "Type": "String",
            "Default": "sellerproductfolder/",
            "Description": "S3 key prefix that is used to simulate a folder for your copy of the nested templates."
        }
    },
    "Resources": {
        "EC2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Ref": "ImageId"
                }
            }
        },
        "NestedStack": {
            "Type": "AWS::CloudFormation::Stack",
            "Properties": {
                "TemplateURL": {
                    "Fn::Sub": "https://${MPS3BucketName}.s3.${MPS3BucketRegion}.${AWS::URLSuffix}/${MPS3KeyPrefix}nested-template.yaml"
                }
            }
        }
    }
}
```

**注意**  
[AWS::CloudFormation::Interface](https://docs.aws.amazon.com//AWSCloudFormation/latest/UserGuide/aws-resource-cloudformation-interface.html)用于定义买家部署您的模板时如何在 AWS CloudFormation 控制台中对参数进行分组和排序。

### 模板输入参数
<a name="template-input-parameters"></a>
+ 模板的输入参数不得包含 AWS Marketplace 客户的 AWS 凭证（例如密码、公钥、私钥或证书）。
+ 对于密码等敏感输入参数，请选择 `NoEcho` 属性并启用更严格的正则表达式。对于其他输入参数，设置最常见的输入以及相应的帮助文本。
+ 如果可用，请使用 CloudFormation 参数类型进行输入。
+ 使用 `AWS::CloudFormation::Interface` 来分组和排序输入参数。
+ 请勿为以下输入参数设置任何默认值：
**注意**  
客户必须提供这些内容作为输入参数。
  + 允许从公共互联网进入远程访问端口的默认 CIDR 范围
  + 允许从公共互联网进入数据库连接端口的默认 CIDR 范围
  + 用户或数据库的默认密码

### 网络和安全参数
<a name="networksecurity-parameters"></a>
+ 确保默认 SSH 端口 (22) 或 RDP 端口 (3389) 未对 0.0.0.0 打开。
+ 我们建议您使用适当的访问控制列表 () 和安全组来构建 VPC，而不是使用默认的虚拟私有云 (VPCACLs)。
+ 您的模板无法向用户请求长期访问密钥，也无法创建这些密钥来访问 AWS 资源。如果您的 AMI 应用程序需要访问买家账户中的 AWS 服务，则它必须使用适用[于 Amazon EC2 的 IAM 角色](/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)。
+ 将 IAM 角色和策略设置为[授予最低权限](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)，并且仅在绝对需要时启用写入访问权限。例如，如果您的应用程序只需要 `S3:GET`、`PUT` 和 `DELETE` 操作，则仅指定这些操作。在这种情况下，我们不建议使用 `S3:*`。

收到您的模板后，将 AWS Marketplace 验证产品配置和信息，并就所有必需的修订提供反馈。

## 架构示意图
<a name="topology-diagram"></a>

您必须为每个模板提供架构示意图。要了解有关绘图的更多信息，请参阅[什么是架构绘图？](https://aws.amazon.com/what-is/architecture-diagramming/)

示意图必须符合以下标准：
+ 在上演示标准部署 AWS。
+ 从逻辑上描述资源的部署位置。例如，Amazon EC2 实例等资源位于正确的子网中。
+ 对通过 CloudFormation 模板 AWS 服务 部署的每个 AWS 产品使用最新的产品图标。要下载最新的架构图标集，请查看 [AWS 架构图标](https://aws.amazon.com/architecture/icons/)。
+ 包括 CloudFormation 模板部署的所有服务的元数据。
+ 包括 CloudFormation 模板部署的所有网络和子网。 VPCs
+ 显示集成点，包括第三方资产 APIs 和本地混合资产。
+ 图表大小必须为 1100 x 700 像素。保持原始图表比例，无需拉伸或裁剪。

## 转换现有产品的 CloudFormation 模板
<a name="convert-cloudformation-templates"></a>

**注意**  
本部分适用于现有 AMI 的卖家，其 CloudFormation 商品使用[商品加载表](https://docs.aws.amazon.com/marketplace/latest/userguide/product-submission.html#aws-cloudformation-launched-product-free-or-paid-or-usage-based-paid-ami-product)发布了模板，现在想在不使用商品加载表的情况下更新该模板。如果您要发布新产品，请参阅[准备 CloudFormation 模板](https://docs.aws.amazon.com/marketplace/latest/userguide/cloudformation.html#aws-cloudformation-template-preparation)。  
如果您在卖家门户网站的[服务器产品](https://aws.amazon.com//marketplace/management/products/server)页面 CloudFormation上创建**亚马逊系统映像 (AMI) 或 AMI**，并且系统提示您下载[商品加载表](https://docs.aws.amazon.com//marketplace/latest/userguide/product-submission.html#aws-cloudformation-launched-product-free-or-paid-or-usage-based-paid-ami-product)，请参阅[使用产品加载表单的 AMI 详情要求](#ami-requirements-product-load-form)。

如果您想使用自助服务体验来更新以前使用[产品加载表单](https://docs.aws.amazon.com/marketplace/latest/userguide/product-submission.html#aws-cloudformation-launched-product-free-or-paid-or-usage-based-paid-ami-product)发布的现有产品，则必须对现有 CloudFormation模板进行更改。

下表描述了使用产品加载表单和自助服务体验之间的区别：


****  

|  | 产品加载表单 | 自助服务体验 | 
| --- | --- | --- | 
| EC2 资源的 ImageId 属性的值 | 引用您的 AMI ID 的映射表。有关更多信息，请参阅 [使用产品加载表单的 AMI 详情要求](#ami-requirements-product-load-form)。 | 引用您的 AMI ID 的模板参数。有关更多信息，请参阅 [AMI 详情要求](#ami-requirements-sse)。 | 
| 嵌套堆栈的 TemplateURL 属性的值 | 必须是固定字符串，不能使用内置函数。 | 可通过内置函数实现动态取值。必须引用一组模板参数。有关更多信息，请参阅 [对嵌套堆栈模板的要求](#nested-stack-template-requirements)。 | 

以下示例模板说明了使用产品加载表单发布模板的现有产品的示例。在此示例中，AMI ID 为 `ami-example123456`，嵌套模板存储在卖家的 S3 存储桶中，具体路径为 `https://sellerbucket.s3.us-east-1.amazonaws.com/sellerproductfolder/nested-template.yaml`。

使用产品加载表单发布的 YAML 示例：

```
AWSTemplateFormatVersion: '2010-09-09'
Mappings:
  RegionMap:
    us-east-1:
      AMI: ami-example123456
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap 
        - RegionMap
        - !Ref AWS::Region
        - AMI
  NestedStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://sellerbucket.s3.us-east-1.amazonaws.com/sellerproductfolder/nested-template.yaml
```

使用产品加载表单发布的 JSON 示例：

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Mappings": {
        "RegionMap": {
            "us-east-1": {
                "AMI": "ami-example123456"
            }
        }
    },
    "Resources": {
        "EC2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "RegionMap",
                        {
                            "Ref": "AWS::Region"
                        },
                        "AMI"
                    ]
                }
            }
        },
        "NestedStack": {
            "Type": "AWS::CloudFormation::Stack",
            "Properties": {
                "TemplateURL": "https://sellerbucket.s3.us-east-1.amazonaws.com/sellerproductfolder/nested-template.yaml"
            }
        }
    }
}
```

以下模板示例说明了使用自助服务体验更新产品所需的更改。

通过自助服务体验发布的 YAML 示例：

```
AWSTemplateFormatVersion: '2010-09-09'
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: AWS Marketplace Parameters
        Parameters:
          - ImageId
          - MPS3BucketName
          - MPS3BucketRegion
          - MPS3KeyPrefix
Parameters:
  ImageId:
    Type: AWS::EC2::Image::Id
    Default: ami-example123456
    Description: The AMI that will be used to launch EC2 resources.
  MPS3BucketName:
    Type: String
    Default: sellerbucket
    Description: Name of the S3 bucket for your copy of the nested templates.
  MPS3BucketRegion:
    Type: String
    Default: us-east-1
    Description: AWS Region where the S3 bucket for your copy of the nested templates is hosted.
  MPS3KeyPrefix:
    Type: String
    Default: sellerproductfolder/
    Description: S3 key prefix that is used to simulate a folder for your copy of the nested templates.
Resources:
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref ImageId
  NestedStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub https://${MPS3BucketName}.s3.${MPS3BucketRegion}.${AWS::URLSuffix}/${MPS3KeyPrefix}nested-template.yaml
```

通过自助服务体验发布的 JSON 示例：

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Metadata": {
        "AWS::CloudFormation::Interface": {
            "ParameterGroups": [
                {
                    "Label": {
                        "default": "AWS Marketplace Parameters"
                    },
                    "Parameters": [
                        "ImageId",
                        "MPS3BucketName",
                        "MPS3BucketRegion",
                        "MPS3KeyPrefix"
                    ]
                }
            ]
        }
    },
    "Parameters": {
        "ImageId": {
            "Type": "AWS::EC2::Image::Id",
            "Default": "ami-example123456",
            "Description": "The AMI that will be used to launch EC2 resources."
        },
        "MPS3BucketName": {
            "Type": "String",
            "Default": "sellerbucket",
            "Description": "Name of the S3 bucket for your copy of the nested templates."
        },
        "MPS3BucketRegion": {
            "Type": "String",
            "Default": "us-east-1",
            "Description": "AWS Region where the S3 bucket for your copy of the nested templates is hosted."
        },
        "MPS3KeyPrefix": {
            "Type": "String",
            "Default": "sellerproductfolder/",
            "Description": "S3 key prefix that is used to simulate a folder for your copy of the nested templates."
        }
    },
    "Resources": {
        "EC2Instance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Ref": "ImageId"
                }
            }
        },
        "NestedStack": {
            "Type": "AWS::CloudFormation::Stack",
            "Properties": {
                "TemplateURL": {
                    "Fn::Sub": "https://${MPS3BucketName}.s3.${MPS3BucketRegion}.${AWS::URLSuffix}/${MPS3KeyPrefix}nested-template.yaml"
                }
            }
        }
    }
}
```