

# 使用 EC2 Image Builder 构建经过 Amazon ECS 优化的自定义 AMI
<a name="image-builder-tutorial"></a>

Amazon 建议使用 Amazon ECS 优化型 AMI，因为已经根据运行容器工作负载的要求和建议进行了预配置。有时您可能需要定制您的 AMI 以添加其他软件。您可以使用 EC2 Image Builder 创建、管理和部署您的服务器映像。您保留在账户中创建的自定义映像的所有权。您可以使用 EC2 Image Builder 管道自动执行映像的更新和系统修补，也可以使用独立命令使用您定义的配置资源创建映像。

您可以为映像创建配方。配方包括父映像和任何其他组件。您还可以创建用于分发自定义 AMI 的管道。

您可以为映像创建配方。Image Builder 映像配方是一个文档，用于定义基础映像和要应用于基础映像以生成输出 AMI 映像所需配置的组件。您还可以创建用于分发自定义 AMI 的管道。有关更多信息，请参阅《EC2 Image Builder 用户指南》**中的 [EC2 Image Builder 工作原理](https://docs.amazonaws.cn/imagebuilder/latest/userguide/how-image-builder-works.html)。

建议您在 EC2 Image Builder 中使用以下经过 Amazon ECS 优化的 AMI 之一作为“父映像”：
+ Linux
  + 经 Amazon ECS 优化的 AL2023 x86
  + 经 Amazon ECS 优化的 Amazon Linux 2023（arm64）AMI
  + 经 Amazon ECS 优化的 Amazon Linux 2 内核 5 AMI
  + 经 Amazon ECS 优化的 Amazon Linux 2 x86 AMI
+ Windows
  + 经 Amazon ECS 优化的 Windows 2022 Full x86
  + 经 Amazon ECS 优化的 Windows 2022 Core x86
  + 经 Amazon ECS 优化的 Windows 2019 Full x86
  + 经 Amazon ECS 优化的 Windows 2019 Core x86
  + 经 Amazon ECS 优化的 Windows 2016 Full x86

还建议您选择“使用最新可用的 OS 版本”。管道将对父映像使用语义版本控制，这有助于检测自动安排的作业中的依赖项更新。有关更多信息，请参阅《EC2 Image Builder 用户指南》**中的[语义版本控制](https://docs.amazonaws.cn/imagebuilder/latest/userguide/ibhow-semantic-versioning.html)。

Amazon 使用安全补丁和新的容器代理版本定期更新经 Amazon ECS 优化的 AMI 映像。在映像配方中使用 AMI ID 作为父映像时，您需要定期检查父映像是否有更新。如果有更新，则必须使用更新的 AMI 创建配方的新版本。这样可以确保您的自定义映像包含了最新版本的父映像。有关如何创建工作流以使用新创建的 AMI 自动更新 Amazon ECS 集群中的 EC2 实例的信息，请参阅[如何创建 AMI 固化管道并自动更新 ECS 实例集](https://www.amazonaws.cn/blogs/security/how-to-create-an-ami-hardening-pipeline-and-automate-updates-to-your-ecs-instance-fleet/)。

您还可以指定通过托管 EC2 Image Builder 管道发布的父映像的 Amazon 资源名称（ARN）。Amazon 会定期通过托管管道发布经 Amazon ECS 优化的 AMI 映像。这些映像可公开访问。您必须具有访问映像的正确权限。当您在 Image Builder 配方中使用映像 ARN 而不是 AMI 时，您的管道在每次运行时都会自动使用父映像的最新版本。通过这种方法，无需为每次更新手动创建新的配方版本。

## 清理经 Amazon ECS 优化的 AMI
<a name="cleanup-ecs-optimized-ami"></a>

当使用经 Amazon ECS 优化的 AMI 作为父映像时，您必须清理该映像以防止暂时性问题。经 Amazon ECS 优化的 AMI 已针对 Amazon ECS 代理预先配置，可自动启动并在 Amazon ECS 中注册为容器实例。如果未进行适当清理就将其用作基础映像，可能会导致您的自定义 AMI 出现问题。

要清理映像以备将来使用，请创建一个组件，该组件会运行下面的命令来停止 ecs-init 包和 Docker 进程：

```
sudo systemctl stop ecs
sudo systemctl stop docker
```

移除当前实例中的所有日志文件，以防止在保存映像时保留这些文件。请使用 [EC2 Image Builder 的安全最佳实践](https://docs.amazonaws.cn/imagebuilder/latest/userguide/security-best-practices.html)中的示例脚本来清理实例中的各种文件。

要清除 Amazon ECS 特有的数据，请运行下面的命令：

```
sudo rm -rf /var/log/ecs/*
sudo rm /var/lib/ecs/data/agent.db
```

有关创建经 Amazon ECS 优化的自定义 AMI 的更多信息，请参阅 Amazon 知识中心中的 [How do I create a custom AMI from an Amazon ECS-optimized AMI?](https://forums.aws.csdn.net/knowledge-center/ecs-create-custom-amis/)。

## 将映像 ARN 与基础设施即代码（IaC）结合使用
<a name="infrastructure-as-code-arn"></a>

您可以使用 EC2 Image Builder 控制台、基础设施即代码（例如 Amazon CloudFormation）或 Amazon 开发工具包来配置配方。在配方中指定父映像时，您可以指定 EC2 AMI ID、Image Builder 映像 ARN、Amazon Web Services Marketplace 产品 ID 或容器映像。Amazon 会公开发布经 Amazon ECS 优化的 AMI 的 AMI ID 和 Image Builder 映像 ARN。映像的 ARN 格式如下所示：

```
arn:${Partition}:imagebuilder:${Region}:${Account}:image/${ImageName}/${ImageVersion}
```

`ImageVersion` 具有以下格式。将{{主要}}要、{{次要}}和{{补丁}}替换为最新值。

```
<{{major}}>.<{{minor}}>.<{{patch}}>
```

您可以将 `major`、`minor` 和 `patch` 替换为特定值，也可以使用映像的无版本 ARN，这样您的管道就可以与最新版本的父映像保持同步。无版本 ARN 使用通配符格式“x.x.x”来表示映像版本。通过这种方法，Image Builder 服务能够自动解析为映像的最新版本。使用无版本 ARN 可确保您的参考始终指向可用的最新映像，从而简化在部署中维护最新映像的过程。当使用控制台创建配方时，EC2 Image Builder 会自动识别您的父映像的 ARN。使用 IaC 创建配方时，您必须识别 ARN 并选择所需的映像版本或使用无版本 ARN，以表示最新的可用映像。建议您创建一个自动脚本，以筛选并仅显示符合您标准的映像。以下 Python 脚本显示如何检索经 Amazon ECS 优化的 AMI 的列表。

该脚本接受两个可选参数：`owner` 和 `platform`，其默认值分别为“Amazon”和“Windows”。所有者参数的有效值为：`Self`、`Shared`、`Amazon` 和 `ThirdParty`。平台参数的有效值为 `Windows` 和 `Linux`。例如，如果您在 `owner` 参数设置为 `Amazon` 且 `platform` 设置为 `Linux` 时运行脚本，则脚本会生成 Amazon 发布的映像列表，包括经 Amazon ECS 优化的映像。

```
import boto3
import argparse

def list_images(owner, platform):
    # Create a Boto3 session
    session = boto3.Session()
    
    # Create an EC2 Image Builder client
    client = session.client('imagebuilder')

    # Define the initial request parameters
    request_params = {
        'owner': owner,
        'filters': [
            {
                'name': 'platform',
                'values': [platform]
            }
        ]
    }

    # Initialize the results list
    all_images = []

    # Get the initial response with the first page of results
    response = client.list_images(**request_params)

    # Extract images from the response
    all_images.extend(response['imageVersionList'])

    # While 'nextToken' is present, continue paginating
    while 'nextToken' in response and response['nextToken']:
        # Update the token for the next request
        request_params['nextToken'] = response['nextToken']

        # Get the next page of results
        response = client.list_images(**request_params)

        # Extract images from the response
        all_images.extend(response['imageVersionList'])

    return all_images

def main():
    # Initialize the parser
    parser = argparse.ArgumentParser(description="List AWS images based on owner and platform")
    
    # Add the parameters/arguments
    parser.add_argument("--owner", default="Amazon", help="The owner of the images. Default is 'Amazon'.")
    parser.add_argument("--platform", default="Windows", help="The platform type of the images. Default is 'Windows'.")

    # Parse the arguments
    args = parser.parse_args()

    # Retrieve all images based on the provided owner and platform
    images = list_images(args.owner, args.platform)

    # Print the details of the images
    for image in images:
        print(f"Name: {image['name']}, Version: {image['version']}, ARN: {image['arn']}")

if __name__ == "__main__":
    main()
```

## 将映像 ARN 与 Amazon CloudFormation 结合使用
<a name="arn-with-cloudformation"></a>

Image Builder 映像配方是一种蓝图，它指定了实现输出映像预期配置所需的父映像和组件。您使用 `AWS::ImageBuilder::ImageRecipe` 资源。将 `ParentImage` 值设置为映像 ARN。使用所需映像的无版本 ARN，确保您的管道始终使用最新版本的映像。例如 `arn:aws:imagebuilder:us-east-1:aws:image/amazon-linux-2023-ecs-optimized-x86/x.x.x`。以下 `AWS::ImageBuilder::ImageRecipe` 资源定义使用 Amazon 托管的映像 ARN：

```
ECSRecipe:
    Type: AWS::ImageBuilder::ImageRecipe
    Properties:
      Name: MyRecipe
      Version: '1.0.0'
      Components:
        - ComponentArn: [<The component arns of the image recipe>]
      ParentImage: "arn:aws:imagebuilder:us-east-1:aws:image/amazon-linux-2023-ecs-optimized-x86/x.x.x"
```

有关 [`AWS::ImageBuilder::ImageRecipe`](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagerecipe.html) 资源更多信息，请参阅《Amazon CloudFormation 用户指南》**。

您可以通过设置 `AWS::ImageBuilder::ImagePipeline` 资源的 `Schedule` 属性在管道中自动创建新映像。计划包括启动条件和 cron 表达式。有关更多信息，请参阅《Amazon CloudFormation 用户指南》**中的 [`AWS::ImageBuilder::ImagePipeline`](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-resource-imagebuilder-imagepipeline.html)。

 以下 `AWS::ImageBuilder::ImagePipeline` 示例让管道每天在协调世界时间（UTC）上午 10:00 构建项目。设置以下 `Schedule` 值：
+ 将 `PipelineExecutionStartCondition` 设置为 `EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE`。只有当依赖资源（例如父映像或在语义版本中使用通配符“x”的组件）更新后，才会启动该版本。这样可以确保版本包含这些资源的最新更新。
+ 将 ScheduleExpression 设置为 cron 表达式 `(0 10 * * ? *)`。

```
ECSPipeline:
    Type: AWS::ImageBuilder::ImagePipeline
    Properties:
      Name: my-pipeline
      ImageRecipeArn: <arn of the recipe you created in previous step>
      InfrastructureConfigurationArn: <ARN of the infrastructure configuration associated with this image pipeline>
      Schedule:
        PipelineExecutionStartCondition: EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE
        ScheduleExpression: 'cron(0 10 * * ? *)'
```

## 将映像 ARN 与 Terraform 结合使用
<a name="arn-with-terraform"></a>

在 Terraform 中指定管道的父映像和计划的方法与 Amazon CloudFormation 中的方法一致。您使用 `aws_imagebuilder_image_recipe` 资源。将 `parent_image` 值设置为映像 ARN。使用所需映像的无版本 ARN，确保您的管道始终使用最新版本的映像。有关更多信息，请参阅 Terraform 文档中的 [`aws_imagebuilder_image_recipe`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/imagebuilder_image_recipe#argument-reference)。

在 `aws_imagebuilder_image_pipeline resource` 的调度配置块中，将 `schedule_expression` 参数值设置为您选择的 cron 表达式，以指定管道运行的频率，并将 `pipeline_execution_start_condition` 设置为 `EXPRESSION_MATCH_AND_DEPENDENCY_UPDATES_AVAILABLE`。有关更多信息，请参阅 Terraform 文档中的 [`aws_imagebuilder_image_pipeline`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/imagebuilder_image_pipeline#argument-reference)。