

终止支持通知：2026 年 10 月 7 日， AWS 将终止对的支持。 AWS Proton 2026 年 10 月 7 日之后，您将无法再访问 AWS Proton 控制台或 AWS Proton 资源。您部署的基础架构将保持不变。有关更多信息，请参阅《[AWS Proton 服务弃用和迁移指南》](https://docs.aws.amazon.com/proton/latest/userguide/proton-end-of-support.html)。

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

# 为创作模板和创建捆绑包 AWS Proton
<a name="ag-template-authoring"></a>

AWS Proton 根据基础设施即代码 (IaC) 文件为您配置资源。您可以在可重用的 IaC 文件中描述基础设施。要使文件可以在不同的环境和应用程序中重复使用，您可以将它们编写为*模板*，定义输入参数，并在 IaC 定义中使用这些参数。稍后创建配置资源（环境、服务实例或组件）时，会 AWS Proton 使用渲染引擎，该引擎将输入值与模板组合在一起，以创建随时可以置备的 IaC 文件。

管理员将大多数模板创作为*模板包*，然后将其上传并注册到 AWS Proton。本页的其余部分将讨论这些 AWS Proton 模板包。*直接定义的组件*是一个例外；开发人员创建这些组件并直接提供 IaC 模板文件。有关组件的更多信息，请参阅[AWS Proton 组件](ag-components.md)。

**Topics**
+ [模板捆绑包](#ag-template-bundles)
+ [AWS Proton 参数](parameters.md)
+ [AWS Proton 基础架构即代码文件](ag-infrastructure-tmp-files.md)
+ [架构文件](ag-schema.md)
+ [总结模板文件 AWS Proton](ag-wrap-up.md)
+ [模板捆绑包注意事项](template-considerations.md)

## 模板捆绑包
<a name="ag-template-bundles"></a>

作为管理员，您可以[创建和注册模板](template-create.md) AWS Proton。您可以使用这些模板创建环境和服务。创建服务时，会将服务实例置 AWS Proton 备并部署到选定的环境。有关更多信息，请参阅 [AWS Proton 适用于平台团队](Welcome.md#ag-admin)。

要在中创建和注册模板 AWS Proton，您需要上传一个模板包，其中包含 AWS Proton 需要置备的基础架构即代码 (IaC) 文件以及环境或服务。

*模板捆绑包* 包含以下内容：
+ [基础设施即代码 (IaC) 文件](ag-infrastructure-tmp-files.md)，其中包含列出 *IaC 文件*的[清单 YAML 文件](ag-wrap-up.md)。
+ IaC 文件输入参数定义的[架构 YAML 文件](ag-schema.md)。

 CloudFormation 环境模板包包含一个 IaC 文件。

 CloudFormation 服务模板包包含一个用于服务实例定义的 IaC 文件和另一个用于管道定义的可选 IaC 文件。

Terraform 环境和服务模板捆绑包可以分别包含多个 IaC 文件。

AWS Proton 需要输入参数架构文件。当你使用 AWS CloudFormation 创建 IaC 文件时，你可以使用 [Jinja](https://jinja.palletsprojects.com/en/2.11.x/) 语法来引用你的输入参数。 AWS Proton 提供了可用于引用 IaC 文件中的[参数的参数](parameters.md)命名空间。

下图显示了您可以为其创建*模板*的步骤示例 AWS Proton。

![\[描述如何为一组 AWS Proton 基础架构资源创建模板包的过程的示意图。\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/images/bundles.png)


 ![\[Red circle with the number 1 inside, typically used as a notification icon.\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/images/label-one.png) 指定[输入参数](parameters.md)。

 ![\[Number 2 icon in a pink circle.\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/images/label-two.png) 创建[架构文件](ag-schema.md)以定义您的输入参数。

 ![\[Pink square icon with a white exclamation mark inside a circle.\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/images/label-three.png) 创建引用您的输入参数的 [IaC 文件](ag-infrastructure-tmp-files.md)。您可以引用环境 IaC 文件*输出* 以作为服务 IaC 文件的*输入*。

 ![\[Number 4 in a red circle icon, commonly used to indicate a notification count.\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/images/label-four.png)[向注册模板版本](template-create.md) AWS Proton 并上传您的模板包。

# AWS Proton 参数
<a name="parameters"></a>

您可以在基础设施即代码 (IaC) 文件中定义和使用参数，以使其灵活且可重用。您可以通过引用参数*命名空间中的参数名称来读取 IaC 文件中的 AWS Proton 参数*值。 AWS Proton 将参数值注入其在资源配置期间生成的渲染的 IaC 文件中。要处理 AWS CloudFormation IaC 参数，请 AWS Proton 使用 [Jinj](https://jinja.palletsprojects.com/en/2.11.x/) a。要处理 Terraform iaC 参数，需要 AWS Proton 生成 Terraform 参数值文件，并依赖 HCL 内置的参数化功能。

使用[CodeBuild 资源调配](ag-works-prov-methods.md#ag-works-prov-methods-codebuild)， AWS Proton 生成您的代码可以导入的输入文件。该文件是 JSON 或 HCL 文件，具体取决于模板清单中的属性。有关更多信息，请参阅 [CodeBuild 配置参数详细信息和示例](parameters-codebuild.md)。

您可以引用环境、服务和组件 IaC 文件或预置代码中的参数，并具有以下要求：
+ 每个参数名称的长度不超过 100 个字符。
+ 参数命名空间和资源名称的总长度不超过资源名称的字符限制。

AWS Proton 如果超过这些配额，则配置将失败。

## 参数类型
<a name="param-name-types"></a>

在 AWS Proton iaC 文件中，以下参数类型可供您参考：

**输入参数**  
环境和服务实例可以使用与环境或服务模板关联的[架构文件](ag-schema.md)中定义的输入参数。您可以在资源的 IaC 文件中引用资源的输入参数。组件 IaC 文件可以引用组件附加到的服务实例的输入参数。  
AWS Proton 根据架构文件检查输入参数名称，并将它们与 IaC 文件中引用的参数进行匹配，以注入您在资源配置期间在规范文件中提供的输入值。

**输出参数**  
您可以在任何 IaC 文件中定义输出。例如，输出可以是模板预置的资源之一的名称、ID 或 ARN，也可以是传递模板输入之一的方式。您可以在其他资源的 IaC 文件中引用这些输出。  
在 CloudFormation IaC 文件中，在`Outputs:`模块中定义输出参数。在 Terraform IaC 文件中，使用 `output` 语句定义每个输出参数。

**资源参数**  
AWS Proton 自动创建 AWS Proton 资源参数。这些参数公开了 AWS Proton 资源对象的属性。一个资源参数示例是 `environment.name`。

## 在 IaC 文件中使用 AWS Proton 参数
<a name="param-name-spaces"></a>

要读取 IaC 文件中的参数值，请在参数命名空间中引用该 AWS Proton 参数的名称。对于 AWS CloudFormation IaC 文件，您可以使用 *Jinja* 语法，并用成对的大括号和引号将参数括起来。

下表显示了每种支持的模板语言的参考语法以及示例。


| 模板语言 | 语法 | 示例：名为“VPC”的环境输入 | 
| --- | --- | --- | 
|  CloudFormation  |  `"{{ parameter-name }}"`  |  `"{{ environment.inputs.VPC }}"`  | 
|  Terraform  |  `var.parameter-name`  |  `var.environment.inputs.VPC` [生成的 Terraform 变量定义](ag-infrastructure-tmp-files-terraform.md#compiled-tform)  | 

**注意**  
如果您在 IaC 文件中使用[CloudFormation 动态参数](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html)，则必须[对其进行转义](https://jinja.palletsprojects.com/en/2.11.x/templates/#escaping)以防止 Jinja 误解错误。有关更多信息，请参阅 [故障排除 AWS Proton](ag-troubleshooting.md)。

下表列出了所有 AWS Proton 资源参数的命名空间名称。每个模板文件类型可以使用参数命名空间的不同子集。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/parameters.html)

有关更多信息和示例，请参阅有关不同资源类型和模板语言的 IaC 模板文件中的参数的子主题。

**Topics**
+ [参数类型](#param-name-types)
+ [在 IaC 文件中使用 AWS Proton 参数](#param-name-spaces)
+ [环境 CloudFormation IaC 文件参数详细信息和示例](env-parameters.md)
+ [服务 CloudFormation IaC 文件参数详细信息和示例](svc-parameters.md)
+ [组件 CloudFormation IaC 文件参数详细信息和示例](comp-parameters.md)
+ [CloudFormation IaC 文件的参数过滤器](parameter-filters.md)
+ [CodeBuild 配置参数详细信息和示例](parameters-codebuild.md)
+ [Terraform 基础设施即代码 (IaC) 文件参数详细信息和示例](env-parameters-tform.md)

# 环境 CloudFormation IaC 文件参数详细信息和示例
<a name="env-parameters"></a>

您可以在环境基础设施即代码 (IaC) 文件中定义和引用参数。有关参数、参数类型、 AWS Proton 参数命名空间以及如何在 IaC 文件中使用参数的详细说明，请参阅[AWS Proton 参数](parameters.md)。

## 定义环境参数
<a name="env-parameters.define"></a>

您可以为环境 IaC 文件定义输入和输出参数。
+ **输入参数** - 在[架构文件](ag-schema.md)中定义环境输入参数。

  以下列表包括典型使用案例的环境输入参数示例。
  + VPC CIDR 值
  + 负载均衡器设置
  + 数据库设置
  + 运行状况检查超时

  作为管理员，您可以在[创建环境](ag-create-env.md)时提供输入参数的值：
  + 使用控制台填写基于架构的表单，该 AWS Proton 表单提供了。
  + 使用 CLI 提供包含这些值的规范。
+ **输出参数** - 在环境 IaC 文件中定义环境输出。然后，您可以在其他资源的 IaC 文件中引用这些输出。

## 读取环境 IaC 文件中的参数值
<a name="env-parameters.refer"></a>

您可以在环境 IaC 文件中读取与环境相关的参数。您可以引用 AWS Proton 参数命名空间中的参数名称以读取参数值。
+ **输入参数** - 引用 `environment.inputs.input-name` 以读取环境输入值。
+ **资源参数**-通过引用名称来读取 AWS Proton 资源参数，`environment.name`例如。

**注意**  
无法在环境 IaC 文件中使用其他资源的输出参数。

## 包含参数的示例环境和服务 IaC 文件
<a name="env-parameters.example"></a>

以下示例说明了环境 IaC 文件中的参数定义和引用。然后，该示例说明了如何在服务 IaC 文件中引用环境 IaC 文件中定义的环境输出参数。

**Example 环境 CloudFormation IaC 文件**  
在该示例中，请注意以下事项：  
+ `environment.inputs.` 命名空间引用环境输入参数。
+ Amazon S EC2 ystems Manager (SSM) 参数`StoreInputValue`连接了环境输入。
+ `MyEnvParameterValue` 输出公开与输出参数相同的输入参数串联。三个额外的输出参数也单独公开输入参数。
+ 6 个额外的输出参数公开环境预置的资源。

```
Resources:
  StoreInputValue:
    Type: AWS::SSM::Parameter
    Properties:
      Type: String
      Value: "{{ environment.inputs.my_sample_input }} {{ environment.inputs.my_other_sample_input}} {{ environment.inputs.another_optional_input }}"
              # input parameter references

# These output values are available to service infrastructure as code files as outputs, when given the 
# the 'environment.outputs' namespace, for example, service_instance.environment.outputs.ClusterName.
Outputs:
  MyEnvParameterValue:                                        # output definition
    Value: !GetAtt StoreInputValue.Value
  MySampleInputValue:                                         # output definition
    Value: "{{ environment.inputs.my_sample_input }}"         #   input parameter reference
  MyOtherSampleInputValue:                                    # output definition
    Value: "{{ environment.inputs.my_other_sample_input }}"   #   input parameter reference
  AnotherOptionalInputValue:                                  # output definition
    Value: "{{ environment.inputs.another_optional_input }}"  #   input parameter reference
  ClusterName:                                                # output definition
    Description: The name of the ECS cluster
    Value: !Ref 'ECSCluster'                                  #   provisioned resource
  ECSTaskExecutionRole:                                       # output definition
    Description: The ARN of the ECS role
    Value: !GetAtt 'ECSTaskExecutionRole.Arn'                 #   provisioned resource
  VpcId:                                                      # output definition
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'                                         #   provisioned resource
  PublicSubnetOne:                                            # output definition
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'                             #   provisioned resource
  PublicSubnetTwo:                                            # output definition
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'                             #   provisioned resource
  ContainerSecurityGroup:                                     # output definition
    Description: A security group used to allow Fargate containers to receive traffic
    Value: !Ref 'ContainerSecurityGroup'                      #   provisioned resource
```

**Example 服务 CloudFormation IaC 文件**  
`environment.outputs.` 命名空间引用环境 IaC 文件的环境输出。例如，名称 `environment.outputs.ClusterName` 读取 `ClusterName` 环境输出参数的值。  

```
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service on AWS Fargate, hosted in a public subnet, and accessible via a public load balancer.
Mappings:
  TaskSize:
    x-small:
      cpu: 256
      memory: 512
    small:
      cpu: 512
      memory: 1024
    medium:
      cpu: 1024
      memory: 2048
    large:
      cpu: 2048
      memory: 4096
    x-large:
      cpu: 4096
      memory: 8192
Resources:
  # A log group for storing the stdout logs from this service's containers
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: '{{service_instance.name}}' # resource parameter

  # The task definition. This is a simple metadata description of what
  # container to run, and what resource requirements it has.
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: '{{service_instance.name}}' # resource parameter
      Cpu: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, cpu] # input parameter
      Memory: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, memory] 
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: '{{environment.outputs.ECSTaskExecutionRole}}'  # output reference to an environment infrastructure code file
      TaskRoleArn: !Ref "AWS::NoValue"
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'  # resource parameter
          Cpu: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, cpu]
          Memory: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, memory]
          Image: '{{service_instance.inputs.image}}'
          PortMappings:
            - ContainerPort: '{{service_instance.inputs.port}}' # input parameter
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group: '{{service_instance.name}}' # resource parameter
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: '{{service_instance.name}}' # resource parameter

  # The service_instance. The service is a resource which allows you to run multiple
  # copies of a type of task, and gather up their logs and metrics, as well
  # as monitor the number of running tasks and replace any that have crashed
  Service:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerRule
    Properties:
      ServiceName: '{{service_instance.name}}'  # resource parameter
      Cluster: '{{environment.outputs.ClusterName}}' # output reference to an environment infrastructure as code file
      LaunchType: FARGATE
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 75
      DesiredCount: '{{service_instance.inputs.desired_count}}'# input parameter
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - '{{environment.outputs.ContainerSecurityGroup}}' # output reference to an environment infrastructure as code file
          Subnets:
            - '{{environment.outputs.PublicSubnetOne}}' # output reference to an environment infrastructure as code file
            - '{{environment.outputs.PublicSubnetTwo}}' # output reference to an environment infrastructure as code file
      TaskDefinition: !Ref 'TaskDefinition'
      LoadBalancers:
        - ContainerName: '{{service_instance.name}}'  # resource parameter
          ContainerPort: '{{service_instance.inputs.port}}' # input parameter
          TargetGroupArn: !Ref 'TargetGroup'
[...]
```

# 服务 CloudFormation IaC 文件参数详细信息和示例
<a name="svc-parameters"></a>

您可以在服务和管道基础设施即代码 (IaC) 文件中定义和引用参数。有关 AWS Proton 参数、参数类型、参数命名空间以及如何在 IaC 文件中使用参数的详细说明，请参阅[AWS Proton 参数](parameters.md)。

## 定义服务参数
<a name="svc-parameters.define"></a>

您可以为服务 IaC 文件定义输入和输出参数。
+ **输入参数** - 在[架构文件](ag-schema.md)中定义服务输入参数。

  以下列表包括典型使用案例的服务输入参数示例。
  + 端口
  + 任务大小
  + 图像
  + 预期数量
  + Docker 文件
  + 单元测试命令

  您可以在[创建服务](ag-create-svc.md)时提供输入参数的值：
  + 使用控制台填写基于架构的表单，该 AWS Proton 表单提供了。
  + 使用 CLI 提供包含这些值的规范。
+ **输出参数** - 在服务 IaC 文件中定义服务实例输出。然后，您可以在其他资源的 IaC 文件中引用这些输出。

## 读取服务 IaC 文件中的参数值
<a name="svc-parameters.refer"></a>

您可以在服务 IaC 文件中读取与服务和其他资源相关的参数。您可以通过在参数命名空间中引用参数的名称来读取 AWS Proton 参数值。
+ **输入参数** - 引用 `service_instance.inputs.input-name` 以读取服务实例输入值。
+ **资源参数**-通过引用`service.name`、`service_instance.name`和`environment.name`等名称来读取 AWS Proton 资源参数。
+ **输出参数** - 引用 `environment.outputs.output-name` 或 `service_instance.components.default.outputs.output-name` 以读取其他资源的输出。

## 包含参数的示例服务 IaC 文件
<a name="svc-parameters.example"></a>

以下示例是服务 CloudFormation IaC 文件中的一段片段。`environment.outputs.` 命名空间引用环境 IaC 文件的输出。`service_instance.inputs.` 命名空间引用服务实例输入参数。该`service_instance.name`属性指的是 AWS Proton 资源参数。

```
Resources:
  StoreServiceInstanceInputValue:
    Type: AWS::SSM::Parameter
    Properties:
      Type: String
      Value: "{{ service.name }} {{ service_instance.name }} {{ service_instance.inputs.my_sample_service_instance_required_input }} {{ service_instance.inputs.my_sample_service_instance_optional_input }} {{ environment.outputs.MySampleInputValue }} {{ environment.outputs.MyOtherSampleInputValue }}"
              #  resource parameter references               # input parameter references                                                                                                                    # output references to an environment infrastructure as code file
Outputs:
  MyServiceInstanceParameter:                                                         # output definition
    Value: !Ref StoreServiceInstanceInputValue 
  MyServiceInstanceRequiredInputValue:                                                # output definition
    Value: "{{ service_instance.inputs.my_sample_service_instance_required_input }}"  # input parameter reference
  MyServiceInstanceOptionalInputValue:                                                # output definition
    Value: "{{ service_instance.inputs.my_sample_service_instance_optional_input }}"  # input parameter reference
  MyServiceInstancesEnvironmentSampleOutputValue:                                     # output definition
    Value: "{{ environment.outputs.MySampleInputValue }}"                             # output reference to an environment IaC file
  MyServiceInstancesEnvironmentOtherSampleOutputValue:                                # output definition
    Value: "{{ environment.outputs.MyOtherSampleInputValue }}"                        # output reference to an environment IaC file
```

# 组件 CloudFormation IaC 文件参数详细信息和示例
<a name="comp-parameters"></a>

您可以在组件基础设施即代码 (IaC) 文件中定义和引用参数。有关参数、参数类型、 AWS Proton 参数命名空间以及如何在 IaC 文件中使用参数的详细说明，请参阅[AWS Proton 参数](parameters.md)。有关组件的更多信息，请参阅[AWS Proton 组件](ag-components.md)。

## 定义组件输出参数
<a name="comp-parameters.define"></a>

您可以在组件 IaC 文件中定义输出参数。然后，您可以在服务 IaC 文件中引用这些输出。

**注意**  
您无法为组件 IaC 文件定义输入。附加的组件可以从它们附加到的服务实例中获取输入。分离的组件没有输入。

## 读取组件 IaC 文件中的参数值
<a name="comp-parameters.refer"></a>

您可以在组件 IaC 文件中读取与组件和其他资源相关的参数。您可以通过在参数命名空间中引用参数的名称来读取 AWS Proton 参数值。
+ **输入参数** - 引用 `service_instance.inputs.input-name` 以读取附加的服务实例输入值。
+ **资源参数**-通过引用`component.name`、`service.name``service_instance.name`、和`environment.name`等名称来读取 AWS Proton 资源参数。
+ **输出参数** - 引用 `environment.outputs.output-name` 以读取环境输出。

## 包含参数的示例组件和服务 IaC 文件
<a name="comp-parameters.example"></a>

以下示例显示了一个组件，该组件预置了亚马逊简单存储服务 (Amazon S3) 存储桶和相关访问策略，并将这两个资源的亚马逊资源ARNs名称 () 作为组件输出公开。服务 IaC 模板将组件输出添加为 Amazon Elastic Container Service (Amazon ECS) 任务的容器环境变量以使输出可供容器中运行的代码使用，并将存储桶访问策略添加到任务的角色中。存储桶名称基于环境、服务、服务实例和组件的名称，这意味着存储桶与扩展特定服务实例的特定组件模板实例结合使用。开发人员可以根据该组件模板创建多个自定义组件，以针对不同的服务实例和功能需求预置 Amazon S3 存储桶。

该示例说明了如何使用 Jinja `{{ ... }}` 语法引用服务 IaC 文件中的组件和其他资源参数。只有在组件附加到服务实例时，您才能使用 `{% if ... %}` 语句添加语句块。`proton_cfn_*` 关键字是可用于清理输出参数值和设置参数值格式的*筛选条件*。有关筛选条件的更多信息，请参阅[CloudFormation IaC 文件的参数过滤器](parameter-filters.md)。

 作为管理员，您编写服务 IaC 模板文件。

**Example 使用组件的服务 CloudFormation IaC 文件**  

```
# service/instance_infrastructure/cloudformation.yaml

Resources: 
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'
          # ...
          {% if service_instance.components.default.outputs | length > 0 %}
          Environment:
            {{ service_instance.components.default.outputs |
                proton_cfn_ecs_task_definition_formatted_env_vars }}
          {% endif %}

  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        {{ service_instance.components.default.outputs
            | proton_cfn_iam_policy_arns }}

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

作为开发人员，您编写组件 IaC 模板文件。

**Example 组件 CloudFormation iaC 文件**  

```
# cloudformation.yaml

# A component that defines an S3 bucket and a policy for accessing the bucket.
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: '{{environment.name}}-{{service.name}}-{{service_instance.name}}-{{component.name}}'
  S3BucketAccessPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
          - Effect: Allow
            Action:
              - 's3:Get*'
              - 's3:List*'
              - 's3:PutObject'
            Resource: !GetAtt S3Bucket.Arn
Outputs:
  BucketName:
    Description: "Bucket to access"
    Value: !GetAtt S3Bucket.Arn
  BucketAccessPolicyArn:
    Value: !Ref S3BucketAccessPolicy
```

为服务实例 AWS Proton 渲染 CloudFormation 模板并将所有参数替换为实际值时，模板可能如下所示。

**Example 服务实例 CloudFormation 呈现的 iaC 文件**  

```
Resources: 
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'
          # ...
          Environment:
            - Name: BucketName
              Value: arn:aws:s3:us-east-1:123456789012:environment_name-service_name-service_instance_name-component_name
            - Name: BucketAccessPolicyArn
              Value: arn:aws:iam::123456789012:policy/cfn-generated-policy-name
  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        - arn:aws:iam::123456789012:policy/cfn-generated-policy-name

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

# CloudFormation IaC 文件的参数过滤器
<a name="parameter-filters"></a>

当您引用 AWS CloudFormation IaC 文件中的[AWS Proton 参数](parameters.md)时，您可以使用称为*过滤器的 Jinja 修饰符来验证、筛选*和格式化参数值，然后再将其插入到渲染的模板中。在引用[组件](ag-components.md)输出参数时，筛选条件验证是特别有用的，因为组件创建和附加是由开发人员完成的，并且在服务实例模板中使用组件输出的管理员可能希望验证它们是否存在和有效。不过，您可以在任何 Jinja IaC 文件中使用筛选条件。

以下各节描述和定义了可用的参数筛选器，并提供了示例。 AWS Proton 定义了其中的大多数过滤器。`default` 筛选条件是 Jinja 内置筛选条件。

## 为 Amazon ECS 任务设置环境属性格式
<a name="parameter-filters.proton.cfn-ecs"></a>

**声明**

```
dict → proton_cfn_ecs_task_definition_formatted_env_vars (raw: boolean = True) → YAML list of dicts
```

**说明**

该筛选条件为 Amazon Elastic Container Service (Amazon ECS) 任务定义 `ContainerDefinition` 部分的 [Environment 属性](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html#cfn-ecs-taskdefinition-containerdefinition-environment)中使用的输出列表设置格式。

还可以将 `raw` 设置为 `False` 以验证参数值。在这种情况下，该值需要与正则表达式 `^[a-zA-Z0-9_-]*$` 匹配。如果该值未通过验证，模板渲染将失败。

### 示例
<a name="parameter-filters.proton.cfn-ecs.example"></a>

如果使用以下自定义组件模板：

```
Resources:
  # ...
Outputs:
  Output1:
    Description: "Example component output 1"
    Value: hello
  Output2:
    Description: "Example component output 2"
    Value: world
```

以及以下服务模板：

```
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      # ...
      ContainerDefinitions:
        - Name: MyServiceName
          # ...
          Environment:
            {{ service_instance.components.default.outputs
              | proton_cfn_ecs_task_definition_formatted_env_vars }}
```

渲染的服务模板如下所示：

```
Resources:
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      # ...
      ContainerDefinitions:
        - Name: MyServiceName
          # ...
          Environment:
            - Name: Output1
              Value: hello
            - Name: Output2
              Value: world
```

## 设置 Lambda 函数的环境属性格式
<a name="parameter-filters.proton.cfn-lambda"></a>

**声明**

```
dict → proton_cfn_lambda_function_formatted_env_vars (raw: boolean = True) → YAML dict
```

**说明**

此过滤器格式化了要在 AWS Lambda 函数定义`Properties`部分的 En [vironment 属性](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-environment)中使用的输出列表。

还可以将 `raw` 设置为 `False` 以验证参数值。在这种情况下，该值需要与正则表达式 `^[a-zA-Z0-9_-]*$` 匹配。如果该值未通过验证，模板渲染将失败。

### 示例
<a name="parameter-filters.proton.cfn-lambda.example"></a>

如果使用以下自定义组件模板：

```
Resources:
  # ...
Outputs:
  Output1:
    Description: "Example component output 1"
    Value: hello
  Output2:
    Description: "Example component output 2"
    Value: world
```

以及以下服务模板：

```
Resources:
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          {{ service_instance.components.default.outputs
            | proton_cfn_lambda_function_formatted_env_vars }}
```

渲染的服务模板如下所示：

```
Resources:
  Lambda:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          Output1: hello
          Output2: world
```

## 提取 IAM 策略 ARNs 以包含在 IAM 角色中
<a name="parameter-filters.proton.cfn-policy-arns"></a>

**声明**

```
dict → proton_cfn_iam_policy_arns → YAML list
```

**说明**

此筛选器格式化了要在 AWS Identity and Access Management (IAM) 角色定义`Properties`部分的[ManagedPolicyArns 属性](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html#cfn-iam-role-managepolicyarns)中使用的输出列表。筛选器使用正则表达式`^arn:[a-zA-Z-]+:iam::\d{12}:policy/` ARNs 从输出参数列表中提取有效的 IAM 策略。您可以使用该筛选条件，将输出参数值中的策略附加到服务模板中的 IAM 角色定义。

### 示例
<a name="parameter-filters.proton.cfn-policy-arns.example"></a>

如果使用以下自定义组件模板：

```
Resources:
  # ...
  ExamplePolicy1:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
  ExamplePolicy2:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...

  # ...

Outputs:
  Output1:
    Description: "Example component output 1"
    Value: hello
  Output2:
    Description: "Example component output 2"
    Value: world
  PolicyArn1:
    Description: "ARN of policy 1"
    Value: !Ref ExamplePolicy1
  PolicyArn2:
    Description: "ARN of policy 2"
    Value: !Ref ExamplePolicy2
```

以及以下服务模板：

```
Resources: 

  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        {{ service_instance.components.default.outputs
            | proton_cfn_iam_policy_arns }}

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

渲染的服务模板如下所示：

```
Resources: 

  # ...

  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      # ...
      ManagedPolicyArns:
        - !Ref BaseTaskRoleManagedPolicy
        - arn:aws:iam::123456789012:policy/cfn-generated-policy-name-1
        - arn:aws:iam::123456789012:policy/cfn-generated-policy-name-2

  # Basic permissions for the task
  BaseTaskRoleManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      # ...
```

## 清理属性值
<a name="parameter-filters.proton.cfn-sanitize"></a>

**声明**

```
string → proton_cfn_sanitize → string
```

**说明**

这是一个通用的筛选条件。可以使用该筛选条件验证参数值的安全性。该筛选条件验证值是否与正则表达式 `^[a-zA-Z0-9_-]*$` 匹配或者是有效的 Amazon 资源名称 (ARN)。如果该值未通过验证，模板渲染将失败。

### 示例
<a name="parameter-filters.proton.cfn-sanitize.example"></a>

如果使用以下自定义组件模板：

```
Resources:
  # ...
Outputs:
  Output1:
    Description: "Example of valid output"
    Value: "This-is_valid_37"
  Output2:
    Description: "Example incorrect output"
    Value: "this::is::incorrect"
  SomeArn:
    Description: "Example ARN"
    Value: arn:aws:some-service::123456789012:some-resource/resource-name
```
+ 服务模板中的以下引用：

  ```
  # ...
    {{ service_instance.components.default.outputs.Output1
      | proton_cfn_sanitize }}
  ```

  渲染如下所示：

  ```
  # ...
    This-is_valid_37
  ```
+ 服务模板中的以下引用：

  ```
  # ...
    {{ service_instance.components.default.outputs.Output2
      | proton_cfn_sanitize }}
  ```

  包含以下渲染错误的结果：

  ```
  Illegal character(s) detected in "this::is::incorrect". Must match regex ^[a-zA-Z0-9_-]*$ or be a valid ARN
  ```
+ 服务模板中的以下引用：

  ```
  # ...
    {{ service_instance.components.default.outputs.SomeArn
      | proton_cfn_sanitize }}
  ```

  渲染如下所示：

  ```
  # ...
    arn:aws:some-service::123456789012:some-resource/resource-name
  ```

## 为不存在的引用提供默认值
<a name="parameter-filters.proton.default"></a>

**说明**

在命名空间引用不存在时，`default` 筛选条件提供默认值。可以使用它编写强大的模板，即使您引用的参数丢失，也可以成功进行渲染。

### 示例
<a name="parameter-filters.default.example"></a>

如果服务实例没有附加直接定义的（默认）组件，或者附加的组件没有名为 `test` 的输出，服务模板中的以下引用将导致模板渲染失败。

```
# ...
  {{ service_instance.components.default.outputs.test }}
```

要避免该问题，请添加 `default` 筛选条件。

```
# ...
  {{ service_instance.components.default.outputs.test | default("[optional-value]") }}
```

# CodeBuild 配置参数详细信息和示例
<a name="parameters-codebuild"></a>

您可以在模板中为 CodeBuild基于 AWS Proton 资源的定义参数，并在配置代码中引用这些参数。有关参数、参数类型、 AWS Proton 参数命名空间以及如何在 IaC 文件中使用参数的详细说明，请参阅[AWS Proton 参数](parameters.md)。

**注意**  
您可以对环境和服务使用 CodeBuild 置备。目前，您无法通过这种方法预置组件。

## 输入参数
<a name="parameters-codebuild.input"></a>

创建 AWS Proton 资源（如环境或服务）时，需要为模板[架构文件](ag-schema.md)中定义的输入参数提供值。当您创建的资源使用时[CodeBuild 资源调配](ag-works-prov-methods.md#ag-works-prov-methods-codebuild)，会将这些输入值 AWS Proton 呈现到输入文件中。您的预置代码可以从该文件中导入和获取参数值。

有关 CodeBuild 模板的示例，请参见[CodeBuild 配置模板包](ag-infrastructure-tmp-files-codebuild.md)。有关清单文件的更多信息，请参阅[总结模板文件 AWS Proton](ag-wrap-up.md)。

以下示例是在 CodeBuild基于服务实例的配置期间生成的 JSON 输入文件。

### 示例：使用 AWS CDK 带 CodeBuild 配置的
<a name="parameters-codebuild.example"></a>

```
{
  "service_instance": {
    "name": "my-service-staging",
    "inputs": {
      "port": "8080",
      "task_size": "medium"
    }
  },
  "service": {
    "name": "my-service"
  },
  "environment": {
    "account_id": "123456789012",
    "name": "my-env-staging",
    "outputs": {
      "vpc-id": "hdh2323423"
    }
  }
}
```

## 输出参数
<a name="parameters-codebuild.output"></a>

要将资源配置输出传回给 AWS Proton，您的配置代码可以生成一个名为的 JSON 文件，该文件名`proton-outputs.json`为模板[架构文件](ag-schema.md)中定义的输出参数的值。例如，该`cdk deploy`命令的`--outputs-file`参数指示生成包含配置输出的 AWS CDK JSON 文件。如果您的资源使用 AWS CDK，请在 CodeBuild 模板清单中指定以下命令：

```
aws proton notify-resource-deployment-status-change
```

AWS Proton 正在寻找这个 JSON 文件。如果配置代码成功完成后文件存在，则从中 AWS Proton 读取输出参数值。

# Terraform 基础设施即代码 (IaC) 文件参数详细信息和示例
<a name="env-parameters-tform"></a>

您可以将 Terraform 输入变量包含在模板捆绑包的 `variable.tf` 文件中。您也可以创建架构来创建 AWS Proton 托管变量。 AWS Proton `.tf files`从您的架构文件中创建变量。有关更多信息，请参阅 [Terraform IaC 文件](ag-infrastructure-tmp-files-terraform.md)。

要在基础架构中引用架构定义的 AWS Proton 变量`.tf files`，请使用 Terrafor AWS Proton m iaC 的*参数和命名空间表中显示的命名空间*。例如，您可以使用 `var.environment.inputs.vpc_cidr`。在引号内，用单大括号将这些变量括起来，并在第一个大括号前面添加一个美元符号（例如 `“${var.environment.inputs.vpc_cidr}”`）。

以下示例说明如何使用命名空间在环境中包含 AWS Proton 参数。`.tf file`

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  // This tells terraform to store the state file in s3 at the location
  // s3://terraform-state-bucket/tf-os-sample/terraform.tfstate
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "tf-os-sample/terraform.tfstate"
    region = "us-east-1"
  }
}

// Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = var.proton_tags
  }
}

resource "aws_ssm_parameter" "my_ssm_parameter" {
  name  = "my_ssm_parameter"
  type  = "String"
  // Use the Proton environment.inputs. namespace
  value = var.environment.inputs.ssm_parameter_value
}
```

# AWS Proton 基础架构即代码文件
<a name="ag-infrastructure-tmp-files"></a>

模板包的主要部分是*基础设施即代码 (IaC) 文件*，用于定义要置备的基础架构资源和属性。 AWS CloudFormation 以及其他基础设施即代码引擎使用这些类型的文件来配置基础架构资源。

**注意**  
也可以独立于模板捆绑包使用 IaC 文件，以作为*直接定义的组件* 的直接输入。有关组件的更多信息，请参阅[AWS Proton 组件](ag-components.md)。

AWS Proton 目前支持两种类型的 IaC 文件：
+ *[CloudFormation](ag-infrastructure-tmp-files-cloudformation.md)文件*-用于*AWS托管配置*。 AWS Proton 在 CloudFormation 模板文件格式之上使用 Jinja 进行参数化。
+ *[Terraform HCL](ag-infrastructure-tmp-files-terraform.md) 文件* - 用于*自托管式预置*。HCL 本身支持参数化。

您不能使用多种配置方法来配置 AWS Proton 资源。您必须使用其中的一种方法。您无法将 AWS托管配置服务部署到自我管理的配置环境，反之亦然。

有关更多信息，请参阅[如何配置 AWS Proton 基础架构](ag-works-prov-methods.md)、[AWS Proton 环境](ag-environments.md)、[AWS Proton 服务](ag-services.md)和[AWS Proton 组件](ag-components.md)。

# CloudFormation IaC 文件
<a name="ag-infrastructure-tmp-files-cloudformation"></a>

通过学习如何使用 AWS CloudFormation 基础架构作为代码文件 AWS Proton。 CloudFormation 是一项基础设施即代码 (IaC) 服务，可帮助您对 AWS 资源进行建模和设置。您可以在模板中定义基础架构资源，在 CloudFormation 模板文件格式之上使用 Jinja 进行参数化。 AWS Proton 展开参数并呈现完整 CloudFormation 模板。 CloudFormation 将定义的资源配置为 CloudFormation 堆栈。有关更多信息，请参阅《 CloudFormation 用户指南》中的[什么是 CloudFormation？](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html)**

AWS Proton 支持 [AWS CloudFormation IaC 的托管配置](ag-works-prov-methods.md#ag-works-prov-methods-direct)。

## 从您自己的现有基础设施即代码文件开始
<a name="iac-tmp-files"></a>

您可以调整*自己现有的基础设施即*代码 (IaC) 文件以供使用 AWS Proton。

以下 CloudFormation 示例（示[例 1](#ag-env-cfn-example) 和示[例 2](#ag-svc-cfn-example)）代表*您自己的现有* CloudFormation IaC 文件。 CloudFormation 可以使用这些文件来创建两个不同的 CloudFormation堆栈。

在[示例 1](#ag-env-cfn-example) 中，将 CloudFormation IaC 文件配置为配置基础架构，以便在容器应用程序之间共享。在该示例中，添加了输入参数，以便使用相同的 IaC 文件创建多组预置的基础设施。每个集合可以具有不同的名称以及不同的 VPC 和子网 CIDR 值集。作为管理员或开发人员，在使用 IaC 文件配置基础设施资源时，您需要为这些参数提供值。 CloudFormation为了方便起见，这些输入参数标有注释，并在该示例中多次引用。*输出*是在模板末尾定义的。它们可以在其他 CloudFormation IaC 文件中引用。

在[示例 2](#ag-svc-cfn-example) 中，将 CloudFormation IaC 文件配置为将应用程序部署到*示例* 1 中配置的基础架构。为了方便起见，对这些参数进行了注释。

### 示例 1： CloudFormation IaC 文件
<a name="ag-env-cfn-example"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS Fargate cluster running containers in a public subnet. Only supports
             public facing load balancer, and public service discovery namespaces.
Parameters:
   VpcCIDR:       # input parameter
        Description: CIDR for VPC
        Type: String
        Default: "10.0.0.0/16"
   SubnetOneCIDR: # input parameter
        Description: CIDR for SubnetOne
        Type: String
        Default: "10.0.0.0/24"
   SubnetTwoCIDR: # input parameters
        Description: CIDR for SubnetTwo
        Type: String
        Default: "10.0.1.0/24"
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: 
        Ref: 'VpcCIDR'

  # Two public subnets, where containers will have public IP addresses
  PublicSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock:
         Ref: 'SubnetOneCIDR'
      MapPublicIpOnLaunch: true

  PublicSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock:
        Ref: 'SubnetTwoCIDR'
      MapPublicIpOnLaunch: true

  # Setup networking resources for the public subnets. Containers
  # in the public subnets have public IP addresses and the routing table
  # sends network traffic via the internet gateway.
  InternetGateway:
    Type: AWS::EC2::InternetGateway
  GatewayAttachement:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref 'VPC'
      InternetGatewayId: !Ref 'InternetGateway'
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'VPC'
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachement
    Properties:
      RouteTableId: !Ref 'PublicRouteTable'
      DestinationCidrBlock: '0.0.0.0/0'
      GatewayId: !Ref 'InternetGateway'
  PublicSubnetOneRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetOne
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetTwoRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetTwo
      RouteTableId: !Ref PublicRouteTable

  # ECS Resources
  ECSCluster:
    Type: AWS::ECS::Cluster

  # A security group for the containers we will run in Fargate.
  # Rules are added to this security group based on what ingress you
  # add for the cluster.
  ContainerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the Fargate containers
      VpcId: !Ref 'VPC'

  # This is a role which is used by the ECS tasks themselves.
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [ecs-tasks.amazonaws.com]
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'

# These output values will be available to other templates to use.
Outputs:
  ClusterName:                                               # output
    Description: The name of the ECS cluster
    Value: !Ref 'ECSCluster'
    Export:
      Name:
        Fn::Sub: "${AWS::StackName}-ECSCluster"
  ECSTaskExecutionRole:                                       # output
    Description: The ARN of the ECS role
    Value: !GetAtt 'ECSTaskExecutionRole.Arn'
    Export: 
      Name:
        Fn::Sub: "${AWS::StackName}-ECSTaskExecutionRole"
  VpcId:                                                      # output
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'
    Export: 
      Name: 
        Fn::Sub: "${AWS::StackName}-VPC"
  PublicSubnetOne:                                            # output
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'
    Export: 
      Name:
        Fn::Sub: "${AWS::StackName}-PublicSubnetOne"
  PublicSubnetTwo:                                            # output
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'
    Export: 
      Name:
        Fn::Sub: "${AWS::StackName}-PublicSubnetTwo"
  ContainerSecurityGroup:                                     # output
    Description: A security group used to allow Fargate containers to receive traffic
    Value: !Ref 'ContainerSecurityGroup'
    Export: 
      Name:
        Fn::Sub: "${AWS::StackName}-ContainerSecurityGroup"
```

### 示例 2： CloudFormation IaC 文件
<a name="ag-svc-cfn-example"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service on AWS Fargate, hosted in a public subnet, and accessible via a public load balancer.
Parameters:
    ContainerPortInput:  # input parameter
        Description: The port to route traffic to
        Type: Number
        Default: 80
    TaskCountInput:      # input parameter
        Description: The default number of Fargate tasks you want running
        Type: Number
        Default: 1
    TaskSizeInput:       # input parameter
        Description: The size of the task you want to run
        Type: String
        Default: x-small
    ContainerImageInput: # input parameter
        Description: The name/url of the container image
        Type: String
        Default: "public.ecr.aws/z9d2n7e1/nginx:1.19.5"
    TaskNameInput:       # input parameter
        Description: Name for your task
        Type: String
        Default: "my-fargate-instance"
    StackName:           # input parameter
        Description: Name of the environment stack to deploy to
        Type: String
        Default: "my-fargate-environment"
Mappings:
  TaskSizeMap:
    x-small:
      cpu: 256
      memory: 512
    small:
      cpu: 512
      memory: 1024
    medium:
      cpu: 1024
      memory: 2048
    large:
      cpu: 2048
      memory: 4096
    x-large:
      cpu: 4096
      memory: 8192
Resources:
  # A log group for storing the stdout logs from this service's containers
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName:
        Ref: 'TaskNameInput' # input parameter

  # The task definition. This is a simple metadata description of what
  # container to run, and what resource requirements it has.
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Ref 'TaskNameInput'
      Cpu: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', cpu]
      Memory: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', memory]
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn:
        Fn::ImportValue:
          !Sub "${StackName}-ECSTaskExecutionRole"    # output parameter from another CloudFormation template
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: !Ref 'TaskNameInput'
                

  # The service_instance. The service is a resource which allows you to run multiple
  # copies of a type of task, and gather up their logs and metrics, as well
  # as monitor the number of running tasks and replace any that have crashed
  Service:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerRule
    Properties:
      ServiceName: !Ref 'TaskNameInput'
      Cluster:
        Fn::ImportValue:
          !Sub "${StackName}-ECSCluster"  # output parameter from another CloudFormation template
      LaunchType: FARGATE
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 75
      DesiredCount: !Ref 'TaskCountInput'
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - Fn::ImportValue:
                !Sub "${StackName}-ContainerSecurityGroup"    # output parameter from another CloudFormation template
          Subnets:
            - Fn::ImportValue:r CloudFormation template
      TaskRoleArn: !Ref "AWS::NoValue"
      ContainerDefinitions:        
        - Name: !Ref 'TaskNameInput'
          Cpu: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', cpu]
          Memory: !FindInMap [TaskSizeMap, !Ref 'TaskSizeInput', memory]
          Image: !Ref 'ContainerImageInput'             # input parameter
          PortMappings:
            - ContainerPort: !Ref 'ContainerPortInput'  # input parameter
          
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group: !Ref 'TaskNameInput'
                !Sub "${StackName}-PublicSubnetOne"    # output parameter from another CloudFormation template
            - Fn::ImportValue:
                !Sub "${StackName}-PublicSubnetTwo"    # output parameter from another CloudFormation template
      TaskDefinition: !Ref 'TaskDefinition'
      LoadBalancers:
        - ContainerName: !Ref 'TaskNameInput'
          ContainerPort: !Ref 'ContainerPortInput'  # input parameter
          TargetGroupArn: !Ref 'TargetGroup'

  # A target group. This is used for keeping track of all the tasks, and
  # what IP addresses / port numbers they have. You can query it yourself,
  # to use the addresses yourself, but most often this target group is just
  # connected to an application load balancer, or network load balancer, so
  # it can automatically distribute traffic across all the targets.
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 6
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      TargetType: ip
      Name: !Ref 'TaskNameInput'
      Port: !Ref 'ContainerPortInput'
      Protocol: HTTP
      UnhealthyThresholdCount: 2
      VpcId:
        Fn::ImportValue:
          !Sub "${StackName}-VPC"    # output parameter from another CloudFormation template

  # Create a rule on the load balancer for routing traffic to the target group
  LoadBalancerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref 'TargetGroup'
          Type: 'forward'
      Conditions:
        - Field: path-pattern
          Values:
            - '*'
      ListenerArn: !Ref PublicLoadBalancerListener
      Priority: 1

  # Enable autoscaling for this service
  ScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    DependsOn: Service
    Properties:
      ServiceNamespace: 'ecs'
      ScalableDimension: 'ecs:service:DesiredCount'
      ResourceId:
        Fn::Join:
          - '/'
          - - service
            - Fn::ImportValue:
                !Sub "${StackName}-ECSCluster"
            - !Ref 'TaskNameInput'
      MinCapacity: 1
      MaxCapacity: 10
      RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService

  # Create scaling policies for the service
  ScaleDownPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    DependsOn: ScalableTarget
    Properties:
      PolicyName:
        Fn::Join:
          - '/'
          - - scale
            - !Ref 'TaskNameInput'
            - down
      PolicyType: StepScaling
      ResourceId:
        Fn::Join:
          - '/'
          - - service
            - Fn::ImportValue:
                !Sub "${StackName}-ECSCluster"  # output parameter from another CloudFormation template
            - !Ref 'TaskNameInput'
      ScalableDimension: 'ecs:service:DesiredCount'
      ServiceNamespace: 'ecs'
      StepScalingPolicyConfiguration:
        AdjustmentType: 'ChangeInCapacity'
        StepAdjustments:
          - MetricIntervalUpperBound: 0
            ScalingAdjustment: -1
        MetricAggregationType: 'Average'
        Cooldown: 60

  ScaleUpPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    DependsOn: ScalableTarget
    Properties:
      PolicyName:
        Fn::Join:
          - '/'
          - - scale
            - !Ref 'TaskNameInput'
            - up
      PolicyType: StepScaling
      ResourceId:
        Fn::Join:
          - '/'
          - - service
            - Fn::ImportValue:
                !Sub "${StackName}-ECSCluster"
            - !Ref 'TaskNameInput'
      ScalableDimension: 'ecs:service:DesiredCount'
      ServiceNamespace: 'ecs'
      StepScalingPolicyConfiguration:
        AdjustmentType: 'ChangeInCapacity'
        StepAdjustments:
          - MetricIntervalLowerBound: 0
            MetricIntervalUpperBound: 15
            ScalingAdjustment: 1
          - MetricIntervalLowerBound: 15
            MetricIntervalUpperBound: 25
            ScalingAdjustment: 2
          - MetricIntervalLowerBound: 25
            ScalingAdjustment: 3
        MetricAggregationType: 'Average'
        Cooldown: 60

  # Create alarms to trigger these policies
  LowCpuUsageAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName:
        Fn::Join:
          - '-'
          - - low-cpu
            - !Ref 'TaskNameInput'
      AlarmDescription:
        Fn::Join:
          - ' '
          - - "Low CPU utilization for service"
            - !Ref 'TaskNameInput'
      MetricName: CPUUtilization
      Namespace: AWS/ECS
      Dimensions:
        - Name: ServiceName
          Value: !Ref 'TaskNameInput'
        - Name: ClusterName
          Value:
            Fn::ImportValue:
              !Sub "${StackName}-ECSCluster"
      Statistic: Average
      Period: 60
      EvaluationPeriods: 1
      Threshold: 20
      ComparisonOperator: LessThanOrEqualToThreshold
      AlarmActions:
        - !Ref ScaleDownPolicy

  HighCpuUsageAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName:
        Fn::Join:
          - '-'
          - - high-cpu
            - !Ref 'TaskNameInput'
      AlarmDescription:
        Fn::Join:
          - ' '
          - - "High CPU utilization for service"
            - !Ref 'TaskNameInput'
      MetricName: CPUUtilization
      Namespace: AWS/ECS
      Dimensions:
        - Name: ServiceName
          Value: !Ref 'TaskNameInput'
        - Name: ClusterName
          Value:
            Fn::ImportValue:
              !Sub "${StackName}-ECSCluster"
      Statistic: Average
      Period: 60
      EvaluationPeriods: 1
      Threshold: 70
      ComparisonOperator: GreaterThanOrEqualToThreshold
      AlarmActions:
        - !Ref ScaleUpPolicy

  EcsSecurityGroupIngressFromPublicALB:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      Description: Ingress from the public ALB
      GroupId:
        Fn::ImportValue:
          !Sub "${StackName}-ContainerSecurityGroup"
      IpProtocol: -1
      SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'

  # Public load balancer, hosted in public subnets that is accessible
  # to the public, and is intended to route traffic to one or more public
  # facing services. This is used for accepting traffic from the public
  # internet and directing it to public facing microservices
  PublicLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the public facing load balancer
      VpcId:
        Fn::ImportValue:
          !Sub "${StackName}-VPC"
      SecurityGroupIngress:
          # Allow access to ALB from anywhere on the internet
          - CidrIp: 0.0.0.0/0
            IpProtocol: -1

  PublicLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      LoadBalancerAttributes:
      - Key: idle_timeout.timeout_seconds
        Value: '30'
      Subnets:
        # The load balancer is placed into the public subnets, so that traffic
        # from the internet can reach the load balancer directly via the internet gateway
        - Fn::ImportValue:
            !Sub "${StackName}-PublicSubnetOne"
        - Fn::ImportValue:
            !Sub "${StackName}-PublicSubnetTwo"
      SecurityGroups: [!Ref 'PublicLoadBalancerSG']

  PublicLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    DependsOn:
      - PublicLoadBalancer
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref 'TargetGroup'
          Type: 'forward'
      LoadBalancerArn: !Ref 'PublicLoadBalancer'
      Port: 80
      Protocol: HTTP
# These output values will be available to other templates to use.
Outputs:
  ServiceEndpoint:        # output
    Description: The URL to access the service
    Value: !Sub "http://${PublicLoadBalancer.DNSName}"
```

您可以调整这些文件以供使用 AWS Proton。

## 将您的基础架构即代码带到 AWS Proton
<a name="proton-tmp-files"></a>

只需稍作修改，即可将[示例 1](#ag-env-cfn-example) 用作用于部署环境的环境模板包的基础架构即 AWS Proton 代码 (IaC) 文件（如示[例 3](#ag-proton-env-cfn-example) 所示）。

您可以使用 [Jinja](https://jinja.palletsprojects.com/en/2.11.x/templates/) 语法来引用在基于 Ope [n API](https://swagger.io/docs/specification/data-models/) 的[架构文件](ag-schema.md)中定义的参数，而不是使用参数。 CloudFormation 为了方便起见，对这些输入参数进行了注释，并在 IaC 文件中多次引用这些参数。这样， AWS Proton 就可以审计和检查参数值。它也可以将一个 IaC 文件中的输出参数值与另一个 IaC 文件中的参数进行匹配和插入。

作为管理员，您可以将 AWS Proton `environment.inputs.`命名空间添加到输入参数中。在服务 IaC 文件中引用环境 IaC 文件输出时，您可以将 `environment.outputs.` 命名空间添加到输出中（例如 `environment.outputs.ClusterName`）。最后，用大括号和引号将它们括起来和引起来。

通过这些修改，您的 CloudFormation IaC 文件就可以被使用了。 AWS Proton

### 示例 3： AWS Proton 环境基础架构作为代码文件
<a name="ag-proton-env-cfn-example"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS Fargate cluster running containers in a public subnet. Only supports
             public facing load balancer, and public service discovery prefixes.
Mappings:
  # The VPC and subnet configuration is passed in via the environment spec.
  SubnetConfig:
    VPC:
      CIDR: '{{ environment.inputs.vpc_cidr}}'        # input parameter
    PublicOne:
      CIDR: '{{ environment.inputs.subnet_one_cidr}}' # input parameter
    PublicTwo:
      CIDR: '{{ environment.inputs.subnet_two_cidr}}' # input parameter
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']

  # Two public subnets, where containers will have public IP addresses
  PublicSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
      MapPublicIpOnLaunch: true

  PublicSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
      MapPublicIpOnLaunch: true

  # Setup networking resources for the public subnets. Containers
  # in the public subnets have public IP addresses and the routing table
  # sends network traffic via the internet gateway.
  InternetGateway:
    Type: AWS::EC2::InternetGateway
  GatewayAttachement:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref 'VPC'
      InternetGatewayId: !Ref 'InternetGateway'
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'VPC'
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachement
    Properties:
      RouteTableId: !Ref 'PublicRouteTable'
      DestinationCidrBlock: '0.0.0.0/0'
      GatewayId: !Ref 'InternetGateway'
  PublicSubnetOneRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetOne
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetTwoRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetTwo
      RouteTableId: !Ref PublicRouteTable

  # ECS Resources
  ECSCluster:
    Type: AWS::ECS::Cluster

  # A security group for the containers we will run in Fargate.
  # Rules are added to this security group based on what ingress you
  # add for the cluster.
  ContainerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the Fargate containers
      VpcId: !Ref 'VPC'

  # This is a role which is used by the ECS tasks themselves.
  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [ecs-tasks.amazonaws.com]
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'

# These output values are available to service infrastructure as code files as outputs, when given the 
# the 'service_instance.environment.outputs.' namespace, for example, service_instance.environment.outputs.ClusterName.

Outputs:
  ClusterName:                                            # output
    Description: The name of the ECS cluster
    Value: !Ref 'ECSCluster'
  ECSTaskExecutionRole:                                   # output
    Description: The ARN of the ECS role
    Value: !GetAtt 'ECSTaskExecutionRole.Arn'
  VpcId:                                                  # output
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'
  PublicSubnetOne:                                        # output
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'
  PublicSubnetTwo:                                        # output
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'
  ContainerSecurityGroup:                                 # output
    Description: A security group used to allow Fargate containers to receive traffic
    Value: !Ref 'ContainerSecurityGroup'
```

[示例 1 和示例](#ag-env-cfn-example) [3](#ag-proton-env-cfn-example) 中的 IaC 文件生成的 CloudFormation 堆栈略有不同。参数是在堆栈模板文件中以不同方式显示的。示*例 1* CloudFormation 堆栈模板文件在堆栈模板视图中显示参数标签（密钥）。示*例 3* AWS Proton CloudFormation 基础设施堆栈模板文件显示了参数值。 AWS Proton 输入参数*不会*出现在控制台 CloudFormation堆栈参数视图中。

在[示例 4](#ag-proton-svc-cfn-example) 中， AWS Proton 服务 IaC 文件与[示例 2](#ag-svc-cfn-example) 相对应。

### 示例 4： AWS Proton 服务实例 IaC 文件
<a name="ag-proton-svc-cfn-example"></a>

```
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service on AWS Fargate, hosted in a public subnet, and accessible via a public load balancer.
Mappings:
  TaskSize:
    x-small:
      cpu: 256
      memory: 512
    small:
      cpu: 512
      memory: 1024
    medium:
      cpu: 1024
      memory: 2048
    large:
      cpu: 2048
      memory: 4096
    x-large:
      cpu: 4096
      memory: 8192
Resources:
  # A log group for storing the stdout logs from this service's containers
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: '{{service_instance.name}}' # resource parameter

  # The task definition. This is a simple metadata description of what
  # container to run, and what resource requirements it has.
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: '{{service_instance.name}}'
      Cpu: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, cpu] # input parameter
      Memory: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, memory] 
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: '{{environment.outputs.ECSTaskExecutionRole}}' # output from an environment infrastructure as code file
      TaskRoleArn: !Ref "AWS::NoValue"
      ContainerDefinitions:
        - Name: '{{service_instance.name}}'
          Cpu: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, cpu]
          Memory: !FindInMap [TaskSize, {{service_instance.inputs.task_size}}, memory]
          Image: '{{service_instance.inputs.image}}'
          PortMappings:
            - ContainerPort: '{{service_instance.inputs.port}}' # input parameter
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group: '{{service_instance.name}}'
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: '{{service_instance.name}}'

  # The service_instance. The service is a resource which allows you to run multiple
  # copies of a type of task, and gather up their logs and metrics, as well
  # as monitor the number of running tasks and replace any that have crashed
  Service:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerRule
    Properties:
      ServiceName: '{{service_instance.name}}'
      Cluster: '{{environment.outputs.ClusterName}}' # output from an environment infrastructure as code file
      LaunchType: FARGATE
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 75
      DesiredCount: '{{service_instance.inputs.desired_count}}'       # input parameter
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - '{{environment.outputs.ContainerSecurityGroup}}' # output from an environment infrastructure as code file
          Subnets:
            - '{{environment.outputs.PublicSubnetOne}}'        # output from an environment infrastructure as code file
            - '{{environment.outputs.PublicSubnetTwo}}'
      TaskDefinition: !Ref 'TaskDefinition'
      LoadBalancers:
        - ContainerName: '{{service_instance.name}}'
          ContainerPort: '{{service_instance.inputs.port}}'
          TargetGroupArn: !Ref 'TargetGroup'

  # A target group. This is used for keeping track of all the tasks, and
  # what IP addresses / port numbers they have. You can query it yourself,
  # to use the addresses yourself, but most often this target group is just
  # connected to an application load balancer, or network load balancer, so
  # it can automatically distribute traffic across all the targets.
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 6
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      TargetType: ip
      Name: '{{service_instance.name}}'
      Port: '{{service_instance.inputs.port}}'
      Protocol: HTTP
      UnhealthyThresholdCount: 2
      VpcId: '{{environment.outputs.VpcId}}' # output from an environment infrastructure as code file

  # Create a rule on the load balancer for routing traffic to the target group
  LoadBalancerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref 'TargetGroup'
          Type: 'forward'
      Conditions:
        - Field: path-pattern
          Values:
            - '*'
      ListenerArn: !Ref PublicLoadBalancerListener
      Priority: 1

  # Enable autoscaling for this service
  ScalableTarget:
    Type: AWS::ApplicationAutoScaling::ScalableTarget
    DependsOn: Service
    Properties:
      ServiceNamespace: 'ecs'
      ScalableDimension: 'ecs:service:DesiredCount'
      ResourceId:
        Fn::Join:
          - '/'
          - - service
            - '{{environment.outputs.ClusterName}}' # output from an environment infrastructure as code file
            - '{{service_instance.name}}'
      MinCapacity: 1
      MaxCapacity: 10
      RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService

  # Create scaling policies for the service
  ScaleDownPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    DependsOn: ScalableTarget
    Properties:
      PolicyName:
        Fn::Join:
          - '/'
          - - scale
            - '{{service_instance.name}}'
            - down
      PolicyType: StepScaling
      ResourceId:
        Fn::Join:
          - '/'
          - - service
            - '{{environment.outputs.ClusterName}}'
            - '{{service_instance.name}}'
      ScalableDimension: 'ecs:service:DesiredCount'
      ServiceNamespace: 'ecs'
      StepScalingPolicyConfiguration:
        AdjustmentType: 'ChangeInCapacity'
        StepAdjustments:
          - MetricIntervalUpperBound: 0
            ScalingAdjustment: -1
        MetricAggregationType: 'Average'
        Cooldown: 60

  ScaleUpPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    DependsOn: ScalableTarget
    Properties:
      PolicyName:
        Fn::Join:
          - '/'
          - - scale
            - '{{service_instance.name}}'
            - up
      PolicyType: StepScaling
      ResourceId:
        Fn::Join:
          - '/'
          - - service
            - '{{environment.outputs.ClusterName}}'
            - '{{service_instance.name}}'
      ScalableDimension: 'ecs:service:DesiredCount'
      ServiceNamespace: 'ecs'
      StepScalingPolicyConfiguration:
        AdjustmentType: 'ChangeInCapacity'
        StepAdjustments:
          - MetricIntervalLowerBound: 0
            MetricIntervalUpperBound: 15
            ScalingAdjustment: 1
          - MetricIntervalLowerBound: 15
            MetricIntervalUpperBound: 25
            ScalingAdjustment: 2
          - MetricIntervalLowerBound: 25
            ScalingAdjustment: 3
        MetricAggregationType: 'Average'
        Cooldown: 60

  # Create alarms to trigger these policies
  LowCpuUsageAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName:
        Fn::Join:
          - '-'
          - - low-cpu
            - '{{service_instance.name}}'
      AlarmDescription:
        Fn::Join:
          - ' '
          - - "Low CPU utilization for service"
            - '{{service_instance.name}}'
      MetricName: CPUUtilization
      Namespace: AWS/ECS
      Dimensions:
        - Name: ServiceName
          Value: '{{service_instance.name}}'
        - Name: ClusterName
          Value:
            '{{environment.outputs.ClusterName}}'
      Statistic: Average
      Period: 60
      EvaluationPeriods: 1
      Threshold: 20
      ComparisonOperator: LessThanOrEqualToThreshold
      AlarmActions:
        - !Ref ScaleDownPolicy

  HighCpuUsageAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName:
        Fn::Join:
          - '-'
          - - high-cpu
            - '{{service_instance.name}}'
      AlarmDescription:
        Fn::Join:
          - ' '
          - - "High CPU utilization for service"
            - '{{service_instance.name}}'
      MetricName: CPUUtilization
      Namespace: AWS/ECS
      Dimensions:
        - Name: ServiceName
          Value: '{{service_instance.name}}'
        - Name: ClusterName
          Value:
            '{{environment.outputs.ClusterName}}'
      Statistic: Average
      Period: 60
      EvaluationPeriods: 1
      Threshold: 70
      ComparisonOperator: GreaterThanOrEqualToThreshold
      AlarmActions:
        - !Ref ScaleUpPolicy

  EcsSecurityGroupIngressFromPublicALB:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      Description: Ingress from the public ALB
      GroupId: '{{environment.outputs.ContainerSecurityGroup}}'
      IpProtocol: -1
      SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'

  # Public load balancer, hosted in public subnets that is accessible
  # to the public, and is intended to route traffic to one or more public
  # facing services. This is used for accepting traffic from the public
  # internet and directing it to public facing microservices
  PublicLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the public facing load balancer
      VpcId: '{{environment.outputs.VpcId}}'
      SecurityGroupIngress:
          # Allow access to ALB from anywhere on the internet
          - CidrIp: 0.0.0.0/0
            IpProtocol: -1

  PublicLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      LoadBalancerAttributes:
      - Key: idle_timeout.timeout_seconds
        Value: '30'
      Subnets:
        # The load balancer is placed into the public subnets, so that traffic
        # from the internet can reach the load balancer directly via the internet gateway
        - '{{environment.outputs.PublicSubnetOne}}'
        - '{{environment.outputs.PublicSubnetTwo}}'
      SecurityGroups: [!Ref 'PublicLoadBalancerSG']

  PublicLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    DependsOn:
      - PublicLoadBalancer
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref 'TargetGroup'
          Type: 'forward'
      LoadBalancerArn: !Ref 'PublicLoadBalancer'
      Port: 80
      Protocol: HTTP
Outputs:
  ServiceEndpoint:         # output
    Description: The URL to access the service
    Value: !Sub "http://${PublicLoadBalancer.DNSName}"
```

在[示例 5](#ag-proton-pipeline-cfn-example) 中， AWS Proton 管道 IaC 文件配置管道基础设施以支持[示](#ag-proton-svc-cfn-example)例 4 中配置的服务实例。

### 示例 5： AWS Proton 服务管道 IaC 文件
<a name="ag-proton-pipeline-cfn-example"></a>

```
Resources:
  ECRRepo:
    Type: AWS::ECR::Repository
    DeletionPolicy: Retain
  BuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0
        PrivilegedMode: true
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: repo_name
          Type: PLAINTEXT
          Value: !Ref ECRRepo
        - Name: service_name
          Type: PLAINTEXT
          Value: '{{ service.name }}'    # resource parameter
      ServiceRole:
        Fn::GetAtt:
          - PublishRole
          - Arn
      Source:
        BuildSpec:
          Fn::Join:
            - ""
            - - >-
                {
                  "version": "0.2",
                  "phases": {
                    "install": {
                      "runtime-versions": {
                        "docker": 18
                      },
                      "commands": [
                        "pip3 install --upgrade --user awscli",
                        "echo 'f6bd1536a743ab170b35c94ed4c7c4479763356bd543af5d391122f4af852460  yq_linux_amd64' > yq_linux_amd64.sha",
                        "wget https://github.com/mikefarah/yq/releases/download/3.4.0/yq_linux_amd64",
                        "sha256sum -c yq_linux_amd64.sha",
                        "mv yq_linux_amd64 /usr/bin/yq",
                        "chmod +x /usr/bin/yq"
                      ]
                    },
                    "pre_build": {
                      "commands": [
                        "cd $CODEBUILD_SRC_DIR",
                        "$(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)",
                        "{{ pipeline.inputs.unit_test_command }}",    # input parameter
                      ]
                    },
                    "build": {
                      "commands": [
                        "IMAGE_REPO_NAME=$repo_name",
                        "IMAGE_TAG=$CODEBUILD_BUILD_NUMBER",
                        "IMAGE_ID=
              - Ref: AWS::AccountId
              - >-
                .dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG",
                        "docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG -f {{ pipeline.inputs.dockerfile }} .",     # input parameter
                        "docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $IMAGE_ID;",
                        "docker push $IMAGE_ID"
                      ]
                    },
                    "post_build": {
                      "commands": [
                        "aws proton --region $AWS_DEFAULT_REGION get-service --name $service_name | jq -r .service.spec > service.yaml",
                        "yq w service.yaml 'instances[*].spec.image' \"$IMAGE_ID\" > rendered_service.yaml"
                      ]
                    }
                  },
                  "artifacts": {
                    "files": [
                      "rendered_service.yaml"
                    ]
                  }
                }
        Type: CODEPIPELINE
      EncryptionKey:
        Fn::GetAtt:
          - PipelineArtifactsBucketEncryptionKey
          - Arn
{% for service_instance in service_instances %}
  Deploy{{loop.index}}Project:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: CODEPIPELINE
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/amazonlinux2-x86_64-standard:3.0
        PrivilegedMode: false
        Type: LINUX_CONTAINER
        EnvironmentVariables:
        - Name: service_name
          Type: PLAINTEXT
          Value:  '{{service.name}}'          # resource parameter
        - Name: service_instance_name
          Type: PLAINTEXT
          Value: '{{service_instance.name}}'  # resource parameter
      ServiceRole:
        Fn::GetAtt:
          - DeploymentRole
          - Arn
      Source:
        BuildSpec: >-
          {
            "version": "0.2",
            "phases": {
              "build": {
                "commands": [
                  "pip3 install --upgrade --user awscli",
                  "aws proton --region $AWS_DEFAULT_REGION update-service-instance --deployment-type CURRENT_VERSION --name $service_instance_name --service-name $service_name --spec file://rendered_service.yaml",
                  "aws proton --region $AWS_DEFAULT_REGION wait service-instance-deployed --name $service_instance_name --service-name $service_name"
                ]
              }
            }
          }
        Type: CODEPIPELINE
      EncryptionKey:
        Fn::GetAtt:
          - PipelineArtifactsBucketEncryptionKey
          - Arn
{% endfor %}
  # This role is used to build and publish an image to ECR
  PublishRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: "2012-10-17"		 	 	 
  PublishRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
            Effect: Allow
            Resource:
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/
                    - Ref: BuildProject
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/
                    - Ref: BuildProject
                    - :*
          - Action:
              - codebuild:CreateReportGroup
              - codebuild:CreateReport
              - codebuild:UpdateReport
              - codebuild:BatchPutTestCases
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - ":codebuild:"
                  - Ref: AWS::Region
                  - ":"
                  - Ref: AWS::AccountId
                  - :report-group/
                  - Ref: BuildProject
                  - -*
          - Action:
              - ecr:GetAuthorizationToken
            Effect: Allow
            Resource: "*"
          - Action:
              - ecr:BatchCheckLayerAvailability
              - ecr:CompleteLayerUpload
              - ecr:GetAuthorizationToken
              - ecr:InitiateLayerUpload
              - ecr:PutImage
              - ecr:UploadLayerPart
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - ECRRepo
                - Arn
          - Action:
              - proton:GetService
            Effect: Allow
            Resource: "*"
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
              - s3:DeleteObject*
              - s3:PutObject*
              - s3:Abort*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - PipelineArtifactsBucket
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - PipelineArtifactsBucket
                        - Arn
                    - /*
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: PublishRoleDefaultPolicy
      Roles:
        - Ref: PublishRole

  DeploymentRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: "2012-10-17"		 	 	 
  DeploymentRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
            Effect: Allow
            Resource:
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/Deploy*Project*
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/Deploy*Project:*
          - Action:
              - codebuild:CreateReportGroup
              - codebuild:CreateReport
              - codebuild:UpdateReport
              - codebuild:BatchPutTestCases
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - ":codebuild:"
                  - Ref: AWS::Region
                  - ":"
                  - Ref: AWS::AccountId
                  - :report-group/Deploy*Project
                  - -*
          - Action:
              - proton:UpdateServiceInstance
              - proton:GetServiceInstance
            Effect: Allow
            Resource: "*"
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - PipelineArtifactsBucket
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - PipelineArtifactsBucket
                        - Arn
                    - /*
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: DeploymentRoleDefaultPolicy
      Roles:
        - Ref: DeploymentRole
  PipelineArtifactsBucketEncryptionKey:
    Type: AWS::KMS::Key
    Properties:
      KeyPolicy:
        Statement:
          - Action:
              - kms:Create*
              - kms:Describe*
              - kms:Enable*
              - kms:List*
              - kms:Put*
              - kms:Update*
              - kms:Revoke*
              - kms:Disable*
              - kms:Get*
              - kms:Delete*
              - kms:ScheduleKeyDeletion
              - kms:CancelKeyDeletion
              - kms:GenerateDataKey
              - kms:TagResource
              - kms:UntagResource
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - PipelineRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - PublishRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - PublishRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - DeploymentRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - DeploymentRole
                  - Arn
            Resource: "*"
        Version: "2012-10-17"		 	 	 
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
  PipelineArtifactsBucket:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              KMSMasterKeyID:
                Fn::GetAtt:
                  - PipelineArtifactsBucketEncryptionKey
                  - Arn
              SSEAlgorithm: aws:kms
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
  PipelineArtifactsBucketEncryptionKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: 'alias/codepipeline-encryption-key-{{ service.name }}'
      TargetKeyId:
        Fn::GetAtt:
          - PipelineArtifactsBucketEncryptionKey
          - Arn
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
  PipelineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codepipeline.amazonaws.com
        Version: "2012-10-17"		 	 	 
  PipelineRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
              - s3:DeleteObject*
              - s3:PutObject*
              - s3:Abort*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - PipelineArtifactsBucket
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - PipelineArtifactsBucket
                        - Arn
                    - /*
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
          - Action: codestar-connections:*
            Effect: Allow
            Resource: "*"
          - Action: sts:AssumeRole
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineBuildCodePipelineActionRole
                - Arn
          - Action: sts:AssumeRole
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineDeployCodePipelineActionRole
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: PipelineRoleDefaultPolicy
      Roles:
        - Ref: PipelineRole
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn:
        Fn::GetAtt:
          - PipelineRole
          - Arn
      Stages:
        - Actions:
            - ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: CodeStarSourceConnection
                Version: "1"
              Configuration:
                ConnectionArn: '{{ service.repository_connection_arn }}'
                FullRepositoryId: '{{ service.repository_id }}'
                BranchName: '{{ service.branch_name }}'
              Name: Checkout
              OutputArtifacts:
                - Name: Artifact_Source_Checkout
              RunOrder: 1
          Name: Source
        - Actions:
            - ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: "1"
              Configuration:
                ProjectName:
                  Ref: BuildProject
              InputArtifacts:
                - Name: Artifact_Source_Checkout
              Name: Build
              OutputArtifacts:
                - Name: BuildOutput
              RoleArn:
                Fn::GetAtt:
                  - PipelineBuildCodePipelineActionRole
                  - Arn
              RunOrder: 1
          Name: Build {%- for service_instance in service_instances %}
        - Actions:
            - ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: "1"
              Configuration:
                ProjectName:
                  Ref: Deploy{{loop.index}}Project
              InputArtifacts:
                - Name: BuildOutput
              Name: Deploy
              RoleArn:
                Fn::GetAtt:
                  - PipelineDeployCodePipelineActionRole
                  - Arn
              RunOrder: 1
          Name: 'Deploy{{service_instance.name}}'
{%- endfor %}
      ArtifactStore:
        EncryptionKey:
          Id:
            Fn::GetAtt:
              - PipelineArtifactsBucketEncryptionKey
              - Arn
          Type: KMS
        Location:
          Ref: PipelineArtifactsBucket
        Type: S3
    DependsOn:
      - PipelineRoleDefaultPolicy
      - PipelineRole
  PipelineBuildCodePipelineActionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
        Version: "2012-10-17"		 	 	 
  PipelineBuildCodePipelineActionRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - codebuild:BatchGetBuilds
              - codebuild:StartBuild
              - codebuild:StopBuild
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - BuildProject
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: PipelineBuildCodePipelineActionRoleDefaultPolicy
      Roles:
        - Ref: PipelineBuildCodePipelineActionRole
  PipelineDeployCodePipelineActionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
        Version: "2012-10-17"		 	 	 
  PipelineDeployCodePipelineActionRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - codebuild:BatchGetBuilds
              - codebuild:StartBuild
              - codebuild:StopBuild
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - ":codebuild:"
                  - Ref: AWS::Region
                  - ":"
                  - Ref: AWS::AccountId
                  - ":project/Deploy*"
        Version: "2012-10-17"		 	 	 
      PolicyName: PipelineDeployCodePipelineActionRoleDefaultPolicy
      Roles:
        - Ref: PipelineDeployCodePipelineActionRole
Outputs:
  PipelineEndpoint:
    Description: The URL to access the pipeline
    Value: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${Pipeline}/view?region=${AWS::Region}"

                ]
              }
            }
          }
        Type: CODEPIPELINE
      EncryptionKey:
        Fn::GetAtt:
          - PipelineArtifactsBucketEncryptionKey
          - Arn
{% endfor %}
  # This role is used to build and publish an image to ECR
  PublishRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: "2012-10-17"		 	 	 
  PublishRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
            Effect: Allow
            Resource:
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/
                    - Ref: BuildProject
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/
                    - Ref: BuildProject
                    - :*
          - Action:
              - codebuild:CreateReportGroup
              - codebuild:CreateReport
              - codebuild:UpdateReport
              - codebuild:BatchPutTestCases
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - ":codebuild:"
                  - Ref: AWS::Region
                  - ":"
                  - Ref: AWS::AccountId
                  - :report-group/
                  - Ref: BuildProject
                  - -*
          - Action:
              - ecr:GetAuthorizationToken
            Effect: Allow
            Resource: "*"
          - Action:
              - ecr:BatchCheckLayerAvailability
              - ecr:CompleteLayerUpload
              - ecr:GetAuthorizationToken
              - ecr:InitiateLayerUpload
              - ecr:PutImage
              - ecr:UploadLayerPart
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - ECRRepo
                - Arn
          - Action:
              - proton:GetService
            Effect: Allow
            Resource: "*"
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
              - s3:DeleteObject*
              - s3:PutObject*
              - s3:Abort*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - PipelineArtifactsBucket
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - PipelineArtifactsBucket
                        - Arn
                    - /*
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: PublishRoleDefaultPolicy
      Roles:
        - Ref: PublishRole

  DeploymentRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
        Version: "2012-10-17"		 	 	 
  DeploymentRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
            Effect: Allow
            Resource:
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/Deploy*Project*
              - Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":logs:"
                    - Ref: AWS::Region
                    - ":"
                    - Ref: AWS::AccountId
                    - :log-group:/aws/codebuild/Deploy*Project:*
          - Action:
              - codebuild:CreateReportGroup
              - codebuild:CreateReport
              - codebuild:UpdateReport
              - codebuild:BatchPutTestCases
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - ":codebuild:"
                  - Ref: AWS::Region
                  - ":"
                  - Ref: AWS::AccountId
                  - :report-group/Deploy*Project
                  - -*
          - Action:
              - proton:UpdateServiceInstance
              - proton:GetServiceInstance
            Effect: Allow
            Resource: "*"
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - PipelineArtifactsBucket
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - PipelineArtifactsBucket
                        - Arn
                    - /*
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: DeploymentRoleDefaultPolicy
      Roles:
        - Ref: DeploymentRole
  PipelineArtifactsBucketEncryptionKey:
    Type: AWS::KMS::Key
    Properties:
      KeyPolicy:
        Statement:
          - Action:
              - kms:Create*
              - kms:Describe*
              - kms:Enable*
              - kms:List*
              - kms:Put*
              - kms:Update*
              - kms:Revoke*
              - kms:Disable*
              - kms:Get*
              - kms:Delete*
              - kms:ScheduleKeyDeletion
              - kms:CancelKeyDeletion
              - kms:GenerateDataKey
              - kms:TagResource
              - kms:UntagResource
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - PipelineRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - PublishRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - PublishRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - DeploymentRole
                  - Arn
            Resource: "*"
          - Action:
              - kms:Decrypt
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Principal:
              AWS:
                Fn::GetAtt:
                  - DeploymentRole
                  - Arn
            Resource: "*"
        Version: "2012-10-17"		 	 	 
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
  PipelineArtifactsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              KMSMasterKeyID:
                Fn::GetAtt:
                  - PipelineArtifactsBucketEncryptionKey
                  - Arn
              SSEAlgorithm: aws:kms
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
  PipelineArtifactsBucketEncryptionKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: 'alias/codepipeline-encryption-key-{{ service.name }}'     # resource parameter
      TargetKeyId:
        Fn::GetAtt:
          - PipelineArtifactsBucketEncryptionKey
          - Arn
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
  PipelineRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: codepipeline.amazonaws.com
        Version: "2012-10-17"		 	 	 
  PipelineRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
              - s3:DeleteObject*
              - s3:PutObject*
              - s3:Abort*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - PipelineArtifactsBucket
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - PipelineArtifactsBucket
                        - Arn
                    - /*
          - Action:
              - kms:Decrypt
              - kms:DescribeKey
              - kms:Encrypt
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineArtifactsBucketEncryptionKey
                - Arn
          - Action: codestar-connections:*
            Effect: Allow
            Resource: "*"
          - Action: sts:AssumeRole
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineBuildCodePipelineActionRole
                - Arn
          - Action: sts:AssumeRole
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - PipelineDeployCodePipelineActionRole
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: PipelineRoleDefaultPolicy
      Roles:
        - Ref: PipelineRole
  Pipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      RoleArn:
        Fn::GetAtt:
          - PipelineRole
          - Arn
      Stages:
        - Actions:
            - ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: CodeStarSourceConnection
                Version: "1"
              Configuration:
                ConnectionArn: '{{ service.repository_connection_arn }}'   # resource parameter
                FullRepositoryId: '{{ service.repository_id }}'            # resource parameter
                BranchName: '{{ service.branch_name }}'                    # resource parameter
              Name: Checkout
              OutputArtifacts:
                - Name: Artifact_Source_Checkout
              RunOrder: 1
          Name: Source
        - Actions:
            - ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: "1"
              Configuration:
                ProjectName:
                  Ref: BuildProject
              InputArtifacts:
                - Name: Artifact_Source_Checkout
              Name: Build
              OutputArtifacts:
                - Name: BuildOutput
              RoleArn:
                Fn::GetAtt:
                  - PipelineBuildCodePipelineActionRole
                  - Arn
              RunOrder: 1
          Name: Build {%- for service_instance in service_instances %}
        - Actions:
            - ActionTypeId:
                Category: Build
                Owner: AWS
                Provider: CodeBuild
                Version: "1"
              Configuration:
                ProjectName:
                  Ref: Deploy{{loop.index}}Project
              InputArtifacts:
                - Name: BuildOutput
              Name: Deploy
              RoleArn:
                Fn::GetAtt:
                  - PipelineDeployCodePipelineActionRole
                  - Arn
              RunOrder: 1
          Name: 'Deploy{{service_instance.name}}'         # resource parameter
{%- endfor %}
      ArtifactStore:
        EncryptionKey:
          Id:
            Fn::GetAtt:
              - PipelineArtifactsBucketEncryptionKey
              - Arn
          Type: KMS
        Location:
          Ref: PipelineArtifactsBucket
        Type: S3
    DependsOn:
      - PipelineRoleDefaultPolicy
      - PipelineRole
  PipelineBuildCodePipelineActionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
        Version: "2012-10-17"		 	 	 
  PipelineBuildCodePipelineActionRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - codebuild:BatchGetBuilds
              - codebuild:StartBuild
              - codebuild:StopBuild
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - BuildProject
                - Arn
        Version: "2012-10-17"		 	 	 
      PolicyName: PipelineBuildCodePipelineActionRoleDefaultPolicy
      Roles:
        - Ref: PipelineBuildCodePipelineActionRole
  PipelineDeployCodePipelineActionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              AWS:
                Fn::Join:
                  - ""
                  - - "arn:"
                    - Ref: AWS::Partition
                    - ":iam::"
                    - Ref: AWS::AccountId
                    - :root
        Version: "2012-10-17"		 	 	 
  PipelineDeployCodePipelineActionRoleDefaultPolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - codebuild:BatchGetBuilds
              - codebuild:StartBuild
              - codebuild:StopBuild
            Effect: Allow
            Resource:
              Fn::Join:
                - ""
                - - "arn:"
                  - Ref: AWS::Partition
                  - ":codebuild:"
                  - Ref: AWS::Region
                  - ":"
                  - Ref: AWS::AccountId
                  - ":project/Deploy*"
        Version: "2012-10-17"		 	 	 
      PolicyName: PipelineDeployCodePipelineActionRoleDefaultPolicy
      Roles:
        - Ref: PipelineDeployCodePipelineActionRole
Outputs:
  PipelineEndpoint:
    Description: The URL to access the pipeline
    Value: !Sub "https://${AWS::Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${Pipeline}/view?region=${AWS::Region}"
```

# CodeBuild 配置模板包
<a name="ag-infrastructure-tmp-files-codebuild"></a>

通过 CodeBuild 配置，无需使用 IaC 模板来渲染 IaC 文件并使用 IaC 配置引擎运行它们， AWS Proton 只需运行 shell 命令即可。为此，请在环境帐户中为环境 AWS Proton 创建一个 AWS CodeBuild 项目，然后启动一个作业，在每次创建或更新 AWS Proton 资源时运行您的命令。在您编写模板捆绑包时，您需要提供一个清单，以指定基础设施预置和取消预置命令，以及这些命令可能需要的任何程序、脚本和其他文件。您的命令可以读取 AWS Proton 提供的输入，并负责预置或取消预置基础设施和生成输出值。

清单还指定了 AWS Proton 应如何呈现您的代码可以输入并从中获取输入值的输入文件。可以将该文件渲染为 JSON 或 HCL。有关输入参数的更多信息，请参阅[CodeBuild 配置参数详细信息和示例](parameters-codebuild.md)。有关清单文件的更多信息，请参阅[总结模板文件 AWS Proton](ag-wrap-up.md)。

**注意**  
您可以对环境和服务使用 CodeBuild 置备。目前，您无法通过这种方法预置组件。

## 示例：使用 AWS CDK 带 CodeBuild 配置的
<a name="ag-infrastructure-tmp-files-codebuild.example"></a>

作为使用 CodeBuild 预配的示例，您可以包括使用预配置（*部署*）和取消置备（*销毁*） AWS 资源的代码，以及用于安装 CDK 并运行 CDK 代码的清单。 AWS Cloud Development Kit (AWS CDK) 

以下各节列出了您可以包含在 CodeBuild 配置模板包中的示例文件，该模板包使用置备环境 AWS CDK。

### 清单
<a name="ag-infrastructure-tmp-files-codebuild.example.manifest"></a>

以下清单文件指定了 CodeBuild 配置，并包括安装和使用 AWS CDK、输出文件处理和报告输出所需的命令 AWS Proton。

**Example infrastructure/manifest.yaml**  

```
infrastructure:
  templates:
    - rendering_engine: codebuild
      settings:
        image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
        runtimes:
          nodejs: 16
        provision:
          - npm install
          - npm run build
          - npm run cdk bootstrap
          - npm run cdk deploy -- --require-approval never --outputs-file proton-outputs.json
          - jq 'to_entries | map_values(.value) | add | to_entries | map({key:.key, valueString:.value})' < proton-outputs.json > outputs.json
          - aws proton notify-resource-deployment-status-change --resource-arn $RESOURCE_ARN --status IN_PROGRESS --outputs file://./outputs.json
        deprovision:
          - npm install
          - npm run build
          - npm run cdk destroy
        project_properties:
          VpcConfig:
            VpcId: "{{ environment.inputs.codebuild_vpc_id }}"
            Subnets: "{{ environment.inputs.codebuild_subnets }}"
            SecurityGroupIds: "{{ environment.inputs.codebuild_security_groups }}"
```

### 架构
<a name="ag-infrastructure-tmp-files-codebuild.example.schema"></a>

以下架构文件为环境定义参数。您的 AWS CDK 代码可以在部署期间引用这些参数的值。

**Example schema/schema.yaml**  

```
schema:
  format:
    openapi: "3.0.0"
  environment_input_type: "MyEnvironmentInputType"
  types:
    MyEnvironmentInputType:
      type: object
      description: "Input properties for my environment"
      properties:
        my_sample_input:
          type: string
          description: "This is a sample input"
          default: "hello world"
        my_other_sample_input:
          type: string
          description: "Another sample input"
      required:
        - my_other_sample_input
```

### AWS CDK 文件
<a name="ag-infrastructure-tmp-files-codebuild.example.cdkcode"></a>

以下文件是一个 Node.js CDK 项目示例。

**Example infrastructure/package.json**  

```
{
  "name": "ProtonEnvironment",
  "version": "0.1.0",
  "bin": {
    "ProtonEnvironmente": "bin/ProtonEnvironment.js"
  },
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk"
  },
  "devDependencies": {
    "@types/jest": "^28.1.7",
    "@types/node": "18.7.6",
    "jest": "^28.1.3",
    "ts-jest": "^28.0.8",
    "aws-cdk": "2.37.1",
    "ts-node": "^10.9.1",
    "typescript": "~4.7.4"
  },
  "dependencies": {
    "aws-cdk-lib": "2.37.1",
    "constructs": "^10.1.77",
    "source-map-support": "^0.5.21"
  }
}
```

**Example infrastructure/tsconfig.json**  

```
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs",
    "lib": [
      "es2018"
    ],
    "declaration": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": false,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": false,
    "inlineSourceMap": true,
    "inlineSources": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "typeRoots": [
      "./node_modules/@types"
    ]
  },
  "exclude": [
    "node_modules",
    "cdk.out"
  ]
}
```

**Example infrastructure/cdk.json**  

```
{
  "app": "npx ts-node --prefer-ts-exts bin/ProtonEnvironment.ts",
  "outputsFile": "proton-outputs.json",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:stackRelativeExports": true,
    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
    "@aws-cdk/aws-lambda:recognizeVersionProps": true,
    "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ]
  }
}
```

**Example infrastructure/bin/ProtonEnvironment.ts**  

```
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { ProtonEnvironmentStack } from '../lib/ProtonEnvironmentStack';

const app = new cdk.App();
new ProtonEnvironmentStack(app, 'ProtonEnvironmentStack', {});
```

**Example infrastructure/lib/ProtonEnvironmentStack.ts**  

```
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import * as ssm from 'aws-cdk-lib/aws-ssm';
import input from '../proton-inputs.json';

export class ProtonEnvironmentStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, { ...props, stackName: process.env.STACK_NAME });

    const ssmParam = new ssm.StringParameter(this, "ssmParam", {
      stringValue: input.environment.inputs.my_sample_input,
      parameterName: `${process.env.STACK_NAME}-Param`,
      tier: ssm.ParameterTier.STANDARD
    })

    new cdk.CfnOutput(this, 'ssmParamOutput', {
      value: ssmParam.parameterName,
      description: 'The name of the ssm parameter',
      exportName: `${process.env.STACK_NAME}-Param`
    });
  }
}
```

### 渲染的输入文件
<a name="ag-infrastructure-tmp-files-codebuild.example.manifest"></a>

当您使用 CodeBuild基于的配置模板创建环境时，会使用您提供的输入[参数值 AWS Proton 呈现一个输入](https://docs.aws.amazon.com/proton/latest/userguide/parameters.html)文件。您的代码可以引用这些值。以下文件是一个渲染的输入文件示例。

**Example infrastructure/proton-inputs.json**  

```
{
  "environment": {
    "name": "myenv",
    "inputs": {
      "my_sample_input": "10.0.0.0/16",
      "my_other_sample_input": "11.0.0.0/16"
    }
  }
}
```

# Terraform IaC 文件
<a name="ag-infrastructure-tmp-files-terraform"></a>

学习如何使用 Terraform 基础设施即代码 (IaC) 文件。 AWS Proton[Terraform](https://www.terraform.io/) 是一个广泛使用的开源 IaC 引擎，由开发。[HashiCorp](https://www.hashicorp.com/)Terraform 模块是用 HCL 语言开发 HashiCorp的，支持包括亚马逊 Web Services 在内的多个后端基础设施提供商。

AWS Proton 支持 Terraform IaC 的[自我管理配置](ag-works-prov-methods.md#ag-works-prov-methods-self)。

有关响应拉取请求并实现基础架构配置的配置存储库的完整示例，请参阅上的 [Terraform Acti OpenSource GitHub ons 自动化模板](https://github.com/aws-samples/aws-proton-terraform-github-actions-sample)。 AWS Proton GitHub

**自托管式预置如何使用 Terraform IaC 模板捆绑包文件：**

1. 使用 Terraform 模板包[创建环境](ag-create-env.md)时，使用控制台或输入参数 AWS Proton 编译`.tf`文件。`spec file`

1. 它发出拉取请求，将编译的 IaC 文件合并到[您在 AWS Proton中注册的存储库](ag-create-repo.md)。

1. 如果请求获得批准，则 AWS Proton 等待您提供的配置状态。

1. 如果拒绝了该请求，则取消创建环境。

1. 如果拉取请求超时，则*不会* 完成创建环境。

**AWS Proton 考虑到 Terraform IaC 的注意事项：**
+ AWS Proton 无法管理你的 Terraform 配置。
+ 您必须[向注册配置存储库](ag-create-repo.md) AWS Proton。 AWS Proton 对该存储库发出拉取请求。
+ 您必须[创建 CodeStar 连接](setting-up-for-service.md#setting-up-vcontrol)才能连接到 AWS Proton 您的配置存储库。
+ 要从 AWS Proton 已编译的 IaC 文件中进行配置，您必须响应 AWS Proton 拉取请求。 AWS Proton 在环境和服务创建和更新操作之后发出拉取请求。有关更多信息，请参阅[AWS Proton 环境](ag-environments.md)和[AWS Proton 服务](ag-services.md)。
+ 要使用 AWS Proton 已编译的 IaC 文件配置管道，必须[创建 CI/CD 管道存储库](setting-up-for-service.md#setting-up-pr-repo)。
+ 基于拉取请求的配置自动化必须包括通知 AWS Proton 任何已配置 AWS Proton 资源状态变化的步骤。你可以使用 AWS Proton [NotifyResourceDeploymentStatusChange API](https://docs.aws.amazon.com/proton/latest/APIReference/API_NotifyResourceDeploymentStatusChange.html)。
+ 您无法将从 CloudFormation IaC 文件创建的服务、管道和组件部署到通过 Terraform iaC 文件创建的环境中。
+ 您无法将从 Terraform IaC 文件创建的服务、管道和组件部署到通过 IaC 文件创建的环境中。 CloudFormation 

在准备 Terraform IaC 文件时 AWS Proton，需要将命名空间附加到输入变量，如以下示例所示。有关更多信息，请参阅[参数](parameters.md)。

## 示例 1： AWS Proton 环境 Terraform iaC 文件
<a name="ag-env-tform-example"></a>

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  // This tells terraform to store the state file in s3 at the location
  // s3://terraform-state-bucket/tf-os-sample/terraform.tfstate
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "tf-os-sample/terraform.tfstate"
    region = "us-east-1"
  }
}

// Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = var.proton_tags
  }
}

resource "aws_ssm_parameter" "my_ssm_parameter" {
  name  = "my_ssm_parameter"
  type  = "String"
  // Use the Proton environment.inputs. namespace
  value = var.environment.inputs.ssm_parameter_value
}
```

## 编译的基础设施即代码
<a name="compiled-tform"></a>

创建环境或服务时，使用控制台或`spec file`输入将基础架构 AWS Proton 编译为代码文件。它为 Terraform 可使用的输入创建 `proton.resource-type.variables.tf` 和 `proton.auto.tfvars.json` 文件，如以下示例中所示。这些文件位于指定存储库中与环境或服务实例名称匹配的文件夹中。

该示例显示了如何在变量定义和变量值中 AWS Proton 包含标签，以及如何将这些 AWS Proton 标签传播到已配置的资源。有关更多信息，请参阅 [标签传播到预置的资源](resources.md#auto-tags-prop)。

### 示例 2：为名为“dev”的环境编译的 IaC 文件。
<a name="ag-compiled-example"></a>

**dev/environment.tf：**

```
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  // This tells terraform to store the state file in s3 at the location
  // s3://terraform-state-bucket/tf-os-sample/terraform.tfstate
  backend "s3" {
    bucket = "terraform-state-bucket"
    key    = "tf-os-sample/terraform.tfstate"
    region = "us-east-1"
  }
}

// Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = var.proton_tags
  }
}

resource "aws_ssm_parameter" "my_ssm_parameter" {
  name  = "my_ssm_parameter"
  type  = "String"
  // Use the Proton environment.inputs. namespace
  value = var.environment.inputs.ssm_parameter_value
}
```

**dev/proton.environment.variables.tf：**

```
variable "environment" {
  type = object({
    inputs = map(string)
    name = string
  })
}

variable "proton_tags" {
  type = map(string)
  default = null
}
```

**dev/proton.auto.tfvars.json：**

```
{
  "environment": {
    "name": "dev",
    "inputs": {
      "ssm_parameter_value": "MyNewParamValue"
    }
  }

  "proton_tags" : {
    "proton:account" : "123456789012",
    "proton:template" : "arn:aws:proton:us-east-1:123456789012:environment-template/fargate-env",
    "proton:environment" : "arn:aws:proton:us-east-1:123456789012:environment/dev"
  }
}
```

## 存储库路径
<a name="repo-dir"></a>

AWS Proton 使用来自环境或服务创建操作的控制台或规范输入来找到已编译的 IaC 文件的存储库和路径。输入值将传递到[命名空间输入参数](parameters.md)。

AWS Proton 支持两种存储库路径布局。在以下示例中，路径是由两个环境中的命名空间资源参数命名的。每个环境具有两个服务的服务实例，其中的一个服务的服务实例具有直接定义的组件。

<a name="limits-table"></a>[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/proton/latest/userguide/ag-infrastructure-tmp-files-terraform.html)

------
#### [ Layout 1 ]

如果 AWS Proton 找到带有`environments`文件夹的指定存储库，它将创建一个包含已编译的 IaC 文件并以命名的文件夹。`environment.name`

如果在指定的存储库中 AWS Proton 找到的`environments`文件夹包含与服务实例兼容环境名称相匹配的文件夹名称，则它会创建一个包含已编译的实例 IaC 文件并以命名的文件夹。`service_instance.name`

```
/repo
    /environments
        /env-prod                             # environment folder
            main.tf
            proton.environment.variables.tf
            proton.auto.tfvars.json
          
            /service-one-instance-one-prod    # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /service-two-instance-two-prod    # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /component-prod                   # component folder
                main.tf
                proton.component.variables.tf
                proton.auto.tfvars.json
              
        /env-staged                           # environment folder
            main.tf
            proton.variables.tf
            proton.auto.tfvars.json         
          
            /service-one-instance-one-staged  # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /service-two-instance-two-staged  # instance folder
                main.tf
                proton.service_instance.variables.tf
                proton.auto.tfvars.json
              
            /component-staged                 # component folder
                main.tf
                proton.component.variables.tf
                proton.auto.tfvars.json
```

------
#### [ Layout 2 ]

如果 AWS Proton 找到没有`environments`文件夹的指定存储库，它将创建一个文件`environment.name`夹，用于查找已编译的环境 IaC 文件。

如果 AWS Proton 找到的指定存储库的文件夹名称与服务实例兼容的环境名称相匹配，它将创建一个`service_instance.name`文件夹，用于查找已编译的实例 IaC 文件。

```
/repo
    /env-prod                             # environment folder
        main.tf
        proton.environment.variables.tf
        proton.auto.tfvars.json
      
        /service-one-instance-one-prod    # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /service-two-instance-two-prod    # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /component-prod                   # component folder
            main.tf
            proton.component.variables.tf
            proton.auto.tfvars.json
          
    /env-staged                           # environment folder
        main.tf
        proton.variables.tf
        proton.auto.tfvars.json         
      
        /service-one-instance-one-staged  # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /service-two-instance-two-staged  # instance folder
            main.tf
            proton.service_instance.variables.tf
            proton.auto.tfvars.json
          
        /component-staged                 # component folder
            main.tf
            proton.component.variables.tf
            proton.auto.tfvars.json
```

------

# 架构文件
<a name="ag-schema"></a>

作为管理员，当您使用 Open API [数据模型（架构）部分](https://swagger.io/docs/specification/data-models/)为模板包定义参数架构 YAML 文件时， AWS Proton 可以根据您在架构中定义的要求验证参数值输入。

有关格式和可用关键字的更多信息，请参阅 OpenAPI 的 [Schema object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#schemaObject) 部分。

## 环境模板捆绑包的架构要求
<a name="schema-req-env"></a>

您的架构必须遵循 OpenAPI 的 [Data Models (schemas) 部分](https://swagger.io/docs/specification/data-models/)并采用 YAML 格式。它还必须是您的环境模板捆绑包的一部分。

对于您的环境架构，您必须包含设置了格式的标头，以确认您使用了 Open API 的 Data Models (schemas) 部分。在以下环境架构示例中，这些标头出现在前三行中。

必须包含 `environment_input_type` 并使用您提供的名称进行定义。在以下示例中，这是在第 5 行中定义的。通过定义此参数，可以将其与 AWS Proton 环境资源相关联。

要遵循 Open API 架构模型，您必须包含 `types`。在以下示例中，它位于第 6 行。

在 `types` 后面，您必须定义一个 `environment_input_type` 类型。您将环境的输入参数定义为 `environment_input_type` 的属性。您必须包含至少一个属性，其名称至少与架构的关联环境基础设施即代码 (IaC) 文件中列出的一个参数匹配。

创建环境并提供自定义参数值时，会 AWS Proton 使用架构文件进行匹配、验证并将其注入关联的 CloudFormation IaC 文件中的花括号参数中。对于每个属性（参数），提供 `name` 和 `type`。（可选）还提供 `description`、`default` 和 `pattern`。

为以下示例*标准* 环境模板架构定义的参数包括 `vpc_cidr`、`subnet_one_cidr` 和 `subnet_two_cidr`，它们使用 `default` 关键字和默认值。在您使用该环境模板捆绑包架构创建环境时，您可以接受默认值或提供您自己的值。如果参数*没有* 默认值并且作为 `required` 属性（参数）列出，您在创建环境时必须为其提供值。

第二个示例*标准* 环境模板架构列出了 `required` 参数 `my_other_sample_input`。

您可以为两种类型的环境模板创建一个架构。有关更多信息，请参阅 [注册并发布模板](template-create.md)。
+ ***标准* 环境模板**

  在以下示例中，环境输入类型是使用描述和输入属性定义的。此架构示例可以与示[例 3](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-env-cfn-example) 中所示的 AWS Proton CloudFormation IaC 文件一起使用。

  *标准* 环境模板的示例架构：

  ```
  schema:                            # required
    format:                          # required
      openapi: "3.0.0"               # required
    # required              defined by administrator
    environment_input_type: "PublicEnvironmentInput"
    types:                           # required
      # defined by administrator
      PublicEnvironmentInput:
        type: object
        description: "Input properties for my environment"
        properties:
          vpc_cidr:                   # parameter
            type: string
            description: "This CIDR range for your VPC"
            default: 10.0.0.0/16
            pattern: ([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))
          subnet_one_cidr:            # parameter
            type: string
            description: "The CIDR range for subnet one"
            default: 10.0.0.0/24
            pattern: ([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))
          subnet_two_cidr:            # parameter
            type: string
            description: "The CIDR range for subnet one"
            default: 10.0.1.0/24
            pattern: ([0-9]{1,3}\.){3}[0-9]{1,3}($|/(16|24))
  ```

  包含 `required` 参数的*标准* 环境模板的示例架构：

  ```
  schema:                            # required
    format:                          # required
      openapi: "3.0.0"               # required
    # required              defined by administrator
    environment_input_type: "MyEnvironmentInputType"
    types:                           # required
      # defined by administrator
      MyEnvironmentInputType:
        type: object
        description: "Input properties for my environment"
        properties:
          my_sample_input:           # parameter
            type: string
            description: "This is a sample input"
            default: "hello world"
          my_other_sample_input:     # parameter
            type: string
            description: "Another sample input"
          another_optional_input:    # parameter
            type: string
            description: "Another optional input"
            default: "!"
        required:
          - my_other_sample_input
  ```
+ ***客户托管* 环境模板**

  在以下示例中，架构仅包含输出列表，这些输出复制您用于预置*客户托管* 基础设施的 IaC 的输出。您需要将输出值类型仅定义为*字符串*（而*不能* 定义为列表、数组或其他类型）。例如，下一个代码片段显示了外部 CloudFormation 模板的输出部分。它来自于[示例 1](ag-infrastructure-tmp-files-cloudformation.md#ag-env-cfn-example) 中所示的模板。它可用于为根据[示例](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-svc-cfn-example) 4 创建的 AWS Proton Fargate 服务创建外部*客户托管*基础架构。
**重要**  
作为管理员，您必须确保您的预配置和托管基础设施以及所有输出参数都与相关的*客户托管*环境模板兼容。 AWS Proton 无法代表你解释更改，因为这些更改对他们不可见 AWS Proton。不一致会导致失败。

  *客户托管*环境模板的 CloudFormation IaC 文件输出示例：

  ```
  // Cloudformation Template Outputs
  [...]
  Outputs:
    ClusterName:
      Description: The name of the ECS cluster
      Value: !Ref 'ECSCluster'
    ECSTaskExecutionRole:
      Description: The ARN of the ECS role
      Value: !GetAtt 'ECSTaskExecutionRole.Arn'
    VpcId:
      Description: The ID of the VPC that this stack is deployed in
      Value: !Ref 'VPC'
  [...]
  ```

  以下示例显示了相应的 AWS Proton *客户托管*环境模板包的架构。每个输出值定义为一个字符串。

  *客户托管* 环境模板的示例架构：

  ```
  schema:                            # required
    format:                          # required
      openapi: "3.0.0"               # required
    # required              defined by administrator
    environment_input_type: "EnvironmentOutput"
    types:                           # required
      # defined by administrator
      EnvironmentOutput:
        type: object
        description: "Outputs of the environment"
        properties:
          ClusterName:               # parameter
            type: string
            description: "The name of the ECS cluster"
          ECSTaskExecutionRole:      # parameter
            type: string
            description: "The ARN of the ECS role"
          VpcId:                     # parameter
            type: string
            description: "The ID of the VPC that this stack is deployed in"
  [...]
  ```

## 服务模板捆绑包的架构要求
<a name="schema-req-svc"></a>

您的架构必须遵循 OpenAPI 的 [Data Models (schemas) 部分](https://swagger.io/docs/specification/data-models/)并采用 YAML 格式，如以下示例中所示。您必须在服务模板捆绑包中提供架构文件。

在以下服务架构示例中，您必须包含设置了格式的标头。在以下示例中，它位于前三行。这是为了确认您使用了 Open API 的 Data Models (schemas) 部分。

必须包含 `service_input_type` 并使用您提供的名称进行定义。在以下示例中，它位于第 5 行。这会将参数与 AWS Proton 服务资源相关联。

当您使用控制台或 CLI 创建 AWS Proton 服务时，默认情况下会包含服务管道。在您为服务包含服务管道时，您必须包含 `pipeline_input_type` 并具有您提供的名称。在以下示例中，它位于第 7 行。如果您@@ *不**包括 AWS Proton 服务管道，请不要*包含此参数。有关更多信息，请参阅 [注册并发布模板](template-create.md)。

要遵循 Open API 架构模型，您必须在以下示例中包含 `types`，它位于第 9 行。

在 `types` 后面，您必须定义一个 `service_input_type` 类型。您将服务的输入参数定义为 `service_input_type` 的属性。您必须包含至少一个属性，其名称至少与架构的关联服务基础设施即代码 (IaC) 文件中列出的一个参数匹配。

要定义服务管道，您必须在 `service_input_type` 定义下面定义一个 `pipeline_input_type`。如上所述，您必须包含至少一个属性，其名称至少与架构的关联管道 IaC 文件中列出的一个参数匹配。如果您@@ *不**包括 AWS Proton 服务管道，请不要*包含此定义。

作为管理员或开发人员，当您创建服务并提供自定义参数值时，会 AWS Proton 使用架构文件来匹配、验证这些值，并将其注入关联的 CloudFormation IaC 文件的花括号参数中。对于每个属性（参数），提供 `name` 和 `type`。（可选）还提供 `description`、`default` 和 `pattern`。

为示例模式定义的参数包括 `port`、`desired_count`、`task_size` 和 `image`，它们使用 `default` 关键字和默认值。在您使用该服务模板捆绑包架构创建服务时，您可以接受默认值或提供您自己的值。`unique_name` 参数也包含在该示例中，并且*没有* 默认值。它作为 `required` 属性（参数）列出。作为管理员或开发人员，您在创建服务时必须提供 `required` 参数的值。

如果要创建具有服务管道的服务模板，请将 `pipeline_input_type` 包含在架构中。

**包含服务管道的服务的示例 AWS Proton 服务架构文件。**

 此架构示例可以与示例 [4 和示例](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-svc-cfn-example) [5](ag-infrastructure-tmp-files-cloudformation.md#ag-proton-pipeline-cfn-example) 中所示的 AWS Proton IaC 文件一起使用。包含一个服务管道。

```
schema:                            # required
  format:                          # required
    openapi: "3.0.0"               # required
  # required           defined by administrator
  service_input_type: "LoadBalancedServiceInput"
  # only include if including AWS Proton service pipeline, defined by administrator
  pipeline_input_type: "PipelineInputs"

  types:                           # required
    # defined by administrator
    LoadBalancedServiceInput:
      type: object
      description: "Input properties for a loadbalanced Fargate service"
      properties:
        port:                      # parameter
          type: number
          description: "The port to route traffic to"
          default: 80
          minimum: 0
          maximum: 65535
        desired_count:             # parameter
          type: number
          description: "The default number of Fargate tasks you want running"
          default: 1
          minimum: 1
        task_size:                 # parameter
          type: string
          description: "The size of the task you want to run"
          enum: ["x-small", "small", "medium", "large", "x-large"]
          default: "x-small"
        image:                     # parameter
          type: string
          description: "The name/url of the container image"
          default: "public.ecr.aws/z9d2n7e1/nginx:1.19.5"
          minLength: 1
          maxLength: 200
        unique_name:               # parameter
          type: string
          description: "The unique name of your service identifier. This will be used to name your log group, task definition and ECS service"
          minLength: 1
          maxLength: 100
      required:
        - unique_name
    # defined by administrator
    PipelineInputs:
      type: object
      description: "Pipeline input properties"
      properties:
        dockerfile:                # parameter
          type: string
          description: "The location of the Dockerfile to build"
          default: "Dockerfile"
          minLength: 1
          maxLength: 100
        unit_test_command:         # parameter
          type: string
          description: "The command to run to unit test the application code"
          default: "echo 'add your unit test command here'"
          minLength: 1
          maxLength: 200
```

如果要创建没有服务管道的服务模板，请*不要* 将 `pipeline_input_type` 包含在架构中，如以下示例中所示。

***不*包含服务管道的服务的示例 AWS Proton 服务架构文件**

```
schema:                            # required
  format:                          # required
    openapi: "3.0.0"               # required
  # required            defined by administrator  
  service_input_type: "MyServiceInstanceInputType"

  types:                           # required
    # defined by administrator
    MyServiceInstanceInputType:
      type: object
      description: "Service instance input properties"
      required:
        - my_sample_service_instance_required_input
      properties:
        my_sample_service_instance_optional_input:   # parameter
          type: string
          description: "This is a sample input"
          default: "hello world"
        my_sample_service_instance_required_input:   # parameter
          type: string
          description: "Another sample input"
```

# 总结模板文件 AWS Proton
<a name="ag-wrap-up"></a>

在准备环境和服务基础设施即代码 (IaC) 文件及其相应的架构文件后，您必须将它们放置到不同的目录中。您还必须创建一个清单 YAML 文件。清单文件列出了目录中的 IaC 文件、渲染引擎以及用于开发该模板中的 IaC 的模板语言。

**注意**  
也可以独立于模板捆绑包使用清单文件，以作为*直接定义的组件* 的直接输入。在这种情况下，它总是为两者 CloudFormation 和 Terraform 指定一个 IaC 模板文件。有关组件的更多信息，请参阅[AWS Proton 组件](ag-components.md)。

清单文件需要符合以下示例中所示的格式和内容。

**CloudFormation 清单文件格式：**

使用 CloudFormation，您可以列出单个文件。

```
infrastructure:
  templates:
    - file: "cloudformation.yaml"
      rendering_engine: jinja
      template_language: cloudformation
```

**Terraform 清单文件格式：**

通过使用 Terraform，您可以明确列出单个文件，或使用 `*` 通配符列出目录中的每个文件。

**注意**  
通配符仅包含名称以 `.tf` 结尾的文件。将忽略其他文件。

```
infrastructure:
  templates:
    - file: "*"
      rendering_engine: hcl
      template_language: terraform
```

**CodeBuild基于配置的清单文件格式：**

使用 CodeBuild基于基础的配置，您可以指定配置和取消置备 shell 命令。

**注意**  
除了清单以外，您的捆绑包还应包含您的命令依赖的任何文件。

以下示例清单使用 CodeBuild基于配置的资源调配，使用 () 来配置（*部署*）和取消配置 AWS Cloud Development Kit (AWS CDK) （*销毁*AWS CDK）资源。模板捆绑包还应包含 CDK 代码。

在预置期间，AWS Proton 创建一个输入文件，其中包含您在名为 `proton-input.json` 的模板架构中定义的输入参数的值。

```
infrastructure:
  templates:
    - rendering_engine: codebuild
      settings:
        image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
        runtimes:
          nodejs: 16
        provision:
          - npm install
          - npm run build
          - npm run cdk bootstrap
          - npm run cdk deploy -- --require-approval never --outputs-file proton-outputs.json
          - jq 'to_entries | map_values(.value) | add | to_entries | map({key:.key, valueString:.value})' < proton-outputs.json > outputs.json
          - aws proton notify-resource-deployment-status-change --resource-arn $RESOURCE_ARN --status IN_PROGRESS --outputs file://./outputs.json
        deprovision:
          - npm install
          - npm run build
          - npm run cdk destroy
        project_properties:
          VpcConfig:
            VpcId: "{{ environment.inputs.codebuild_vpc_id }}"
            Subnets: "{{ environment.inputs.codebuild_subnets }}"
            SecurityGroupIds: "{{ environment.inputs.codebuild_security_groups }}"
```

为环境或服务模板包设置目录和清单文件后，您可以将这些目录压缩成焦油球，然后将其上传到可以检索它们的亚马逊简单存储服务 (Amazon S3) 存储桶 AWS Proton ，或者上传到[模板同步](ag-template-sync-configs.md) Git 存储库。

当您创建注册的环境或服务模板的次要版本时 AWS Proton，您需要提供指向位于 S3 存储桶中的环境或服务模板包 tar ball 的路径。 AWS Proton 将其与新的模板次要版本一起保存。您可以选择新的模板次要版本来创建或更新环境或服务 AWS Proton。

## 打包环境模板捆绑包
<a name="environment-wrap-up"></a>

您创建的环境模板包有两种类型。 AWS Proton
+ 要为*标准* 环境模板创建环境模板捆绑包，请在目录中放置架构、基础设施即代码 (IaC) 文件和清单文件，如以下环境模板捆绑包目录结构中所示。
+ 要为*客户托管* 环境模板创建环境模板捆绑包，请仅提供架构文件和目录。*不要*包含基础架构目录和文件。 AWS Proton 如果包含基础架构目录和文件，则会引发错误。

有关更多信息，请参阅 [注册并发布模板](template-create.md)。

CloudFormation 环境模板包目录结构：

```
 /schema
   schema.yaml
 /infrastructure
   manifest.yaml
   cloudformation.yaml
```

Terraform 环境模板捆绑包目录结构：

```
 /schema
   schema.yaml
 /infrastructure
   manifest.yaml
   environment.tf
```

## 打包服务模板捆绑包
<a name="service-wrap-up"></a>

要创建服务模板捆绑包，您必须将架构、基础设施即代码 (IaC) 文件和清单文件放置在目录中，如服务模板捆绑包目录结构示例中所示。

如果在您的模板捆绑包中*不* 包含服务管道，则*不要* 包含管道目录和文件，并在创建与该模板捆绑包关联的服务模板时设置 `"pipelineProvisioning": "CUSTOMER_MANAGED"`。

**注意**  
在创建服务模板后，您无法修改 `pipelineProvisioning`。

有关更多信息，请参阅 [注册并发布模板](template-create.md)。

CloudFormation 服务模板包目录结构：

```
 /schema
   schema.yaml
 /instance_infrastructure
   manifest.yaml
   cloudformation.yaml
 /pipeline_infrastructure
   manifest.yaml
   cloudformation.yaml
```

Terraform 服务模板捆绑包目录结构：

```
 /schema
   schema.yaml
 /instance_infrastructure
   manifest.yaml
   instance.tf
 /pipeline_infrastructure
   manifest.yaml
   pipeline.tf
```

# 模板捆绑包注意事项
<a name="template-considerations"></a>


+ **基础设施即代码 (IaC) 文件**

  AWS Proton 审核模板以确定文件格式是否正确。但是， AWS Proton 不检查模板开发、依赖关系和逻辑错误。例如，假设您在服务或环境模板中指定在 CloudFormation IaC 文件中创建 Amazon S3 存储桶。服务是根据这些模板创建的。现在，假设您在某个时候希望删除该服务。如果指定的 S3 存储桶*不*为空且 CloudFormation IaC 文件*未*将其标记为`Retain`在中`DeletionPolicy`， AWS Proton 则服务删除操作将失败。
+ **捆绑包文件大小限制和格式**
  + 可以在[AWS Proton 配额](ag-limits.md)中找到捆绑包文件大小、计数和名称大小限制。
  + 文件的模板捆绑包目录使用 gzip 压缩为 tar 包，并位于 Amazon Simple Storage Service (Amazon S3) 存储桶中。
  + 捆绑包中的每个文件必须是有效的 YAML 格式文件。
+ **S3 存储桶模板捆绑包加密**

  如果您想在 S3 存储桶中对模板包中的敏感数据进行静态加密，请使用 SSE-S3 或 SSE-KMS 密钥 AWS Proton 允许检索这些数据。