

# Amazon ECS 任务定义应用场景
<a name="use-cases"></a>

了解如何为各种 AWS 服务和功能编写任务定义的更多信息。

根据您的工作负载，需要设置某些任务定义参数。另外，对于 EC2，必须选择专为工作负载设计的特定实例。

**Topics**
+ [适用于 GPU 工作负载的 Amazon ECS 任务定义](ecs-gpu.md)
+ [适用于视频转码工作负载的 Amazon ECS 任务定义](ecs-vt1.md)
+ [适用于 AWS 神经元机器学习工作负载的 Amazon ECS 任务定义](ecs-inference.md)
+ [适用于深度学习实例的 Amazon ECS 任务定义](ecs-dl1.md)
+ [适用于 64 位 ARM 工作负载的 Amazon ECS 任务定义](ecs-arm64.md)
+ [将 Amazon ECS 日志发送到 CloudWatch](using_awslogs.md)
+ [将 Amazon ECS 日志发送到 AWS 服务或 AWS Partner](using_firelens.md)
+ [在 Amazon ECS 中使用非 AWS 容器映像](private-auth.md)
+ [使用容器重启策略重启 Amazon ECS 任务中的单个容器](container-restart-policy.md)
+ [将敏感数据传递给 Amazon ECS 容器](specifying-sensitive-data.md)

# 适用于 GPU 工作负载的 Amazon ECS 任务定义
<a name="ecs-gpu"></a>

当您使用支持 GPU 的容器实例创建集群时，Amazon ECS 支持使用 GPU 的工作负载。使用 p2、p3、p5、g3、g4 和 g5 实例类型的基于 GPU 的 Amazon EC2 容器实例提供对 NVIDIA GPU 的访问权限。有关更多信息，请参阅《Amazon EC2 示例类型指南》中的 [Linux 加速型计算实例](https://docs.aws.amazon.com/ec2/latest/instancetypes/ac.html)**。

Amazon ECS 提供了经 GPU 优化的 AMI，后者附带了预配置的 NVIDIA 内核驱动程序和 Docker GPU 运行时。有关更多信息，请参阅 [经 Amazon ECS 优化的 Linux AMI](ecs-optimized_AMI.md)。

您可以在任务定义中指定多个 GPU，以便在容器级别考虑任务放置。Amazon ECS 将安排支持 GPU 的可用容器实例，并将物理 GPU 固定到正确的容器以获得最佳性能。

支持以下基于 GPU 的 Amazon EC2 实例类型。有关更多信息，请参阅 [Amazon EC2 P2 实例](https://aws.amazon.com/ec2/instance-types/p2/)、[Amazon EC2 P3 实例](https://aws.amazon.com/ec2/instance-types/p3/)、[Amazon EC2 P4d 实例](https://aws.amazon.com/ec2/instance-types/p4/)、[Amazon EC2 P5 实例](https://aws.amazon.com/ec2/instance-types/p5/)、[Amazon EC2 G3 实例](https://aws.amazon.com/ec2/instance-types/g3/)、[Amazon EC2 G4 实例](https://aws.amazon.com/ec2/instance-types/g4/)、[Amazon EC2 G5 实例](https://aws.amazon.com/ec2/instance-types/g5/)、[Amazon EC2 G6 实例](https://aws.amazon.com/ec2/instance-types/g6/)和[Amazon EC2 G6e 实例](https://aws.amazon.com/ec2/instance-types/g6e/)。


|  实例类型  |  GPU  |  GPU 内存（GiB）  |  vCPU  |  内存（GiB）  | 
| --- | --- | --- | --- | --- | 
|  p3.2xlarge  |  1  |  16  |  8  |  61  | 
|  p3.8xlarge  |  4  |  64  |  32  |  244  | 
|  p3.16xlarge  |  8  |  128  |  64  |  488  | 
|  p3dn.24xlarge  |  8  |  256  |  96  |  768  | 
|  p4d.24xlarge  | 8 | 320 | 96 | 1152 | 
| p5.48xlarge | 8 | 640 | 192 | 2048 | 
|  g3s.xlarge  |  1  |  8  |  4  |  30.5  | 
|  g3.4xlarge  |  1  |  8  |  16  |  122  | 
|  g3.8xlarge  |  2  |  16  |  32  |  244  | 
|  g3.16xlarge  |  4  |  32  |  64  |  488  | 
|  g4dn.xlarge  |  1  |  16  |  4  |  16  | 
|  g4dn.2xlarge  |  1  |  16  |  8  |  32  | 
|  g4dn.4xlarge  |  1  |  16  |  16  |  64  | 
|  g4dn.8xlarge  |  1  |  16  |  32  |  128  | 
|  g4dn.12xlarge  |  4  |  64  |  48  |  192  | 
|  g4dn.16xlarge  |  1  |  16  |  64  |  256  | 
|  g5.xlarge  |  1  |  24  |  4  |  16  | 
|  g5.2xlarge  |  1  |  24  |  8  |  32  | 
|  g5.4xlarge  |  1  |  24  |  16  |  64  | 
|  g5.8xlarge  |  1  |  24  |  32  |  128  | 
|  g5.16xlarge  |  1  |  24  |  64  |  256  | 
|  g5.12xlarge  |  4  |  96  |  48  |  192  | 
|  g5.24xlarge  |  4  |  96  |  96  |  384  | 
|  g5.48xlarge  |  8  |  192  |  192  |  768  | 
| g6.xlarge | 1 | 24 | 4 | 16 | 
| g6.2xlarge | 1 | 24 | 8 | 32 | 
| g6.4xlarge | 1 | 24 | 16 | 64 | 
| g6.8xlarge | 1 | 24 | 32 | 128 | 
| g6.16.xlarge | 1 | 24 | 64 | 256 | 
| g6.12xlarge | 4 | 96 | 48 | 192 | 
| g6.24xlarge | 4 | 96 | 96 | 384 | 
| g6.48xlarge | 8 | 192 | 192 | 768 | 
| g6.metal | 8 | 192 | 192 | 768 | 
| gr6.4xlarge | 1 | 24 | 16 | 128 | 
| g6e.xlarge | 1 | 48 | 4 | 32 | 
| g6e.2xlarge | 1 | 48 | 8 | 64 | 
| g6e.4xlarge | 1 | 48 | 16 | 128 | 
| g6e.8xlarge | 1 | 48 | 32 | 256 | 
| g6e16.xlarge | 1 | 48 | 64 | 512 | 
| g6e12.xlarge | 4 | 192 | 48 | 384 | 
| g6e24.xlarge | 4 | 192 | 96 | 768 | 
| g6e48.xlarge | 8 | 384 | 192 | 1536 | 
| gr6.8xlarge | 1 | 24 | 32 | 256 | 

您可以通过查询 AWS Systems Manager Parameter Store API 来检索经 Amazon EKS 优化的 AMI 的亚马逊机器映像（AMI）ID。使用此参数，您无需手动查找经 Amazon ECS 优化的 AMI ID。有关 Systems Manager Parameter Store API 的更多信息，请参阅 [GetParameter](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_GetParameter.html)。您使用的用户必须具有 `ssm:GetParameter` IAM 权限才能检索经 Amazon ECS 优化的 AMI 元数据。

```
aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended --region us-east-1
```

# 将 GPU 与 Amazon ECS 托管实例结合使用
<a name="managed-instances-gpu"></a>

Amazon ECS 托管实例通过以下 Amazon EC2 实例类型对机器学习、高性能计算和视频处理等工作负载支持 GPU 加速计算。有关 Amazon ECS 托管实例支持的实例类型的更多信息，请参阅[Amazon ECS 托管实例实例类型](managed-instances-instance-types.md)。

下面是 Amazon ECS 托管实例上支持的部分基于 GPU 的实例类型：
+ `g4dn`：由 NVIDIA T4 GPUs 提供支持，适用于机器学习推理、计算机视觉和图形密集型应用程序。
+ `g5`：由 NVIDIA A10G GPUs 提供支持，为图形密集型应用程序和机器学习工作负载提供更高性能。
+ `p3`：由 NVIDIA V100 GPUs 提供支持，专为高性能计算和深度学习训练而设计。
+ `p4d`：由 NVIDIA A100 GPUs 提供支持，为机器学习训练和高性能计算提供最高性能。

当您将支持 GPU 的实例类型与 Amazon ECS 托管实例一起使用时，NVIDIA 驱动程序和 CUDA 工具包已预先安装在实例上，从而更轻松地运行 GPU 加速的工作负载。

## 选择支持 GPU 的实例
<a name="managed-instances-gpu-instance-selection"></a>

要为您的 Amazon ECS 托管实例工作负载选择选择 GPU 的实例类型，请使用容量提供程序的启动模板中的 `instanceRequirements` 对象。以下代码段展示了可用于选择支持 GPU 的实例的属性。

```
{
  "instanceRequirements": {
    "acceleratorTypes": "gpu",
    "acceleratorCount": 1,
    "acceleratorManufacturers": ["nvidia"]
  }
}
```

以下代码段展示了可用于在启动模板中指定支持 GPU 的实例类型的属性。

```
{
  "instanceRequirements": {
    "allowedInstanceTypes": ["g4dn.xlarge", "p4de.24xlarge"]
  }
}
```

## 支持 GPU 的容器映像
<a name="managed-instances-gpu-container-images"></a>

要在容器中使用 GPU，您需要使用包含必要 GPU 库和工具的容器映像。NVIDIA 提供了一些预构建的容器映像，您可以将其用作 GPU 工作负载的基础，包括：
+ `nvidia:cuda`：包含用于 GPU 计算的 CUDA 工具包的基础映像。
+ `tensorflow/tensorflow:latest-gpu`：支持 GPU 的 TensorFlow。
+ `pytorch/pytorch:latest-cuda`：支持 GPU 的 PyTorch。

有关涉及使用 GPU 的 Amazon ECS 托管实例的 Amazon ECS 任务定义示例，请参阅[在 Amazon ECS 任务定义中指定 GPU 数](ecs-gpu-specifying.md)。

## 注意事项
<a name="gpu-considerations"></a>

**注意**  
已弃用对 g2 实例系列类型的支持。  
Amazon ECS 经 GPU 优化的 AMI 的 `20230912` 版本之前的版本仅支持 p2 实例系列类型。如果您需要继续使用 p2 实例，请参阅 [如果您需要 P2 实例该怎么办](#p2-instance)。  
这两种实例系列类型上的 NVIDIA/CUDA 驱动程序的就地更新将导致 GPU 工作负载出现潜在故障。

开始在 Amazon ECS 上使用 GPU 之前，我们建议您考虑以下事项。
+ 您的集群可以包含 GPU 和非 GPU 容器实例的组合。
+ 您可以在外部实例上运行 GPU 工作负载。当向集群注册外部实例时，请确保安装脚本中包含 `--enable-gpu` 标记。有关更多信息，请参阅 [将外部实例注册到 Amazon ECS 集群](ecs-anywhere-registration.md)。
+ 您必须在代理配置文件中将 `ECS_ENABLE_GPU_SUPPORT` 设置为 `true`。有关更多信息，请参阅 [Amazon ECS 容器代理配置](ecs-agent-config.md)。
+ 在运行任务或创建服务时，您可以在配置任务放置约束时使用实例类型属性，以确定要在其上启动任务的容器实例。通过这样做，您可以更有效地使用您的资源。有关更多信息，请参阅 [Amazon ECS 如何将任务放置在容器实例上](task-placement.md)。

  以下示例在您的默认集群中的 `g4dn.xlarge` 容器实例上启动一个任务。

  ```
  aws ecs run-task --cluster default --task-definition ecs-gpu-task-def \
       --placement-constraints type=memberOf,expression="attribute:ecs.instance-type ==  g4dn.xlarge" --region us-east-2
  ```
+ 对于在容器定义中指定了 GPU 资源要求的每个容器，Amazon ECS 将容器运行时设置为 NVIDIA 容器运行时。
+ NVIDIA 容器运行时需要在容器中设置一些环境变量才能工作。有关这些环境变量的列表，请参阅[使用 Docker 的专用配置](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/docker-specialized.html?highlight=environment%20variable)。Amazon ECS 设置 `NVIDIA_VISIBLE_DEVICES` 环境变量值设置为 Amazon ECS 分配给容器的 GPU 设备 ID 列表。对于其他必需的环境变量，Amazon ECS 不会对其进行设置。因此，请确保容器映像对其进行设置，或者在容器定义中对其进行设置。
+ `20230929` 版本和更高版本的 Amazon ECS 经 GPU 优化的 AMI 支持 p5 实例类型系列。
+ `20230913` 版本和更高版本的 Amazon ECS 经 GPU 优化的 AMI 支持 g4 实例类型系列。有关更多信息，请参阅 [经 Amazon ECS 优化的 Linux AMI](ecs-optimized_AMI.md)。它在 Amazon ECS 控制台的“创建集群”工作流中不受支持。要使用这些实例类型，您必须使用 Amazon EC2 控制台、AWS CLI 或 API 并手动将实例注册到您的集群。
+ p4d.24xlarge 实例类型仅适用于 CUDA 11 或更高版本。
+ Amazon ECS 经 GPU 优化的 AMI 启用了 IPv6，这会导致使用 `yum` 时出现问题。可以通过配置 `yum` 将 IPv4 与以下命令结合使用。

  ```
  echo "ip_resolve=4" >> /etc/yum.conf
  ```
+  当您构建不使用 NVIDIA/CUDA 基础映像的容器映像时，必须设置 `NVIDIA_DRIVER_CAPABILITIES` 容器运行时变量设置为以下值之一：
  + `utility,compute`
  + `all`

  有关如何设置变量的信息，请参阅 NVIDIA 网站上的[控制 NVIDIA 容器运行时](https://sarus.readthedocs.io/en/stable/user/custom-cuda-images.html#controlling-the-nvidia-container-runtime)
+ Windows 容器不支持 GPU。

# 启动适用于 Amazon ECS 的 GPU 容器实例
<a name="gpu-launch"></a>

要在 Amazon EC2 上的 Amazon ECS 上使用 GPU 实例，您需要创建启动模板、用户数据文件，然后启动实例。

然后，您可以运行使用为 GPU 配置的任务定义的任务。

## 使用启动模板
<a name="gpu-launch-template"></a>

您可以创建启动模板。
+ 创建将经 Amazon ECS 优化的 GPU AMI ID 用于 AMI 的启动模板。有关如何创建启动模板的信息，请参阅《Amazon EC2 用户指南》中的[使用您定义的参数创建新启动模板](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-launch-template.html#create-launch-template-define-parameters)**。

  将上一步中的 AMI ID 用于**亚马逊机器映像**。有关如何使用 Systems Manager 参数指定 AMI ID 的信息，请参阅《Amazon EC2 用户指南》中的[在启动模板中指定 Systems Manager 参数](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/create-launch-template.html#use-an-ssm-parameter-instead-of-an-ami-id)**。

  将以下各项添加到启动模板中的**用户数据**中。将 *cluster-name* 替换为您集群的名称。

  ```
  #!/bin/bash
  echo ECS_CLUSTER=cluster-name >> /etc/ecs/ecs.config;
  echo ECS_ENABLE_GPU_SUPPORT=true >> /etc/ecs/ecs.config
  ```

## 使用 AWS CLI
<a name="gpu-launch-cli"></a>

您可以使用 AWS CLI 启动容器实例。

1. 创建名为 `userdata.toml` 的文件。此文件会用于实例用户数据。将 *cluster-name* 替换为您集群的名称。

   ```
   #!/bin/bash
   echo ECS_CLUSTER=cluster-name >> /etc/ecs/ecs.config;
   echo ECS_ENABLE_GPU_SUPPORT=true >> /etc/ecs/ecs.config
   ```

1. 运行以下命令以获取 GPU AMI ID。您将在以下步骤中使用此 ID。

   ```
   aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/gpu/recommended --region us-east-1
   ```

1. 运行以下命令来启动 GPU 实例。请记得替换以下参数：
   + 用您的实例将在其中启动的私有或公有子网的 ID 替换*子网*。
   + 将 *gpu\$1ami* 替换为上一步中的 AMI ID。
   + 将 *t3.large* 替换为您要使用的实例类型。
   + 将 *region* 替换为区域代码。

   ```
   aws ec2 run-instances --key-name ecs-gpu-example \
      --subnet-id subnet \
      --image-id gpu_ami \
      --instance-type t3.large \
      --region region \
      --tag-specifications 'ResourceType=instance,Tags=[{Key=GPU,Value=example}]' \
      --user-data file://userdata.toml \
      --iam-instance-profile Name=ecsInstanceRole
   ```

1. 运行以下命令，以验证容器实例是否注册到集群。在运行此命令时，请记得替换以下参数：
   + 将 *cluster* 替换为您的集群名称。
   + 将 *region* 替换为区域代码。

   ```
   aws ecs list-container-instances --cluster cluster-name --region region
   ```

# 在 Amazon ECS 任务定义中指定 GPU 数
<a name="ecs-gpu-specifying"></a>

要在容器实例和 Docker GPU 运行时上使用 GPU，请确保在任务定义中指定容器所需的 GPU 数量。由于已放置支持 GPU 的容器，Amazon ECS 容器代理会将所需数量的物理 GPU 固定到相应的容器中。为某个任务中的所有容器预留的 GPU 的数量不能超过该任务在其上启动的容器实例的可用 GPU 的数量。有关更多信息，请参阅 [使用控制台创建 Amazon ECS 任务定义](create-task-definition.md)。

**重要**  
如果任务定义中未指定 GPU 要求，则任务将使用原定设置 Docker 运行时。

下面显示了任务定义中的 GPU 要求的 JSON 格式：

```
{
  "containerDefinitions": [
     {
        ...
        "resourceRequirements" : [
            {
               "type" : "GPU", 
               "value" : "2"
            }
        ],
     },
...
}
```

以下示例演示了指定 GPU 要求的 Docker 容器的语法。此容器使用两个 GPU，运行 `nvidia-smi` 实用程序，然后退出。

```
{
  "containerDefinitions": [
    {
      "memory": 80,
      "essential": true,
      "name": "gpu",
      "image": "nvidia/cuda:11.0.3-base",
      "resourceRequirements": [
         {
           "type":"GPU",
           "value": "2"
         }
      ],
      "command": [
        "sh",
        "-c",
        "nvidia-smi"
      ],
      "cpu": 100
    }
  ],
  "family": "example-ecs-gpu"
}
```

以下示例任务定义展示了一个打印可用 GPU 数量的 TensorFlow 容器。该任务在 Amazon ECS 托管实例上运行，需要一个 GPU，并使用 `g4dn.xlarge` 实例。

```
{
  "family": "tensorflow-gpu",
  "networkMode": "awsvpc",
  "executionRoleArn": "arn:aws:iam::account-id:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "tensorflow",
      "image": "tensorflow/tensorflow:latest-gpu",
      "essential": true,
      "command": [
        "python",
        "-c",
        "import tensorflow as tf; print('Num GPUs Available: ', len(tf.config.list_physical_devices('GPU')))"
      ],
      "resourceRequirements": [
        {
          "type": "GPU",
          "value": "1"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/tensorflow-gpu",
          "awslogs-region": "region",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ],
  "requiresCompatibilities": [
    "MANAGED_INSTANCES"
  ],
  "cpu": "4096",
  "memory": "8192",
}
```

## 共享 GPU
<a name="share-gpu"></a>

当想要共享 GPU 时，需要进行以下配置。

1. 从任务定义中移除 GPU 资源要求，以便 Amazon ECS 不会预留任何应共享的 GPU。

1. 当想要共享 GPU 时，请将以下用户数据添加到您的实例。这将使 nvidia 成为容器实例上的默认 Docker 容器运行时，以便所有 Amazon ECS 容器都可以使用 GPU。有关更多信息，请参阅《Amazon EC2 用户指南》**中的[在启动包含用户数据输入的 EC2 实例时运行命令](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html)。

   ```
   const userData = ec2.UserData.forLinux();
    userData.addCommands(
    'sudo rm /etc/sysconfig/docker',
    'echo DAEMON_MAXFILES=1048576 | sudo tee -a /etc/sysconfig/docker',
    'echo OPTIONS="--default-ulimit nofile=32768:65536 --default-runtime nvidia" | sudo tee -a /etc/sysconfig/docker',
    'echo DAEMON_PIDFILE_TIMEOUT=10 | sudo tee -a /etc/sysconfig/docker',
    'sudo systemctl restart docker',
   );
   ```

1. 在容器上设置 `NVIDIA_VISIBLE_DEVICES` 环境变量。您可以通过在任务定义中指定环境变量来执行此操作。有关有效值的信息，请参阅 NVIDIA 文档网站上的 [GPU Enumeration](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/docker-specialized.html#gpu-enumeration)。

## 如果您需要 P2 实例该怎么办
<a name="p2-instance"></a>

如果您需要使用 P2 实例，可以使用以下选项之一继续使用实例。

您必须修改这两个选项的实例用户数据。有关更多信息，请参阅《Amazon EC2 用户指南》**中的[在启动包含用户数据输入的 EC2 实例时运行命令](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html)。

**使用最新支持的经 GPU 优化的 AMI**

您可以使用经 GPU 优化的 AMI 的 `20230906` 版本，并将以下内容添加到实例用户数据中。

将 cluster-name 替换为您集群的名称。

```
#!/bin/bash
echo "exclude=*nvidia* *cuda*" >> /etc/yum.conf
echo "ECS_CLUSTER=cluster-name" >> /etc/ecs/ecs.config
```

**使用最新的经 GPU 优化的 AMI，并更新用户数据**

您可在实例用户数据中添加以下内容。这将卸载 Nvidia 535/Cuda12.2 驱动程序，然后安装 Nvidia 470/Cuda11.4 驱动程序并修复该版本。

```
#!/bin/bash
yum remove -y cuda-toolkit* nvidia-driver-latest-dkms*
tmpfile=$(mktemp)
cat >$tmpfile <<EOF
[amzn2-nvidia]
name=Amazon Linux 2 Nvidia repository
mirrorlist=\$awsproto://\$amazonlinux.\$awsregion.\$awsdomain/\$releasever/amzn2-nvidia/latest/\$basearch/mirror.list
priority=20
gpgcheck=1
gpgkey=https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/7fa2af80.pub
enabled=1
exclude=libglvnd-*
EOF

mv $tmpfile /etc/yum.repos.d/amzn2-nvidia-tmp.repo
yum install -y system-release-nvidia cuda-toolkit-11-4 nvidia-driver-latest-dkms-470.182.03
yum install -y libnvidia-container-1.4.0 libnvidia-container-tools-1.4.0 nvidia-container-runtime-hook-1.4.0 docker-runtime-nvidia-1

echo "exclude=*nvidia* *cuda*" >> /etc/yum.conf
nvidia-smi
```

**创建您自己的兼容 P2 且经过 GPU 优化的 AMI**

您可以创建与 P2 实例兼容的自定义 Amazon ECS GPU 优化型 AMI，然后使用 AMI 启动 P2 实例。

1. 运行以下命令以克隆 `amazon-ecs-ami repo`。

   ```
   git clone https://github.com/aws/amazon-ecs-ami
   ```

1. 在 `release.auto.pkrvars.hcl` 或 `overrides.auto.pkrvars.hcl` 中设置所需的 Amazon ECS 代理和源 Amazon Linux AMI 版本。

1. 运行以下命令来构建兼容 P2 的私有 EC2 AMI。

   将“区域”替换为“区域”和“实例区域”。

   ```
   REGION=region make al2keplergpu
   ```

1. 使用包含以下实例用户数据的 AMI 连接到 Amazon ECS 集群。

   将 cluster-name 替换为您集群的名称。

   ```
   #!/bin/bash
   echo "ECS_CLUSTER=cluster-name" >> /etc/ecs/ecs.config
   ```

# 适用于视频转码工作负载的 Amazon ECS 任务定义
<a name="ecs-vt1"></a>

要在 Amazon ECS 上使用视频转码工作负载，请注册 [Amazon EC2 VT1](https://aws.amazon.com/ec2/instance-types/vt1/) 实例。注册这些实例后，您可以将实时和预渲染的视频转码工作负载作为 Amazon ECS 上的任务运行。Amazon EC2 VT1 实例使用 Xilinx U30 媒体转码卡来加速实时和预渲染的视频转码工作负载。

**注意**  
有关如何在 Amazon ECS 以外的容器中运行视频转码工作负载的说明，请参阅 [Xilinx 文档](https://xilinx.github.io/video-sdk/v1.5/container_setup.html#working-with-docker-vt1)。

## 注意事项
<a name="ecs-vt1-considerations"></a>

在 Amazon ECS 上开始部署 VT1 之前，请注意以下事项：
+ 您的集群可以包含 VT1 和非 VT1 实例的组合。
+ 您需要一个 Linux 应用程序，该应用程序使用具有加速 AVC（H.264）和 HEVC（H.265）编解码器的 Xilinx U30 媒体转码卡。
**重要**  
使用其他编解码器的应用程序可能不会在 VT1 实例上获得性能提升。
+ U30 卡上只能运行一个转码任务。每张卡都有两个与之关联的设备。您可以运行的转码任务数量与每个 VT1 实例的卡的数量一样。
+ 在创建服务或运行独立任务时，您可以在配置任务放置约束时使用实例类型属性。这样可以确保在您指定的容器实例上启动任务。这样做有助于确保您有效地使用资源，并确保视频转码工作负载任务在 VT1 实例上。有关更多信息，请参阅 [Amazon ECS 如何将任务放置在容器实例上](task-placement.md)。

  在以下示例中，任务在您的 `default` 集群上的 `vt1.3xlarge` 实例上运行。

  ```
  aws ecs run-task \
       --cluster default \
       --task-definition vt1-3xlarge-xffmpeg-processor \
       --placement-constraints type=memberOf,expression="attribute:ecs.instance-type == vt1.3xlarge"
  ```
+ 您可以将容器配置为使用主机容器实例上可用的特定 U30 卡。您可以通过使用 `linuxParameters` 参数并指定设备详细信息来执行此操作。有关更多信息，请参阅 [任务定义要求](#ecs-vt1-requirements)。

## 使用 VT1 AMI
<a name="ecs-vt1-ami"></a>

您有两种选择可以在 Amazon EC2 上运行适用于 Amazon ECS 容器实例的 AMI。第一个选项是在 AWS Marketplace 上使用 Xilinx 官方 AMI。第二种选择是从示例存储库构建自己的 AMI。
+ [Xilinx 在 AWS Marketplace 上提供 AMI](https://aws.amazon.com/marketplace/pp/prodview-phvk6d4mq3hh6)。
+ Amazon ECS 提供了一个示例存储库，您可以使用该存储库为视频转码工作负载构建 AMI。该 AMI 随附 Xilinx U30 驱动程序。您可以在 [Github](https://github.com/aws-samples/aws-vt-baseami-pipeline) 上找到包含 Packer 脚本的存储库。有关 Packer 的更多信息，请参阅 [Packer 文档](https://developer.hashicorp.com/packer/docs)。

## 任务定义要求
<a name="ecs-vt1-requirements"></a>

要在 Amazon ECS 上运行视频转码容器，您的任务定义必须包含使用加速 H.264/AVC 和 H.265/HEVC 编解码器的视频转码应用程序。您可以按照 [Xilinx Github](https://xilinx.github.io/video-sdk/v1.5/container_setup.html#creating-a-docker-image-for-vt1-usage) 上的步骤来构建容器映像。

任务定义必须特定于实例类型。实例类型为 3xlarge、6xlarge 和 24xlarge。您必须将容器配置为使用主机容器实例上可用的特定 Xilinx U30 设备。您还可以使用 `linuxParameters` 参数执行此操作。下表详细介绍了特定于每种实例类型的卡和设备 SoC。


| 实例类型 | vCPU | RAM (GiB) | U30 加速器卡 | 可寻址的 XCU30 SoC 设备 | 设备路径 | 
| --- | --- | --- | --- | --- | --- | 
| vt1.3xlarge | 12 | 24 | 1 | 2 | /dev/dri/renderD128,/dev/dri/renderD129 | 
| vt1.6xlarge | 24 | 48 | 2 | 4 | /dev/dri/renderD128,/dev/dri/renderD129,/dev/dri/renderD130,/dev/dri/renderD131 | 
| vt1.24xlarge | 96 | 182 | 8 | 16 | /dev/dri/renderD128,/dev/dri/renderD129,/dev/dri/renderD130,/dev/dri/renderD131,/dev/dri/renderD132,/dev/dri/renderD133,/dev/dri/renderD134,/dev/dri/renderD135,/dev/dri/renderD136,/dev/dri/renderD137,/dev/dri/renderD138,/dev/dri/renderD139,/dev/dri/renderD140,/dev/dri/renderD141,/dev/dri/renderD142,/dev/dri/renderD143 | 

**重要**  
如果任务定义列出了 EC2 实例没有的设备，则任务将无法运行。当任务失败时，`stoppedReason` 中将出现以下错误消息：`CannotStartContainerError: Error response from daemon: error gathering device information while adding custom device "/dev/dri/renderD130": no such file or directory`。

# 在 Amazon ECS 任务定义中指定视频转码
<a name="task-def-video-transcode"></a>

以下示例中，提供了用于 Amazon EC2 上 Linux 容器的任务定义的语法。此任务定义适用于按照 [Xilinx 文档](https://xilinx.github.io/video-sdk/v1.5/container_setup.html#creating-a-docker-image-for-vt1-usage)中提供的过程构建的容器映像。如果使用此示例，请将 `image` 替换为您自己的映像，然后将视频文件复制到 `/home/ec2-user` 目录中的实例。

------
#### [ vt1.3xlarge ]

1. 使用以下内容创建名为 `vt1-3xlarge-ffmpeg-linux.json` 的文本文件。

   ```
   {
       "family": "vt1-3xlarge-xffmpeg-processor",
       "requiresCompatibilities": ["EC2"],
       "placementConstraints": [
           {
               "type": "memberOf",
               "expression": "attribute:ecs.os-type == linux"
           },
           {
               "type": "memberOf",
               "expression": "attribute:ecs.instance-type == vt1.3xlarge"
           }
       ],
       "containerDefinitions": [
           {
               "entryPoint": [
                   "/bin/bash",
                   "-c"
               ],
               "command": ["/video/ecs_ffmpeg_wrapper.sh"],
               "linuxParameters": {
                   "devices": [
                       {
                           "containerPath": "/dev/dri/renderD128",
                           "hostPath": "/dev/dri/renderD128",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD129",
                           "hostPath": "/dev/dri/renderD129",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       }
                   ]
               },
               "mountPoints": [
                   {
                       "containerPath": "/video",
                       "sourceVolume": "video_file"
                   }
               ],
               "cpu": 0,
               "memory": 12000,
               "image": "0123456789012.dkr.ecr.us-west-2.amazonaws.com/aws/xilinx-xffmpeg",
               "essential": true,
               "name": "xilinix-xffmpeg"
           }
       ],
       "volumes": [
           {
               "name": "video_file",
               "host": {"sourcePath": "/home/ec2-user"}
           }
       ]
   }
   ```

1. 注册任务定义。

   ```
   aws ecs register-task-definition --family vt1-3xlarge-xffmpeg-processor --cli-input-json file://vt1-3xlarge-xffmpeg-linux.json --region us-east-1
   ```

------
#### [ vt1.6xlarge ]

1. 使用以下内容创建名为 `vt1-6xlarge-ffmpeg-linux.json` 的文本文件。

   ```
   {
       "family": "vt1-6xlarge-xffmpeg-processor",
       "requiresCompatibilities": ["EC2"],
       "placementConstraints": [
           {
               "type": "memberOf",
               "expression": "attribute:ecs.os-type == linux"
           },
           {
               "type": "memberOf",
               "expression": "attribute:ecs.instance-type == vt1.6xlarge"
           }
       ],
       "containerDefinitions": [
           {
               "entryPoint": [
                   "/bin/bash",
                   "-c"
               ],
               "command": ["/video/ecs_ffmpeg_wrapper.sh"],
               "linuxParameters": {
                   "devices": [
                       {
                           "containerPath": "/dev/dri/renderD128",
                           "hostPath": "/dev/dri/renderD128",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD129",
                           "hostPath": "/dev/dri/renderD129",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD130",
                           "hostPath": "/dev/dri/renderD130",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD131",
                           "hostPath": "/dev/dri/renderD131",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       }
                   ]
               },
               "mountPoints": [
                   {
                       "containerPath": "/video",
                       "sourceVolume": "video_file"
                   }
               ],
               "cpu": 0,
               "memory": 12000,
               "image": "0123456789012.dkr.ecr.us-west-2.amazonaws.com/aws/xilinx-xffmpeg",
               "essential": true,
               "name": "xilinix-xffmpeg"
           }
       ],
       "volumes": [
           {
               "name": "video_file",
               "host": {"sourcePath": "/home/ec2-user"}
           }
       ]
   }
   ```

1. 注册任务定义。

   ```
   aws ecs register-task-definition --family vt1-6xlarge-xffmpeg-processor --cli-input-json file://vt1-6xlarge-xffmpeg-linux.json --region us-east-1
   ```

------
#### [ vt1.24xlarge ]

1. 使用以下内容创建名为 `vt1-24xlarge-ffmpeg-linux.json` 的文本文件。

   ```
   {
       "family": "vt1-24xlarge-xffmpeg-processor",
       "requiresCompatibilities": ["EC2"],
       "placementConstraints": [
           {
               "type": "memberOf",
               "expression": "attribute:ecs.os-type == linux"
           },
           {
               "type": "memberOf",
               "expression": "attribute:ecs.instance-type == vt1.24xlarge"
           }
       ],
       "containerDefinitions": [
           {
               "entryPoint": [
                   "/bin/bash",
                   "-c"
               ],
               "command": ["/video/ecs_ffmpeg_wrapper.sh"],
               "linuxParameters": {
                   "devices": [
                       {
                           "containerPath": "/dev/dri/renderD128",
                           "hostPath": "/dev/dri/renderD128",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD129",
                           "hostPath": "/dev/dri/renderD129",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD130",
                           "hostPath": "/dev/dri/renderD130",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD131",
                           "hostPath": "/dev/dri/renderD131",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD132",
                           "hostPath": "/dev/dri/renderD132",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD133",
                           "hostPath": "/dev/dri/renderD133",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD134",
                           "hostPath": "/dev/dri/renderD134",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD135",
                           "hostPath": "/dev/dri/renderD135",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD136",
                           "hostPath": "/dev/dri/renderD136",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD137",
                           "hostPath": "/dev/dri/renderD137",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD138",
                           "hostPath": "/dev/dri/renderD138",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD139",
                           "hostPath": "/dev/dri/renderD139",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD140",
                           "hostPath": "/dev/dri/renderD140",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD141",
                           "hostPath": "/dev/dri/renderD141",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD142",
                           "hostPath": "/dev/dri/renderD142",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       },
                       {
                           "containerPath": "/dev/dri/renderD143",
                           "hostPath": "/dev/dri/renderD143",
                           "permissions": [
                               "read",
                               "write"
                           ]
                       }
                   ]
               },
               "mountPoints": [
                   {
                       "containerPath": "/video",
                       "sourceVolume": "video_file"
                   }
               ],
               "cpu": 0,
               "memory": 12000,
               "image": "0123456789012.dkr.ecr.us-west-2.amazonaws.com/aws/xilinx-xffmpeg",
               "essential": true,
               "name": "xilinix-xffmpeg"
           }
       ],
       "volumes": [
           {
               "name": "video_file",
               "host": {"sourcePath": "/home/ec2-user"}
           }
       ]
   }
   ```

1. 注册任务定义。

   ```
   aws ecs register-task-definition --family vt1-24xlarge-xffmpeg-processor --cli-input-json file://vt1-24xlarge-xffmpeg-linux.json --region us-east-1
   ```

------

# 适用于 AWS 神经元机器学习工作负载的 Amazon ECS 任务定义
<a name="ecs-inference"></a>

您可以将 [Amazon EC2 Trn1](https://aws.amazon.com/ec2/instance-types/trn1/)、[Amazon EC2 Trn2](https://aws.amazon.com/ec2/instance-types/trn2/)、[Amazon EC2 Inf1](https://aws.amazon.com/ec2/instance-types/inf1/) 和 [Amazon EC2 Inf2](https://aws.amazon.com/ec2/instance-types/inf2/) 实例注册到您的集群，以执行机器学习工作负载。

Amazon EC2 Trn1 和 Trn2 实例由 [AWS Trainium](https://aws.amazon.com/ai/machine-learning/trainium/) 芯片提供技术支持。这些实例在云中为机器学习提供高性能的低成本训练。您可以在 Trn1 或 Trn2 实例上使用具有 AWS Neuron 的机器学习框架训练机器学习推理模型。然后，您可以在 Inf1 实例或 Inf2 实例上运行模型来利用 AWS Inferentia 芯片的加速。

Amazon EC2 Inf1 实例和 Inf2 实例由 [AWS Inferentia](https://aws.amazon.com/ai/machine-learning/inferentia/) 芯片提供支持，，它们可在云中提供高性能和最低成本的推理。

机器学习模型使用 [AWS Neuron](https://aws.amazon.com/ai/machine-learning/neuron/) 部署到容器中，它是专门的软件开发工具包（SDK）。SDL 由编译器、运行时和分析工具组成，可用于优化 AWS 机器学习芯片的机器学习性能。AWSNeuron 支持常用的机器学习框架，例如 TensorFlow、PyTorch 和 Apache MXNet。

## 注意事项
<a name="ecs-inference-considerations"></a>

在 Amazon ECS 上开始部署 Neuron 之前，请注意以下事项：
+ 您的集群可以包含 Trn1、Trn2、Inf1、Inf2 和其他实例的组合。
+ 在容器中，您需要一个采用支持 AWS Neuron 的机器学习框架的 Linux 应用程序。
**重要**  
使用其他框架的应用程序可能不会在 Trn1、Trn2、Inf1 和 Inf2 实例上获得性能提升。
+ 每个 [AWS Trainium](https://aws.amazon.com/ai/machine-learning/trainium/) 或 [AWS Inferentia](https://aws.amazon.com/ai/machine-learning/inferentia/) 芯片上只能运行一个推理或推理训练任务。对于 Inf1，每个芯片有 4 个 NeuronCore。对于 Trn1、Trn2 和 Inf2，每个芯片有 2 个 NeuronCore。每个 Trn1、Trn2、Inf1 和 Inf2 实例都有芯片，您可以运行与之一样多的任务。
+ 在创建服务或运行独立任务时，您可以在配置任务放置约束时使用实例类型属性。这样可以确保在您指定的容器实例上启动任务。这样做可以帮助您优化总体资源利用率，并确保推理工作负载的任务位于 Trn1、Trn2、Inf1 和 Inf2 实例上。有关更多信息，请参阅 [Amazon ECS 如何将任务放置在容器实例上](task-placement.md)。

  在以下示例中，任务在您的 `default` 集群上的 `Inf1.xlarge` 实例上运行。

  ```
  aws ecs run-task \
       --cluster default \
       --task-definition ecs-inference-task-def \
       --placement-constraints type=memberOf,expression="attribute:ecs.instance-type == Inf1.xlarge"
  ```
+ 无法在任务定义中定义 Neuron 资源需求。但您要将容器配置为使用主机容器实例上可用的特定 AWS Trainium 或 AWSInferentia 芯片。通过使用 `linuxParameters` 参数并指定设备详细信息来执行此操作。有关更多信息，请参阅 [任务定义要求](#ecs-inference-requirements)。

## 使用经 Amazon ECS 优化的 Amazon Linux 2023（Neuron）AMI
<a name="ecs-inference-ami2023"></a>

Amazon ECS 为 AWS Trainium 和 AWS Inferentia 工作负载提供了一个基于 Amazon Linux 2023 的经 Amazon ECS 优化的 AMI。它附带适用于 Docker 的 AWS Neuron 驱动程序和运行时。此 AMI 使得在 Amazon ECS 上运行机器学习 inference 工作负载变得更加轻松。

我们建议您在启动 Amazon EC2 Trn1、Inf1 和 Inf2 实例时使用经 Amazon ECS 优化的 Amazon Linux 2023（Neuron）AMI。

您可以使用 AWS CLI 和以下命令检索当前经 Amazon ECS 优化的 Amazon Linux 2023（Neuron）AMI。

```
aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2023/neuron/recommended
```

## 任务定义要求
<a name="ecs-inference-requirements"></a>

要在 Amazon ECS 上部署 Neuron，您的任务定义必须包含预构建容器的容器定义，该容器服务于 TensorFlow 的 推理模型。它是由 AWS Deep Learning Containers 提供的。此容器包含 AWS Neuron 运行时和 TensorFlow 服务应用程序。在启动时，此容器将从 Amazon S3 获取您的模型，用保存的模型启动 Neuron TensorFlow 服务，并等待预测请求。在以下示例中，容器映像具有 TensorFlow 1.15 和 Ubuntu 18.04。GitHub 上维护了针对 Neuron 优化的预构建 Deep Learning Containers 的完整列表。有关更多信息，请参阅[使用 AWS Neuron TensorFlow Serving](https://docs.aws.amazon.com/dlami/latest/devguide/tutorial-inferentia-tf-neuron-serving.html)。

```
763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-inference-neuron:1.15.4-neuron-py37-ubuntu18.04
```

或者，您也可以构建自己的 Neuron 边车容器映像。有关更多信息，请参阅《AWS Deep Learning AMIs 开发人员指南》**中的[教程：Neuron TensorFlow Serving](https://github.com/aws-neuron/aws-neuron-sdk/blob/master/frameworks/tensorflow/tensorflow-neuron/tutorials/tutorials-tensorflow-utilizing-neuron-capabilities.rst)。

任务定义必须特定于一种实例类型。您必须将容器配置为使用主机容器实例上可用的特定 AWS Trainium 或 AWS Inferentia 设备。您还可以使用 `linuxParameters` 参数执行此操作。对于示例任务定义，请参阅 [在 Amazon ECS 任务定义中指定 AWS Neuron 机器学习](ecs-inference-task-def.md)。下表详细介绍了特定于每种实例类型的芯片。


| 实例类型 | vCPU | RAM (GiB) | AWS ML 加速器芯片 | 设备路径 | 
| --- | --- | --- | --- | --- | 
| trn1.2xlarge | 8 | 32 | 1 | /dev/neuron0 | 
| trn1.32xlarge | 128 | 512 | 16 |  /dev/neuron0, /dev/neuron1, /dev/neuron2, /dev/neuron3, /dev/neuron4, /dev/neuron5, /dev/neuron6, /dev/neuron7, /dev/neuron8, /dev/neuron9, /dev/neuron10, /dev/neuron11, /dev/neuron12, /dev/neuron13, /dev/neuron14, /dev/neuron15  | 
| trn2.48xlarge | 192 | 1536 | 16 |  /dev/neuron0, /dev/neuron1, /dev/neuron2, /dev/neuron3, /dev/neuron4, /dev/neuron5, /dev/neuron6, /dev/neuron7, /dev/neuron8, /dev/neuron9, /dev/neuron10, /dev/neuron11, /dev/neuron12, /dev/neuron13, /dev/neuron14, /dev/neuron15  | 
| inf1.xlarge | 4 | 8 | 1 | /dev/neuron0 | 
| inf1.2xlarge | 8 | 16 | 1 | /dev/neuron0 | 
| inf1.6xlarge | 24 | 48 | 4 | /dev/neuron0, /dev/neuron1, /dev/neuron2, /dev/neuron3 | 
| inf1.24xlarge | 96 | 192 | 16 |  /dev/neuron0, /dev/neuron1, /dev/neuron2, /dev/neuron3, /dev/neuron4, /dev/neuron5, /dev/neuron6, /dev/neuron7, /dev/neuron8, /dev/neuron9, /dev/neuron10, /dev/neuron11, /dev/neuron12, /dev/neuron13, /dev/neuron14, /dev/neuron15  | 
| inf2.xlarge | 8 | 16 | 1 | /dev/neuron0 | 
| inf2.8xlarge | 32 | 64 | 1 | /dev/neuron0 | 
| inf2.24xlarge | 96 | 384 | 6 | /dev/neuron0, /dev/neuron1, /dev/neuron2, /dev/neuron3, /dev/neuron4, /dev/neuron5,  | 
| inf2.48xlarge | 192 | 768 | 12 | /dev/neuron0, /dev/neuron1, /dev/neuron2, /dev/neuron3, /dev/neuron4, /dev/neuron5, /dev/neuron6, /dev/neuron7, /dev/neuron8, /dev/neuron9, /dev/neuron10, /dev/neuron11 | 

# 在 Amazon ECS 任务定义中指定 AWS Neuron 机器学习
<a name="ecs-inference-task-def"></a>

以下是 `inf1.xlarge` 的示例 Linux 任务定义，显示要使用的语法。

```
{
    "family": "ecs-neuron",
    "requiresCompatibilities": ["EC2"],
    "placementConstraints": [
        {
            "type": "memberOf",
            "expression": "attribute:ecs.os-type == linux"
        },
        {
            "type": "memberOf",
            "expression": "attribute:ecs.instance-type == inf1.xlarge"
        }
    ],
    "executionRoleArn": "${YOUR_EXECUTION_ROLE}",
    "containerDefinitions": [
        {
            "entryPoint": [
                "/usr/local/bin/entrypoint.sh",
                "--port=8500",
                "--rest_api_port=9000",
                "--model_name=resnet50_neuron",
                "--model_base_path=s3://amzn-s3-demo-bucket/resnet50_neuron/"
            ],
            "portMappings": [
                {
                    "hostPort": 8500,
                    "protocol": "tcp",
                    "containerPort": 8500
                },
                {
                    "hostPort": 8501,
                    "protocol": "tcp",
                    "containerPort": 8501
                },
                {
                    "hostPort": 0,
                    "protocol": "tcp",
                    "containerPort": 80
                }
            ],
            "linuxParameters": {
                "devices": [
                    {
                        "containerPath": "/dev/neuron0",
                        "hostPath": "/dev/neuron0",
                        "permissions": [
                            "read",
                            "write"
                        ]
                    }
                ],
                "capabilities": {
                    "add": [
                        "IPC_LOCK"
                    ]
                }
            },
            "cpu": 0,
            "memoryReservation": 1000,
            "image": "763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-inference-neuron:1.15.4-neuron-py37-ubuntu18.04",
            "essential": true,
            "name": "resnet50"
        }
    ]
}
```

# 适用于深度学习实例的 Amazon ECS 任务定义
<a name="ecs-dl1"></a>

要在 Amazon ECS 上使用深度学习工作负载，请将 [Amazon EC2 DL1](https://aws.amazon.com/ec2/instance-types/dl1/) 实例注册到您的集群。Amazon EC2 DL1 实例由英特尔旗下公司 Habana Labs 的 Gaudi 加速器提供支持。使用 Habana SynapseAI SDK 连接 Habana Gaudi 加速器。SDK 支持常用的机器学习框架 TensorFlow 和 PyTorch。

## 注意事项
<a name="ecs-dl1-considerations"></a>

在 Amazon ECS 上开始部署 DL1 之前，请注意以下事项：
+ 您的集群可以包含 DL1 和非 DL1 实例的组合。
+ 在创建服务或运行独立任务时，您可以在配置任务放置约束时使用实例类型属性，以确保在您指定的容器实例上启动任务。这样做可以确保您有效地使用资源，并确保深度学习工作负载任务在 DL1 实例上。有关更多信息，请参阅 [Amazon ECS 如何将任务放置在容器实例上](task-placement.md)。

  以下示例运行 `default` 集群上的 `dl1.24xlarge` 实例任务。

  ```
  aws ecs run-task \
       --cluster default \
       --task-definition ecs-dl1-task-def \
       --placement-constraints type=memberOf,expression="attribute:ecs.instance-type == dl1.24xlarge"
  ```

## 使用 DL1 AMI
<a name="ecs-dl1-ami"></a>

您有三种选择可以在 Amazon EC2 DL1 实例上运行适用于 Amazon ECS 的 AMI：
+ Habana [在此处](https://aws.amazon.com/marketplace/pp/prodview-h24gzbgqu75zq)提供的 AWS Marketplace AMI。
+ Amazon Web Services 提供的 Habana 深度学习 AMI。因为它不包括在内，因此您需要单独安装 Amazon ECS 容器代理。
+ 使用 Packer 构建由 [GitHub 存储库](https://github.com/aws-samples/aws-habana-baseami-pipeline)提供的自定义 AMI。有关更多信息，请参阅 [Packer 文档](https://developer.hashicorp.com/packer/docs)。

# 在 Amazon ECS 任务定义中指定深度学习
<a name="ecs-dl1-requirements"></a>

要在 Amazon ECS 上运行 Habana Gaudi 加速深度学习容器，您的任务定义必须包含预构建容器的容器定义，该容器使用 AWS 深度学习容器提供的 Habana SynapseAI 服务于 TensorFlow 或 PyTorch 的深度学习模型。

以下容器映像具有 TensorFlow 2.7.0 和 Ubuntu 20.04。GitHub 上维护了针对 Habana Gaudi 加速器优化的预构建深度学习容器的完整列表。有关更多信息，请参阅 [Habana Training Containers](https://github.com/aws/deep-learning-containers/blob/master/available_images.md#habana-training-containers)（Habana 训练容器）。

```
763104351884.dkr.ecr.us-east-1.amazonaws.com/tensorflow-training-habana:2.7.0-hpu-py38-synapseai1.2.0-ubuntu20.04
```

以下是 Amazon EC2 上的 Linux 容器的示例任务定义，显示要使用的语法。此示例使用包含 Habana Labs 实验室系统管理界面工具（HL-SMI）的图像，可参见此处：`vault.habana.ai/gaudi-docker/1.1.0/ubuntu20.04/habanalabs/tensorflow-installer-tf-cpu-2.6.0:1.1.0-614`

```
{
    "family": "dl-test",
    "requiresCompatibilities": ["EC2"],
    "placementConstraints": [
        {
            "type": "memberOf",
            "expression": "attribute:ecs.os-type == linux"
        },
        {
            "type": "memberOf",
            "expression": "attribute:ecs.instance-type == dl1.24xlarge"
        }
    ],
    "networkMode": "host",
    "cpu": "10240",
    "memory": "1024",
    "containerDefinitions": [
        {
            "entryPoint": [
                "sh",
                "-c"
            ],
            "command": ["hl-smi"],
            "cpu": 8192,
            "environment": [
                {
                    "name": "HABANA_VISIBLE_DEVICES",
                    "value": "all"
                }
            ],
            "image": "vault.habana.ai/gaudi-docker/1.1.0/ubuntu20.04/habanalabs/tensorflow-installer-tf-cpu-2.6.0:1.1.0-614",
            "essential": true,
            "name": "tensorflow-installer-tf-hpu"
        }
    ]
}
```

# 适用于 64 位 ARM 工作负载的 Amazon ECS 任务定义
<a name="ecs-arm64"></a>

Amazon ECS 支持使用 64 位 ARM 应用程序。您可以在 [AWS Graviton 处理器](https://aws.amazon.com/ec2/graviton/)支持的平台上运行您的应用程序。它适用于各类工作负载。这包括应用程序服务器、微服务、高性能计算、基于 CPU 的机器学习推断、视频编码、电子设计自动化、游戏、开源数据库和内存缓存等工作负载。

## 注意事项
<a name="ecs-arm64-considerations"></a>

在开始部署使用 64 位 ARM 架构的任务定义之前，请考虑以下事项：
+ 应用程序可以使用 Fargate 或 EC2。
+ 这些应用程序只能使用 Linux 操作系统。
+ 对于 Fargate 类型，应用程序必须使用 Fargate 平台版本 `1.4.0` 或更高版本。
+ 应用程序可以使用 Fluent Bit 或 CloudWatch 进行监控。
+ 对于 Fargate，以下 AWS 区域不支持 64 位 ARM 工作负载：
  + 美国东部（弗吉尼亚州北部），`use1-az3` 可用区
+  对于 EC2，请参阅以下内容以验证您的区域是否支持要使用的实例类型：
  + [Amazon EC2 M6g 实例](https://aws.amazon.com/ec2/instance-types/m6)
  +  [Amazon EC2 T4g 实例](https://aws.amazon.com/ec2/instance-types/t4/)
  +  [Amazon EC2 C6g 实例](https://aws.amazon.com/ec2/instance-types/c6g/)
  +  [Amazon EC2 R6gd 实例](https://aws.amazon.com/ec2/instance-types/r6/)
  +  [Amazon EC2 X2gd 实例](https://aws.amazon.com/ec2/instance-types/x2/)

  您还可以使用带筛选器的 Amazon EC2 `describe-instance-type-offerings` 命令来查看您所在区域的实例产品。

  ```
  aws ec2 describe-instance-type-offerings --filters Name=instance-type,Values=instance-type --region region
  ```

  以下示例检查美国东部（弗吉尼亚州北部）（us-east-1）区域中的 M6 实例类型可用性。

  ```
  aws ec2 describe-instance-type-offerings --filters "Name=instance-type,Values=m6*" --region us-east-1
  ```

  有关更多信息，请参阅 *Amazon EC2 命令行参考*中的 [describe-instance-type-offerings](https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instance-type-offerings.html)。

# 在 Amazon ECS 任务定义中指定 ARM 架构
<a name="ecs-arm-specifying"></a>

要使用 ARM 架构，请为 `cpuArchitecture` 任务定义参数指定 `ARM64`。

在以下示例中，ARM 架构是在任务定义中指定的。该文件以 JSON 格式。

```
{
    "runtimePlatform": {
        "operatingSystemFamily": "LINUX",
        "cpuArchitecture": "ARM64"
    },
...
}
```

在以下示例中，ARM 架构的任务定义显示“hello world”。

```
{
 "family": "arm64-testapp",
 "networkMode": "awsvpc",
 "containerDefinitions": [
    {
        "name": "arm-container",
        "image": "public.ecr.aws/docker/library/busybox:latest",
        "cpu": 100,
        "memory": 100,
        "essential": true,
        "command": [ "echo hello world" ],
        "entryPoint": [ "sh", "-c" ]
    }
 ],
 "requiresCompatibilities": [ "EC2" ],
 "cpu": "256",
 "memory": "512",
 "runtimePlatform": {
        "operatingSystemFamily": "LINUX",
        "cpuArchitecture": "ARM64"
  },
 "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole"
}
```

# 将 Amazon ECS 日志发送到 CloudWatch
<a name="using_awslogs"></a>

您可在任务中配置容器以将日志信息发送到 CloudWatch Logs。如果您对任务使用 Fargate，则可以查看容器中的日志。如果您使用 EC2，则可以在一个方便的位置查看容器中的不同日志，并防止您的容器日志占用您容器实例上的磁盘空间。

**注意**  
任务中的容器所记录的信息类型主要取决于其 `ENTRYPOINT` 命令。默认情况下，捕获的日志显示命令输出是您在本地运行容器时在交互式终端上通常看到的内容，即 `STDOUT` 和 `STDERR` I/O 流。`awslogs`日志驱动程序只是将 Docker 中的这些日志传递到 CloudWatch Logs。有关如何处理 Docker 日志的更多信息，包括捕获不同文件数据或流的替代方法，请参阅 Docker 文档中的[查看容器或服务的日志](https://docs.docker.com/engine/logging/)。

要将系统日志从 Amazon ECS 容器实例发送到 CloudWatch Logs，请参阅《Amazon CloudWatch Logs 用户指南》**中的[监控日志文件](https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/WhatIsCloudWatchLogs.html)和 [CloudWatch Logs 配额](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html)。

## Fargate
<a name="enable_awslogs"></a>

如果您对任务使用 Fargate，您需要将所需的 `logConfiguration` 参数添加到您的任务定义才能打开 `awslogs` 日志驱动程序。有关更多信息，请参阅 [Amazon ECS 任务定义示例：将日志路由到 CloudWatch](specify-log-config.md)。

对于 Fargate 上的 Windows 容器，当您的任何任务定义参数包含特殊字符（例如 `& \ < > ^ |`）时，请执行以下选项之一：
+ 在整个参数字符串周围添加一个带有双引号的 escape（`\`）字符

  示例

  ```
  "awslogs-multiline-pattern": "\"^[|DEBUG|INFO|WARNING|ERROR\"",
  ```
+ 在每个特殊字符周围添加一个 escape（`^`）字符

  示例

  ```
  "awslogs-multiline-pattern": "^^[^|DEBUG^|INFO^|WARNING^|ERROR",
  ```

## EC2
<a name="ec2-considerations"></a>

如果您对任务使用 EC2，并且想要打开 `awslogs` 日志驱动程序，您的 Amazon ECS 容器实例至少需要容器代理的 1.9.0 版本。有关如何检查您的代理版本并更新到最新版本的信息，请参阅[更新 Amazon ECS 容器代理](ecs-agent-update.md)。

**注意**  
您必须使用经 Amazon ECS 优化的 AMI 或至少包含 `ecs-init` 软件包版本 `1.9.0-1` 的自定义 AMI。使用自定义 AMI 时，如果在 **docker run** 语句或环境变量文件中使用以下环境变量启动代理，您必须指定 `awslogs` 日志驱动程序在 Amazon EC2 实例上可用。  

```
ECS_AVAILABLE_LOGGING_DRIVERS=["json-file","awslogs"]
```

Amazon ECS 容器实例还需要针对您用于启动容器实例的 IAM 角色的 `logs:CreateLogStream` 和 `logs:PutLogEvents` 权限。如果在 Amazon ECS 中启用 `awslogs` 日志驱动程序支持之前创建了 Amazon ECS 容器实例，可能需要添加此权限。`ecsTaskExecutionRole` 在将其分配给任务时使用，并且可能包含正确的权限。有关任务执行角色的信息，请参阅[Amazon ECS 任务执行 IAM 角色](task_execution_IAM_role.md)。如果您的容器实例使用容器实例的托管 IAM 策略，您的容器实例可能具有正确的权限。有关容器实例的托管 IAM 策略的信息，请参阅[Amazon ECS 容器实例 IAM 角色](instance_IAM_role.md)。

# Amazon ECS 任务定义示例：将日志路由到 CloudWatch
<a name="specify-log-config"></a>

必须先在任务定义中为容器指定 `awslogs` 日志驱动程序，容器才能将日志发送到 CloudWatch。有关日志参数的更多信息，请参阅 [存储和日志记录](task_definition_parameters.md#container_definition_storage)

下面的任务定义 JSON 有一个为每个容器指定的 `logConfiguration` 对象。一个是用于将日志发送到名为 `awslogs-wordpress` 的日志组的 WordPress 容器。另一个是用于将日志发送到名为 `awslogs-mysql` 的日志组的 MySQL 容器。两个容器都使用`awslogs-example`日志流前缀。

```
{
    "containerDefinitions": [
        {
            "name": "wordpress",
            "links": [
                "mysql"
            ],
            "image": "public.ecr.aws/docker/library/wordpress:latest",
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-create-group": "true",
                    "awslogs-group": "awslogs-wordpress",
                    "awslogs-region": "us-west-2",
                    "awslogs-stream-prefix": "awslogs-example"
                }
            },
            "memory": 500,
            "cpu": 10
        },
        {
            "environment": [
                {
                    "name": "MYSQL_ROOT_PASSWORD",
                    "value": "password"
                }
            ],
            "name": "mysql",
            "image": "public.ecr.aws/docker/library/mysql:latest",
            "cpu": 10,
            "memory": 500,
            "essential": true,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-create-group": "true",
                    "awslogs-group": "awslogs-mysql",
                    "awslogs-region": "us-west-2",
                    "awslogs-stream-prefix": "awslogs-example",
                    "mode": "non-blocking", 
                    "max-buffer-size": "25m" 
                }
            }
        }
    ],
    "family": "awslogs-example"
}
```

## 后续步骤
<a name="specify-log-config-next-steps"></a>
+ 您可以选择使用 CloudWatch AWS CLI 或 API 为日志组设置保留策略。有关更多信息，请参阅《AWS Command Line Interface 命令参考》中的 [put-retention-policy](https://docs.aws.amazon.com/cli/latest/reference/logs/put-retention-policy.html)**。
+ 在容器定义日志配置中向 `awslogs` 日志驱动程序注册任务定义之后，可运行任务或使用此任务定义创建服务以开始将日志发送到 CloudWatch Logs。有关更多信息，请参阅[将应用程序作为 Amazon ECS 任务运行](standalone-task-create.md)和[创建 Amazon ECS 滚动更新部署](create-service-console-v2.md)。

# 将 Amazon ECS 日志发送到 AWS 服务或 AWS Partner
<a name="using_firelens"></a>

您可以使用适用于 Amazon ECS 的 FireLens 来使用任务定义参数将日志路由到 AWS 服务或 AWS Partner Network（APN）目标来进行日志存储和分析。AWS Partner Network 是一个由合作伙伴组成的全球社区，它利用计划、专业知识和资源来构建、营销和销售客户产品。有关更多信息，请参阅 [AWS Partner](https://aws.amazon.com/partners/work-with-partners/)。FireLens 与 [Fluentd](https://www.fluentd.org/) 和 [Fluent Bit](https://fluentbit.io/) 结合使用。我们提供 AWS for Fluent Bit 映像，您也可以使用自己的 Fluentd 或 Fluent Bit 映像。

默认情况下，Amazon ECS 会配置容器依赖关系，以便 Firelens 容器先启动，任何使用它的容器随后启动。Firelens 容器也会在所有使用它的容器停止后才停止。

要使用此功能，您必须为您的任务创建一个 IAM 角色，该角色提供使用任务需要的任何 AWS 服务所需的权限。例如，如果容器将日志路由到 Firehose，则任务需要调用 `firehose:PutRecordBatch` API 的权限。有关更多信息，请参阅 *IAM用户指南*中的[添加和删除 IAM 标识权限](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)。

在以下条件下，您的任务也可能需要 Amazon ECS 任务执行角色。有关更多信息，请参阅 [Amazon ECS 任务执行 IAM 角色](task_execution_IAM_role.md)。
+ 如果在 Fargate 上托管您的任务，并且您正在从 Amazon ECR 提取容器映像或 AWS Secrets Manager 在日志配置中引用敏感数据，那么您必须包含任务执行 IAM 角色。
+ 当您使用托管于 Amazon S3 中的自定义配置文件时，任务执行 IAM 角色必须包含 `s3:GetObject` 权限。

使用 FireLens for Amazon ECS 时考虑以下事项：
+ 建议您在日志容器名称中添加 `my_service_`，以便可以在控制台中轻松区分容器名称。
+ 默认情况下，Amazon ECS 在应用程序容器和 FireLens 容器之间添加启动容器顺序依赖关系。当您在应用程序容器和 FireLens 容器之间指定容器顺序时，默认的启动容器顺序将被覆盖。
+ 支持将适用于 Amazon ECS 的 FireLens 用于托管在 Linux 上的 AWS Fargate 和 Amazon EC2 的任务。Windows 容器不支持 FireLens。

  有关如何为 Windows 容器配置集中日志记录的信息，请参阅[使用 Fluent Bit 在 Amazon ECS 上对 Windows 容器进行集中日志记录](https://aws.amazon.com/blogs/containers/centralized-logging-for-windows-containers-on-amazon-ecs-using-fluent-bit/)。
+ 您可以使用 CloudFormation 模板为 Amazon ECS 配置 FireLens。有关更多信息，请参阅《AWS CloudFormation 用户指南》**中的 [AWS::ECS::TaskDefinition FirelensConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-firelensconfiguration.html)
+ FireLens 在端口 `24224` 上侦听，因此为了确保从任务外部无法访问 FireLens 日志路由器，不得允许任务使用的安全组中端口 `24224` 上的入站流量。对于使用 `awsvpc` 网络模式的任务，这是与任务关联的安全组。对于使用 `host` 网络模式的任务，它是与托管任务的 Amazon EC2 实例关联的安全组。对于使用 `bridge` 网络模式的任务，请勿创建任何使用端口 `24224` 的端口映射。
+ 对于使用 `bridge` 网络模式的任务，具有 FirelLens 配置的容器必须在依赖它的任何应用程序容器启动之前启动。要控制容器的启动顺序，请在任务定义中使用依赖条件。有关更多信息，请参阅 [容器依赖项](task_definition_parameters.md#container_definition_dependson)。
**注意**  
如果您将容器定义中的依赖条件参数与 FirelLens 配置结合使用，请确保每个容器均具有 `START` 或 `HEALTHY` 条件要求。
+ 默认情况下，FireLens 将集群和任务定义名称以及集群的 Amazon 资源名称（ARN）作为元数据键添加到您的 stdout/stderr 容器日志中。以下为元数据格式的示例。

  ```
  "ecs_cluster": "cluster-name",
  "ecs_task_arn": "arn:aws:ecs:region:111122223333:task/cluster-name/f2ad7dba413f45ddb4EXAMPLE",
  "ecs_task_definition": "task-def-name:revision",
  ```

  如果您不希望日志中出现元数据，请在任务定义的 `firelensConfiguration` 部分中将 `enable-ecs-log-metadata` 设置为 `false`。

  ```
  "firelensConfiguration":{
     "type":"fluentbit",
     "options":{
        "enable-ecs-log-metadata":"false",
        "config-file-type":"file",
        "config-file-value":"/extra.conf"
  }
  ```

您可以将 FireLens 容器配置为以非根用户身份运行。请考虑以下事项：
+  要将 FireLens 容器配置为以非根用户身份运行，您必须使用以下其中一种格式指定用户：
  + `uid`
  + `uid:gid`
  + `uid:group`

  有关在容器定义中指定用户的更多信息，请参阅《Amazon Elastic Container Service API 参考》**中的 [ContainerDefinition](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html)。

  FireLens 容器通过 UNIX 套接字接收应用程序日志。Amazon ECS 代理使用 `uid` 将套接字目录的所有权分配给 FireLens 容器。
+ 在 Amazon ECS 代理版本 `1.96.0` 及更高版本以及经 Amazon ECS 优化的 AMI 版本 `v20250716` 及更高版本上，支持将 FireLens 容器配置为以非根用户身份运行。
+ 当您为 FireLens 容器指定用户时，`uid` 必须是唯一的，并且不得用于属于任务中其他容器或容器实例的其他进程。

有关如何将多个配置文件用于 Amazon ECS 的信息（包括您托管的文件或 Amazon S3 中的文件），请参阅 [Init process for Fluent Bit on ECS, multi-config support](https://github.com/aws/aws-for-fluent-bit/tree/mainline/use_cases/init-process-for-fluent-bit)。

有关示例配置的信息，请参阅[Amazon ECS 任务定义示例：将日志路由到 FireLens](firelens-taskdef.md)。

有关配置日志以实现高吞吐量的更多信息，请参阅[配置 Amazon ECS 日志，以实现高吞吐量](firelens-docker-buffer-limit.md)。

# 配置 Amazon ECS 日志，以实现高吞吐量
<a name="firelens-docker-buffer-limit"></a>

对于高日志吞吐量场景，我们建议将 `awsfirelens` 日志驱动程序与 FireLens 和 Fluent Bit 一起使用。Fluent Bit 是一款轻量级日志处理器，资源利用效率高，可以处理数百万条日志记录。但是，要大规模实现最佳性能，需要调整其配置。

本部分介绍高级 Fluent Bit 优化技术，用于处理高日志吞吐量，同时保持系统稳定性并确保不丢失数据。

有关如何使用 FireLens 自定义配置文件的信息，请参阅 [使用自定义配置文件](firelens-taskdef.md#firelens-taskdef-customconfig)。有关其他示例，请参阅 GitHub 上的 [Amazon ECS FireLens 示例](https://github.com/aws-samples/amazon-ecs-firelens-examples)。

**注意**  
本部分中的某些配置选项（例如 `workers` 和 `threaded`）需要适用于 Fluent Bit 版本 3 或更高版本的 AWS。有关可用版本的信息，请参阅[适用于 Fluent Bit 的 AWS 版本](https://github.com/aws/aws-for-fluent-bit/releases)。

## 了解分块
<a name="firelens-understanding-chunks"></a>

Fluent Bit 以称为*分块*的单元处理数据。当 INPUT 插件收到数据时，引擎会创建一个分块，该分块在发送到 OUTPUT 目标之前存储在内存或文件系统中。

缓冲行为取决于 INPUT 部分中的 `storage.type` 设置。默认情况下，Fluent Bit 使用内存缓冲。对于高吞吐量或生产场景，文件系统缓冲可提供更好的韧性。

有关更多信息，请参阅 Fluent Bit 文档中的[分块](https://docs.fluentbit.io/manual/administration/buffering-and-storage#chunks)和 AWS for Fluent Bit 示例存储库中的[什么是分块？](https://github.com/aws-samples/amazon-ecs-firelens-examples/tree/mainline/examples/fluent-bit/oomkill-prevention#what-is-a-chunk)。

## 内存缓冲（默认）
<a name="firelens-memory-buffering"></a>

默认情况下，Fluent Bit 使用内存缓冲（`storage.type memory`）。您可以使用 `Mem_Buf_Limit` 参数限制每个 INPUT 插件的内存使用量。

以下示例显示了一个内存缓冲的输入配置：

```
[INPUT]
    Name          tcp
    Tag           ApplicationLogs
    Port          5170
    storage.type  memory
    Mem_Buf_Limit 5MB
```

**重要**  
当一个插件超出 `Mem_Buf_Limit` 时，Fluent Bit 将暂停输入并且会丢失新记录。这可能会导致背压并减慢应用程序的速度。Fluent Bit 日志中会出现以下警告：  

```
[input] tcp.1 paused (mem buf overlimit)
```

内存缓冲适用于日志吞吐量低至中等的简单应用场景。对于需要高吞吐量或用于生产环境且存在数据丢失风险的情况，应采用文件系统缓冲机制。

有关更多信息，请参阅 Fluent Bit 文档中的[缓冲和内存](https://docs.fluentbit.io/manual/administration/buffering-and-storage#buffering-and-memory)以及 AWS for Fluent Bit 示例存储库中的[仅限内存缓冲](https://github.com/aws-samples/amazon-ecs-firelens-examples/tree/mainline/examples/fluent-bit/oomkill-prevention#case-1-memory-buffering-only-default-or-storagetype-memory)。

## 文件系统缓冲
<a name="firelens-filesystem-buffering"></a>

对于高吞吐量场景，我们建议使用文件系统缓冲。有关 Fluent Bit 如何管理缓冲和存储的更多信息，请参阅 Fluent Bit 文档中的[缓冲和存储](https://docs.fluentbit.io/manual/administration/buffering-and-storage)。

文件系统缓冲提供以下优势：
+ **更大的缓冲容量** – 磁盘空间通常比内存更充足。
+ **持久性** – 缓冲的数据在 Fluent Bit 重新启动后仍能存活下来。
+ **正常降级** – 在输出失败期间，数据会积聚在磁盘上，而不是导致内存耗尽。

要启用文件系统缓冲，请提供自定义 Fluent Bit 配置文件。以下示例展示了建议的配置：

```
[SERVICE]
    # Flush logs every 1 second
    Flush 1
    # Wait 120 seconds during shutdown to flush remaining logs
    Grace 120
    # Directory for filesystem buffering
    storage.path             /var/log/flb-storage/
    # Limit chunks stored 'up' in memory (reduce for memory-constrained environments)
    storage.max_chunks_up    32
    # Flush backlog chunks to destinations during shutdown (prevents log loss)
    storage.backlog.flush_on_shutdown On

[INPUT]
    Name forward
    unix_path /var/run/fluent.sock
    # Run input in separate thread to prevent blocking
    threaded true
    # Enable filesystem buffering for persistence
    storage.type filesystem

[OUTPUT]
    Name cloudwatch_logs
    Match *
    region us-west-2
    log_group_name /aws/ecs/my-app
    log_stream_name $(ecs_task_id)
    # Use multiple workers for parallel processing
    workers 2
    # Retry failed flushes up to 15 times
    retry_limit 15
    # Maximum disk space for buffered data for this output
    storage.total_limit_size 10G
```

关键配置参数：

`storage.path`  
Fluent Bit 在磁盘上存储缓冲块的目录。

`storage.backlog.flush_on_shutdown`  
启用后，Fluent Bit 会尝试在停机期间将所有积压文件系统块刷新到目标。这有助于确保在 Fluent Bit 停止之前传输数据，但可能会增加停机时间。

`storage.max_chunks_up`  
保留在内存中的块的数量。默认值为 128 个块，这会消耗 500 MB 以上的内存，因为每个块最多可以使用 4-5 MB 的内存。在内存受限的环境中，请降低此值。例如，如果您有 50 MB 可于缓冲，请将其设置为 8-10 个块。

`storage.type filesystem`  
为输入插件启用文件系统存储。尽管名称如此，但 Fluent Bit 会使用 `mmap` 将块映射到内存和磁盘，从而在不牺牲性能的情况下提供持久性。

`storage.total_limit_size`  
特定 OUTPUT 插件的缓冲数据的最大磁盘空间。当达到此限制时，该输出的最旧记录将被删除。有关大小的更多信息，请参阅 [了解 `storage.total_limit_size`](#firelens-storage-sizing)。

`threaded true`  
在自己的线程中运行输入，与 Fluent Bit 的主事件循环分开。这样可以防止慢速输入阻塞整个管道。

有关更多信息，请参阅 Fluent Bit 文档中的[文件系统缓冲](https://docs.fluentbit.io/manual/administration/buffering-and-storage#filesystem-buffering)以及 AWS for Fluent Bit 示例存储库中的[文件系统和内存缓冲](https://github.com/aws-samples/amazon-ecs-firelens-examples/tree/mainline/examples/fluent-bit/oomkill-prevention#case-2-filesystem-and-memory-buffering-storagetype-filesystem)。

## 了解 `storage.total_limit_size`
<a name="firelens-storage-sizing"></a>

每个 OUTPUT 插件上的 `storage.total_limit_size` 参数控制该输出的缓冲数据的最大磁盘空间。当达到此限制时，该输出的最旧记录将被删除以为新数据腾出空间。当磁盘空间完全耗尽时，Fluent Bit 无法将记录加入队列，这些记录会丢失。

根据您的日志速率和所需的恢复窗口，使用以下公式计算适当的 `storage.total_limit_size`：

```
If log rate is in KB/s, convert to MB/s first:
log_rate (MB/s) = log_rate (KB/s) / 1000

storage.total_limit_size (GB) = log_rate (MB/s) × duration (hours) × 3600 (seconds/hour) / 1000 (MB to GB)
```

下表显示了常见日志速率和恢复窗口的计算示例：


| 日志速率 | 1 小时 | 6 小时 | 12 小时 | 24 小时 | 
| --- | --- | --- | --- | --- | 
| 0.25 MB/s | 0.9 GB | 5.4 GB | 10.8GB | 21.6GB | 
| 0.5 MB/s | 1.8 GB | 10.8GB | 21.6GB | 43.2 GB | 
| 1 MB/s | 3.6 GB | 21.6GB | 43.2 GB | 86.4GB | 
| 5 MB/s | 18 GB | 108 GB | 216 GB | 432 GB | 
| 10 MB/s | 36 GB | 216 GB | 432 GB | 864 GB | 

要观测峰值吞吐量并选择合适的缓冲区大小，请使用 [measure-throughput FireLens 样本](https://github.com/aws-samples/amazon-ecs-firelens-examples/tree/mainline/examples/measure-throughput)。

使用公式、示例计算和基准测试来选择合适的 `storage.total_limit_size`，在故障发生时为尽力恢复提供足够的空间。

## Amazon ECS 任务存储要求
<a name="firelens-storage-task-requirements"></a>

将 OUTPUT 部分的所有 `storage.total_limit_size` 值相加，并为开销部分预留缓冲空间。这个总数决定了您在 Amazon ECS 任务定义中所需的存储空间大小。例如，3 个输出 × 每个 10GB = 30GB \$1 缓冲区 (5—10GB) = 总共需要 35—40GB。如果总存储量超过可用存储空间，则 Fluent Bit 可能无法将记录加入队列，这些记录会丢失。

提供以下存储选项：

绑定挂载（临时存储）  
+ 对于 AWS Fargate，默认值为 20GB 的临时存储空间（最大 200GB）。在任务定义中使用 `ephemeralStorage` 进行配置。有关更多信息，请参阅《AWS CloudFormation 用户指南》**中的 [EphemeralStorage](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-ephemeralstorage.html)。
+ 对于 EC2，使用 Amazon ECS 优化的 AMI（在操作系统和 Docker 之间共享）时，默认值为 30GB。通过更改根卷大小来增加。

Amazon EBS 卷  
+ 提供高度可用、持久、高性能的块存储。
+ 需要卷配置和任务定义中指向 `storage.path` 的 `mountPoint`（默认：`/var/log/flb-storage/`）。
+ 有关更多信息，请参阅 [在 Amazon ECS 任务定义中将卷配置推迟到启动时间](specify-ebs-config.md)。

Amazon EFS 卷  
+ 提供简单的可扩展文件存储。
+ 需要卷配置和任务定义中指向 `storage.path` 的 `mountPoint`（默认：`/var/log/flb-storage/`）。
+ 有关更多信息，请参阅 [在 Amazon ECS 任务定义中指定 Amazon EFS 文件系统](specify-efs-config.md)。

有关数据卷的更多信息，请参阅 [Amazon ECS 任务的存储选项](using_data_volumes.md)。

## 优化输出配置
<a name="firelens-output-optimization"></a>

网络问题、服务中断和目标节流可能会导致无法传送日志。正确的输出配置可确保韧性而不会丢失数据。

当输出刷新失败时，Fluent Bit 可以重试该操作。以下参数控制重试行为：

`retry_limit`  
在首次尝试后放弃记录之前的最大重试次数。默认 为 1。例如，`retry_limit 3` 表示总尝试次数 4 次（1 次初始尝试 \$1 3 次重试）。对于生产环境，我们建议设置为 15 或更高，这可以通过指数回退覆盖几分钟的中断时间。  
设置为 `no_limits` 或 `False` 以进行无限重试：  
+ 使用内存缓冲时，无限次重试会导致输入插件在达到内存限制时暂停。
+ 使用文件系统缓冲时，最旧的记录在到达 `storage.total_limit_size` 时会被丢弃。
用尽所有重试次数（1 次初始尝试 \$1 `retry_limit` 次重试）后，记录将被删除。带有 `auto_retry_requests true` 的 AWS 插件（默认）在 Fluent Bit 的重试机制之前提供了额外的重试层。有关更多信息，请参阅 Fluent Bit 文档中的[配置重试](https://docs.fluentbit.io/manual/administration/scheduling-and-retries#configure-retries)。  
例如，使用默认设置（`scheduler.base 5`、`scheduler.cap 2000`、`net.connect_timeout 10s`）的 `retry_limit 3` 可提供大约 70 秒的调度程序等待时间（10s \$1 20s \$1 40s）、40 秒的网络连接超时（4 次尝试 × 10s）以及 AWS 插件重试次数，总计大约 2-10 分钟，具体取决于网络条件和操作系统 TCP 超时。

`scheduler.base`  
两次重试之间的基本秒数（默认值：5）。我们建议 10 秒。

`scheduler.cap`  
两次重试之间的最大秒数（默认值：2000）。我们建议 60 秒。

两次重试之间的等待时间使用带有抖动的指数回退：

```
wait_time = random(base, min(base × 2^retry_number, cap))
```

例如，使用 `scheduler.base 10` 和 `scheduler.cap 60`：
+ 第一次重试：在 10–20 秒之间随机等待
+ 第二次重试：在 10–40 秒之间随机等待
+ 第三次重试及以后：在 10–60 秒之间随机等待（上限）

有关更多信息，请参阅 Fluent Bit 文档中的[配置重试等待时间](https://docs.fluentbit.io/manual/administration/scheduling-and-retries#configure-wait-time-for-retry)和[联网](https://docs.fluentbit.io/manual/administration/networking)。

`workers`  
并行输出处理的线程数。多个 Worker 允许并发刷新，从而提高处理多个块时的吞吐量。

`auto_retry_requests`  
一种特定于 AWS 插件的设置，在 Fluent Bit 的内置重试机制之前提供了额外的重试层。默认值为 `true`。启用后，AWS 输出插件会在内部重试失败的请求，然后请求才会被视为刷新失败并受 `retry_limit` 配置的约束。

`[SERVICE]` 部分中的 `Grace` 参数设置 Fluent Bit 在停机期间等待刷新缓冲数据的时间。`Grace` 期限必须与容器的 `stopTimeout` 相协调。确保 `stopTimeout` 超过 `Grace` 期限，进而允许 Fluent Bit 在接收 `SIGKILL` 之前完成刷新。例如，如果 `Grace` 为 120 秒，则将 `stopTimeout` 设置为 150 秒。

以下示例展示了针对高吞吐量场景的完整 Fluent Bit 配置，其中包含所有推荐设置：

```
[SERVICE]
    # Flush logs every 1 second
    Flush 1
    # Wait 120 seconds during shutdown to flush remaining logs
    Grace 120
    # Directory for filesystem buffering
    storage.path             /var/log/flb-storage/
    # Limit chunks stored 'up' in memory (reduce for memory-constrained environments)
    storage.max_chunks_up    32
    # Flush backlog chunks to destinations during shutdown (prevents log loss)
    storage.backlog.flush_on_shutdown On
    # Minimum seconds between retries
    scheduler.base           10
    # Maximum seconds between retries (exponential backoff cap)
    scheduler.cap            60

[INPUT]
    Name forward
    unix_path /var/run/fluent.sock
    # Run input in separate thread to prevent blocking
    threaded true
    # Enable filesystem buffering for persistence
    storage.type filesystem

[OUTPUT]
    Name cloudwatch_logs
    Match *
    region us-west-2
    log_group_name /aws/ecs/my-app
    log_stream_name $(ecs_task_id)
    # Use multiple workers for parallel processing
    workers 2
    # Retry failed flushes up to 15 times
    retry_limit 15
    # Maximum disk space for buffered data for this output
    storage.total_limit_size 10G
```

## 了解数据丢失情况
<a name="firelens-record-loss-scenarios"></a>

在长时间故障或输出目标出现问题的情况下，记录可能会丢失。本指南中的配置建议是尽力减少数据丢失，但不能保证长时间故障期间零丢失。了解这些场景有助于您配置 Fluent Bit 以最大限度地提高韧性。

记录可能会以两种方式丢失：当存储空间满时，最旧的记录会被删除；或者当系统无法再接收更多数据时，最新的记录会被拒绝。

### 最旧的记录已删除
<a name="firelens-record-loss-oldest-dropped"></a>

当重试尝试用尽或 `storage.total_limit_size` 已满且需要为新数据腾出空间时，最旧的缓冲记录将被丢弃。

超出了重试限制  
发生在 AWS 插件重试（如果 `auto_retry_requests true`）加上 1 次初始 Fluent Bit 尝试加上 `retry_limit` 重试次数之后。为了缓解风险，为每个 OUTPUT 插件设置 `retry_limit no_limits` 以进行无限次重试：  

```
[OUTPUT]
    Name                        cloudwatch_logs
    Match                       ApplicationLogs
    retry_limit                 no_limits
    auto_retry_requests         true
```
无限重试可防止由于重试耗尽而丢弃记录，但可能会导致 `storage.total_limit_size` 被填满。

已达到存储限制（文件系统缓冲）  
在输出目标不可用的时间超过您所配置的 `storage.total_limit_size` 可以缓冲的时间时，就会出现这种情况。例如，日志速率为 1 MB/s 的 10GB 缓冲区可提供大约 2.7 小时的缓冲时间。为了缓解风险，请增加每个 OUTPUT 插件的 `storage.total_limit_size` 并预置足够的 Amazon ECS 任务存储空间：  

```
[OUTPUT]
    Name                        cloudwatch_logs
    Match                       ApplicationLogs
    storage.total_limit_size    10G
```

### 最新的记录被拒绝
<a name="firelens-record-loss-newest-rejected"></a>

当磁盘空间耗尽或由于 `Mem_Buf_Limit` 暂停输入时，最新的记录将被丢弃。

磁盘空间已耗尽（文件系统缓冲）  
当磁盘空间完全耗尽时发生。Fluent Bit 无法将新记录列队且它们会丢失。为了缓解风险，将所有的 `storage.total_limit_size` 值相加并预置足够的 Amazon ECS 任务存储空间。有关更多信息，请参阅 [Amazon ECS 任务存储要求](#firelens-storage-task-requirements)。

已达到内存限制（内存缓冲）  
在输出目标不可用且内存缓冲区已满时发生。暂停的输入插件将停止接受新记录。要缓解风险，请使用 `storage.type filesystem` 提高韧性，或增加 `Mem_Buf_Limit`。

### 最大限度减少数据丢失的最佳实践
<a name="firelens-record-loss-best-practices"></a>

考虑以下最佳实践来最大限度减少数据丢失：
+ **使用文件系统缓冲** – 设置 `storage.type filesystem` 以在中断期间提高韧性。
+ **适当调整存储空间大小** – 根据日志速率和所需的恢复窗口计算 `storage.total_limit_size`。
+ **预置足够的磁盘** – 确保 Amazon ECS 任务有足够的临时存储、Amazon EBS 或 Amazon EFS。
+ **配置重试行为** – 在 `retry_limit`（用尽重试后丢弃记录）和 `no_limits`（无限次重试但可能会填满存储空间）之间保持平衡。

## 使用多目标日志记录实现可靠性
<a name="firelens-multi-destination"></a>

将日志发送到多个目标可以消除单点故障。例如，如果 CloudWatch Logs 出现中断，日志仍会到达 Amazon S3。

多目标日志记录提供以下优势：Amazon S3 输出插件还支持 gzip 和 Parquet 格式等压缩选项，这可以降低存储成本。有关更多信息，请参阅 Fluent Bit 文档中的 [S3 压缩](https://docs.fluentbit.io/manual/pipeline/outputs/s3#compression)。

多目标日志记录可以提供以下优势：
+ **冗余** – 如果一个目标出现故障，日志仍会到达另一个目标。
+ **恢复** – 重建一个系统与另一个系统之间的差距。
+ **持久性** – 将日志归档到 Amazon S3 实现长期保留。
+ **成本优化** – 将最近的日志保存在诸如 CloudWatch Logs 之类的快速查询服务中，保留时间较短，而将所有日志归档到成本较低的 Amazon S3 存储可以实现长期保留。

以下 Fluent Bit 配置将日志发送到 CloudWatch Logs 和 Amazon S3：

```
[OUTPUT]
    Name cloudwatch_logs
    Match *
    region us-west-2
    log_group_name /aws/ecs/my-app
    log_stream_name $(ecs_task_id)
    workers 2
    retry_limit 15

[OUTPUT]
    Name s3
    Match *
    bucket my-logs-bucket
    region us-west-2
    total_file_size 100M
    s3_key_format /fluent-bit-logs/$(ecs_task_id)/%Y%m%d/%H/%M/$UUID
    upload_timeout 10m
    # Maximum disk space for buffered data for this output
    storage.total_limit_size 5G
```

两个输出都使用相同的 `Match *` 模式，因此所有记录都独立发送到两个目标。在一个目标中断期间，日志继续流向另一个目标，而失败的刷新会积聚在文件系统缓冲区中供以后重试。

## 通过 tail 输入插件使用基于文件的日志记录
<a name="firelens-tail-input"></a>

对于日志丢失是一个关键问题的高吞吐量场景，可以使用另一种方法：让应用程序将日志写入磁盘上的文件，然后使用 `tail` 输入插件将 Fluent Bit 配置为读取日志。这种方法完全绕过了 Docker 日志记录驱动程序层。

通过 tail 插件进行基于文件的日志记录提供以下优势：
+ **偏移跟踪** – Tail 插件可以将文件偏移存储在数据库文件中（使用 `DB` 选项），从而在 Fluent Bit 重新启动后提供持久性。这有助于防止在容器重新启动期间丢失日志。
+ **输入级缓冲** – 可以使用 `Mem_Buf_Limit` 直接在输入插件上配置内存缓冲区限制，从而更精细地控制内存使用情况。
+ **避免 Docker 开销** – 日志直接从文件转到 Fluent Bit，无需通过 Docker 的日志缓冲区。

要使用这种方法，您的应用程序必须将日志写入文件中，而不是 `stdout`。应用程序容器和 Fluent Bit 容器都挂载一个存储日志文件的共享卷。

以下示例展示了具有最佳实践的 tail 输入配置：

```
[INPUT]
    Name tail
    # File path or glob pattern to tail
    Path /var/log/app.log
    # Database file for storing file offsets (enables resuming after restart)
    DB /var/log/flb_tail.db
    # when true, controls that only fluent-bit will access the database (improves performance)
    DB.locking true
    # Skip long lines instead of skipping the entire file
    Skip_Long_Lines On
    # How often (in seconds) to check for new files matching the glob pattern
    Refresh_Interval 10
    # Extra seconds to monitor a file after rotation to account for pending flush
    Rotate_Wait 30
    # Maximum size of the buffer for a single line
    Buffer_Max_Size 10MB
    # Initial allocation size for reading file data
    Buffer_Chunk_Size 1MB
    # Maximum memory buffer size (tail pauses when full)
    Mem_Buf_Limit 75MB
```

使用 tail 输入插件时，请考虑以下几点：
+ 对应用程序日志实施日志轮换，以防止磁盘耗尽。监控基础卷指标以衡量性能。
+ 根据您的日志格式考虑诸如 `Ignore_Older`、`Read_from_Head` 和多行解析器之类的设置。

有关更多信息，请参阅 Fluent Bit 文档中的 [Tail](https://docs.fluentbit.io/manual/pipeline/inputs/tail)。有关最佳实践，请参阅适用于 Fluent Bit 的 AWS 故障排除指南中的 [Tail 配置和最佳实践](https://github.com/aws/aws-for-fluent-bit/blob/mainline/troubleshooting/debugging.md#tail-config-with-best-practices)。

## 直接记录到 FireLens
<a name="firelens-environment-variables"></a>

在任务定义中指定 `awsfirelens` 日志驱动程序时，Amazon ECS 容器 代理会将以下环境变量注入容器中：

`FLUENT_HOST`  
分配给 FirelLens 容器的 IP 地址。  
如果在 `bridge` 网络模式下使用 EC2，则在重启 FireLens 日志路由器容器（容器定义中包含 `firelensConfiguration` 对象的容器）后，应用程序容器中的 `FLUENT_HOST` 环境变量可能会变得不准确。这是因为 `FLUENT_HOST` 是一个动态 IP 地址，重启后就会改变。地址改变后，直接从应用程序容器登录到 `FLUENT_HOST` IP 地址可能会失败。有关重启单个容器的更多信息，请参阅 [使用容器重启策略重启 Amazon ECS 任务中的单个容器](container-restart-policy.md)。

`FLUENT_PORT`  
Fluent Forward 协议正在侦听的端口。

您可以使用这些环境变量，使用 Fluent Forward 协议从应用程序代码直接记录到 Fluent Bit 日志路由器，而不是写入 `stdout`。这种方法绕过了 Docker 日志记录驱动程序层，提供以下优势：
+ **更低的延迟** – 日志无需通过 Docker 的日志记录基础设施即可直接转到 Fluent Bit。
+ **结构化日志记录** – 以原生方式发送结构化日志数据，无需 JSON 编码开销。
+ **更好的控制** – 您的应用程序可以实现自己的缓冲和错误处理逻辑。

以下 Fluent 记录器库支持 Fluent Forward 协议，可用于将日志直接发送到 Fluent Bit：
+ **Go** – [fluent-logger-golang](https://github.com/fluent/fluent-logger-golang)
+ **Python** – [fluent-logger-python](https://github.com/fluent/fluent-logger-python)
+ **Java** – [fluent-logger-java](https://github.com/fluent/fluent-logger-java)
+ **Node.js** – [fluent-logger-node](https://github.com/fluent/fluent-logger-node)
+ **Ruby** – [fluent-logger-ruby](https://github.com/fluent/fluent-logger-ruby)

## 配置 Docker 缓冲区限制
<a name="firelens-buffer-limit"></a>

创建任务定义时，您可以通过在 `log-driver-buffer-limit` 中指定值来指定将在内存中缓冲的日志行数。这会控制 Docker 和 Fluent Bit 之间的缓冲区。有关更多信息，请参阅 Docker 文档中的 [Fluentd 日志记录驱动程序](https://docs.docker.com/engine/logging/drivers/fluentd/)。

当吞吐量高时使用此选项，因为 Docker 可能会耗尽缓冲区内存并丢弃缓冲区消息，以便添加新消息。

使用此选项时，请考虑以下几点：
+ 平台版本为 `1.4.0` 或更高版本的 EC2 和 Fargate 类型支持此选项。
+ 该选项仅在 `logDriver` 设置为 `awsfirelens` 时有效。
+ 默认缓冲区限制为 `1048576` 个日志行。
+ 缓冲区限制必须大于或等于 `0` 且小于 `536870912` 个日志行。
+ 用于此缓冲区的最大内存量是每个日志行的大小与缓冲区大小的乘积。例如，假设应用程序的日志行大小平均为 `2` KiB，则缓冲区限制为 4096 时最多只能使用 `8` MiB。除了日志驱动程序的内存缓冲区外，在任务级别分配的内存总量必须大于为所有容器分配的内存量。

以下任务定义展示了如何配置 `log-driver-buffer-limit`：

```
{
    "containerDefinitions": [
        {
            "name": "my_service_log_router",
            "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:3",
            "cpu": 0,
            "memoryReservation": 51,
            "essential": true,
            "firelensConfiguration": {
                "type": "fluentbit"
            }
        },
        {
            "essential": true,
            "image": "public.ecr.aws/docker/library/httpd:latest",
            "name": "app",
            "logConfiguration": {
                "logDriver": "awsfirelens",
                "options": {
                    "Name": "firehose",
                    "region": "us-west-2",
                    "delivery_stream": "my-stream",
                    "log-driver-buffer-limit": "52428800"
                }
            },
            "dependsOn": [
                {
                    "containerName": "my_service_log_router",
                    "condition": "START"
                }
            ],
            "memoryReservation": 100
        }
    ]
}
```

# Amazon ECS 的 AWS for Fluent Bit 映像存储库
<a name="firelens-using-fluentbit"></a>

AWS 提供了 Fluent Bit 映像以及 CloudWatch Logs 和 Firehose 的插件。我们建议使用 Fluent Bit 作为日志路由器，因为其资源利用率低于 Fluentd。有关更多信息，请参阅 [CloudWatch Logs for Fluent Bit](https://github.com/aws/amazon-cloudwatch-logs-for-fluent-bit) 和 [Amazon Kinesis Firehose for Fluent Bit](https://github.com/aws/amazon-kinesis-firehose-for-fluent-bit)。

为了获得高可用性，Amazon ECR 公开映像浏览馆和 Amazon ECR 存储库上的 Amazon ECR 都提供了 **AWS for Fluent Bit** 映像。

## Amazon ECR 公开映像浏览馆
<a name="firelens-image-ecrpublic"></a>

Amazon ECR 公开映像浏览馆提供了 AWS for Fluent Bit 映像。这是下载 AWS for Fluent Bit 映像的推荐位置，因为它是一个公共存储库，可从所有AWS 区域区域使用。有关更多信息，请参阅 Amazon ECR 公开映像浏览馆上的 [aws-for-fluent-bit](https://gallery.ecr.aws/aws-observability/aws-for-fluent-bit)。

### Linux
<a name="firelens-image-ecrpublic-linux"></a>

Amazon ECR 公开映像浏览馆中的 AWS for Fluent Bit 映像支持带有 `ARM64` 或 `x86-64` 架构的 Amazon Linux 操作系统。

通过使用所需的映像标记指定存储库 URL，可以从 Amazon ECR 公开映像浏览馆中提取 AWS for Fluent Bit 映像。可在 Amazon ECR 公开映像浏览馆上的**映像标签**选项卡上找到映像标签。

下面说明 Docker CLI 使用的语法。

```
docker pull public.ecr.aws/aws-observability/aws-for-fluent-bit:tag
```

例如，您可以使用此 Docker CLI 命令拉取适用于 Fluent Bit 的 AWS 版本的“3.x”系列中的最新映像。

```
docker pull public.ecr.aws/aws-observability/aws-for-fluent-bit:3
```

**注意**  
可以进行未经身份验证的拉取，但速率限制低于经过身份验证的拉取。拉取前如果要使用 AWS 账户验证身份，请使用以下命令。  

```
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
```

#### AWS for Fluent Bit 3.0.0
<a name="firelens-image-ecrpublic-linux-3.0.0"></a>

除了现有的 AWS for Fluent Bit 版本 `2.x` 外，AWS for Fluent Bit 还支持新的主要版本 `3.x`。新的主要版本包括将映像从 Amazon Linux 2 升级到 Amazon Linux 2023 以及将 Fluent Bit 版本 `1.9.10` 升级到 `4.1.1`。有关更多信息，请参阅 GitHub 上的 [AWS for Fluent Bit 存储库](https://github.com/aws/aws-for-fluent-bit/blob/mainline/VERSIONS.md)。

以下示例展示了 AWS for Fluent Bit `3.x` 映像更新后的标签：

您可以对 AWS for Fluent Bit 映像使用多架构标签。

```
docker pull public.ecr.aws/aws-observability/aws-for-fluent-bit:3
```

### Windows
<a name="firelens-image-ecrpublic-windows"></a>

Amazon ECR 公开映像浏览馆中 Fluent Bit 映像的 AWS 支持带有以下操作系统的 `AMD64` 架构：
+ Windows Server 2022 Full
+ Windows Server 2022 Core
+ Windows Server 2019 Full
+ Windows Server 2019 Core

AWS Fargate 上的 Windows 容器不支持 FireLens。

通过使用所需的映像标记指定存储库 URL，可以从 Amazon ECR 公开映像浏览馆中提取 AWS for Fluent Bit 映像。可在 Amazon ECR 公开映像浏览馆上的**映像标签**选项卡上找到映像标签。

下面说明 Docker CLI 使用的语法。

```
docker pull public.ecr.aws/aws-observability/aws-for-fluent-bit:tag
```

例如，您可以使用此 Docker CLI 命令拉取最新的稳定 AWS for Fluent Bit 映像。

```
docker pull public.ecr.aws/aws-observability/aws-for-fluent-bit:windowsservercore-stable
```

**注意**  
可以进行未经身份验证的拉取，但速率限制低于经过身份验证的拉取。拉取前如果要使用 AWS 账户验证身份，请使用以下命令。  

```
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
```

## Amazon ECR
<a name="firelens-image-ecr"></a>

AWS for Fluent Bit 映像可在 Amazon ECR 上获得高可用性。可以使用以下命令来检索映像 URI 并确定映像在给定 AWS 区域 区域的可用性。

### Linux
<a name="firelens-image-ecr-linux"></a>

可以使用以下命令检索最新的稳定 AWS for Fluent Bit 映像 URI。

```
aws ssm get-parameters \
      --names /aws/service/aws-for-fluent-bit/stable \
      --region us-east-1
```

使用以下命令来查询 Systems Manager Parameter Store 参数可以列出 AWS for Fluent Bit 映像的所有版本。

```
aws ssm get-parameters-by-path \
      --path /aws/service/aws-for-fluent-bit \
      --region us-east-1
```

可以通过引用 Systems Manager 参数存储名称在 CloudFormation 模板中引用最新的稳定 AWS for Fluent Bit 映像。以下是示例：

```
Parameters:
  FireLensImage:
    Description: Fluent Bit image for the FireLens Container
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/aws-for-fluent-bit/stable
```

**注意**  
如果命令失败或没有输出，则映像在调用该命令的 AWS 区域不可用。

### Windows
<a name="firelens-image-ecr-windows"></a>

可以使用以下命令检索最新的稳定 AWS for Fluent Bit 映像 URI。

```
aws ssm get-parameters \
      --names /aws/service/aws-for-fluent-bit/windowsservercore-stable \
      --region us-east-1
```

使用以下命令来查询 Systems Manager Parameter Store 参数可以列出 AWS for Fluent Bit 映像的所有版本。

```
aws ssm get-parameters-by-path \
      --path /aws/service/aws-for-fluent-bit/windowsservercore \
      --region us-east-1
```

可以通过引用 Systems Manager 参数存储名称在 CloudFormation 模板中引用最新的稳定 AWS for Fluent Bit 映像。以下是示例：

```
Parameters:
  FireLensImage:
    Description: Fluent Bit image for the FireLens Container
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/aws-for-fluent-bit/windowsservercore-stable
```

# Amazon ECS 任务定义示例：将日志路由到 FireLens
<a name="firelens-taskdef"></a>

要将自定义日志路由与 FireLens 结合使用，您必须在任务定义中指定以下内容：
+ 包含 FireLens 配置的日志路由器容器。我们建议将容器标记为 `essential`。
+ 一个或多个包含指定 `awsfirelens` 日志驱动程序的日志配置的应用程序容器。
+ 一个任务 IAM 角色 Amazon 资源名称（ARN），其中包含任务路由日志所需的权限。

使用 AWS 管理控制台创建新的任务定义时，通过 Firelens 集成部分可以轻松添加日志路由器容器。有关更多信息，请参阅 [使用控制台创建 Amazon ECS 任务定义](create-task-definition.md)。

Amazon ECS 将转换日志配置并生成 Fluentd 或 Fluent Bit 输出配置。输出配置挂载在 `/fluent-bit/etc/fluent-bit.conf`（对于 Fluent Bit）和 `/fluentd/etc/fluent.conf`（对于 Fluentd）处的日志路由容器中。

**重要**  
FireLens 在端口 `24224` 上侦听。因此，为了确保从任务外部无法访问 FireLens 日志路由器，不得允许任务使用的安全组中端口 `24224` 上的入口流量。对于使用 `awsvpc` 网络模式的任务，这是与任务关联的安全组。对于使用 `host` 网络模式的任务，它是与托管任务的 Amazon EC2 实例关联的安全组。对于使用 `bridge` 网络模式的任务，请勿创建任何使用端口 `24224` 的端口映射。

默认情况下，Amazon ECS 会在日志条目中添加其他字段来帮助标识日志源。
+ `ecs_cluster`：任务所属的集群的名称。
+ `ecs_task_arn` – 容器所属的任务的完整 Amazon 资源名称（ARN）。
+ `ecs_task_definition`：任务正在使用的任务定义名称和修订。
+ `ec2_instance_id` – 容器托管于的 Amazon EC2 实例 ID。此字段仅对使用 EC2 启动类型的任务有效。

如果您不想要元数据，可以将 `enable-ecs-log-metadata` 设置为 `false`。

下面的任务定义示例定义了一个日志路由器容器，它使用 Fluent Bit 将日志路由到 CloudWatch Logs。该示例还定义了一个应用程序容器，它使用日志配置将日志路由到 Amazon Data Firehose 并将用于缓冲事件的内存设置为 2MiB。

**注意**  
有关更多示例任务定义，请参阅 GitHub 上的 [Amazon ECS FireLens 示例](https://github.com/aws-samples/amazon-ecs-firelens-examples)。

```
{
  "family": "firelens-example-firehose",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecs_task_iam_role",
  "containerDefinitions": [
    {
            "name": "log_router",
            "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:3",
            "cpu": 0,
            "memoryReservation": 51,
            "portMappings": [],
            "essential": true,
            "environment": [],
            "mountPoints": [],
            "volumesFrom": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "/ecs/ecs-aws-firelens-sidecar-container",
                    "mode": "non-blocking",
                    "awslogs-create-group": "true",
                    "max-buffer-size": "25m",
                    "awslogs-region": "us-east-1",
                    "awslogs-stream-prefix": "firelens"
                },
                "secretOptions": []
            },
            "systemControls": [],
            "firelensConfiguration": {
                "type": "fluentbit"
            }
        },
    {
      "essential": true,
      "image": "public.ecr.aws/docker/library/httpd:latest",
      "name": "app",
      "logConfiguration": {
        "logDriver": "awsfirelens",
        "options": {
          "Name": "firehose",
          "region": "us-west-2",
          "delivery_stream": "my-stream",
          "log-driver-buffer-limit": "1048576"
        }
      },
      "memoryReservation": 100
    }
  ]
}
```

在 `logConfiguration` 对象中指定为选项的键值对用于生成 Fluentd 或 Fluent Bit 输出配置。以下是来自 Fluent Bit 输出定义的代码示例。

```
[OUTPUT]
    Name   firehose
    Match  app-firelens*
    region us-west-2
    delivery_stream my-stream
```

**注意**  
FirelLens 可管理 `match` 配置。您没有在任务定义中指定 `match` 配置。

## 使用自定义配置文件
<a name="firelens-taskdef-customconfig"></a>

您可以指定自定义配置文件。配置文件格式是您所使用的日志路由器的本机格式。有关更多信息，请参阅 [Fluentd Config 文件语法](https://docs.fluentd.org/configuration/config-file)和 [YAML 配置](https://docs.fluentbit.io/manual/administration/configuring-fluent-bit/yaml)。

在您的自定义配置文件中，对于使用 `bridge` 或 `awsvpc` 网络模式的任务，请勿通过 TCP 设置 Fluentd 或 Fluent Bit 转发输入，因为 FireLens 会将它添加到输入配置中。

您的 FireLens 配置必须包含以下选项才能指定自定义配置文件：

`config-file-type`  
自定义配置文件的源位置。可用选项为 `s3` 或 `file`。  
托管在 AWS Fargate 上的任务仅支持 `file` 配置文件类型。但是，您可以使用适用于 Fluent Bit 的 AWS 初始化容器在 AWS Fargate 上使用 Amazon S3 中托管的配置文件。有关更多信息，请参阅 GitHub 上的 [ECS 上的 Fluent Bit 的初始化进程，多配置支持](https://github.com/aws/aws-for-fluent-bit/blob/mainline/use_cases/init-process-for-fluent-bit/README.md)。

`config-file-value`  
自定义配置文件的源。如果使用 `s3` 配置文件类型，则配置文件值是 Amazon S3 存储桶和文件的完整 ARN。如果使用 `file` 配置文件类型，则配置文件值是容器映像中或挂载到容器中的卷上存在的配置文件的完整路径。  
在使用自定义配置文件时，必须指定一个与 FireLens 所用路径不同的路径。Amazon ECS 保留对于 Fluent Bit 和 `/fluentd/etc/fluent.conf` 对于 Fluentd 的文件路径 `/fluent-bit/etc/fluent-bit.conf`。

以下示例显示了指定自定义配置时所需的语法。

**重要**  
要指定托管于 Amazon S3 中的自定义配置文件，请确保已创建具有适当权限的任务执行 IAM 角色。

下面显示了在指定自定义配置时所需的语法。

```
{
  "containerDefinitions": [
    {
      "essential": true,
      "image": "906394416424.dkr.ecr.us-west-2.amazonaws.com/aws-for-fluent-bit:3",
      "name": "log_router",
      "firelensConfiguration": {
        "type": "fluentbit",
        "options": {
          "config-file-type": "s3 | file",
          "config-file-value": "arn:aws:s3:::amzn-s3-demo-bucket/fluent.conf | filepath"
        }
      }
    }
  ]
}
```

**注意**  
托管在 AWS Fargate 上的任务仅支持 `file` 配置文件类型。但是，您可以使用适用于 Fluent Bit 的 AWS 初始化容器在 AWS Fargate 上使用 Amazon S3 中托管的配置文件。有关更多信息，请参阅 GitHub 上的 [ECS 上的 Fluent Bit 的初始化进程，多配置支持](https://github.com/aws/aws-for-fluent-bit/blob/mainline/use_cases/init-process-for-fluent-bit/README.md)。

# 在 Amazon ECS 中使用非 AWS 容器映像
<a name="private-auth"></a>

使用私有注册表在 AWS Secrets Manager 中存储您的凭证，然后在任务定义中引用它们。这提供了一种方法来引用存在于 AWS 以外的私有注册表中的容器映像，这需要在任务定义中进行身份验证。在 Fargate 上托管的任务、Amazon EC2 实例以及使用 Amazon ECS Anywhere 的外部实例都支持此功能。

**重要**  
如果您的任务定义引用了存储在 Amazon ECR 中的映像，则此主题不适用。有关更多信息，请参阅 *Amazon Elastic Container Registry 用户指南*中的[使用 Amazon ECR 和 Amazon ECS](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ECR_on_ECS.html)。

对于 Amazon EC2 实例上托管的任务，此功能要求您具有版本 `1.19.0` 或更高版本的容器代理。但是，我们建议使用最新的容器代理版本。有关如何检查您的代理版本并更新到最新版本的信息，请参阅[更新 Amazon ECS 容器代理](ecs-agent-update.md)。

对于 Fargate 上托管的任务，此功能需要平台版本 `1.2.0` 或更高版本。有关信息，请参阅[适用于 Amazon ECS 的 Fargate 平台版本](platform-fargate.md)。

在容器定义中，使用您创建的密钥的详细信息指定 `repositoryCredentials` 对象。引用的密钥可以来自与使用此密钥的任务不同的 AWS 区域 或不同的账户。

**注意**  
使用 Amazon ECS API、AWS CLI 或 AWS SDK 时，如果密钥存在于要启动的任务所在的AWS 区域，可以使用密钥的完整 ARN 或名称。如果密钥存在于另一个账户中，则必须指定密钥的完整 ARN。使用 AWS 管理控制台 时，必须始终指定密钥的完整 ARN。

下面是显示必需参数的任务定义代码段：

替换以下参数：
+ 将 *private-repo* 替换为私有存储库主机名称 
+ 将 *private-image* 替换为映像名称
+ 将 *arn:aws:secretsmanager:region:aws\$1account\$1id:secret:secret\$1name* 替换为密钥 Amazon 资源名称（ARN）

```
"containerDefinitions": [
    {
        "image": "private-repo/private-image",
        "repositoryCredentials": {
            "credentialsParameter": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name"
        }
    }
]
```

**注意**  
启用私有注册表身份验证的另一种方法使用 Amazon ECS 容器代理环境变量向私有注册表进行身份验证。此方法仅支持 Amazon EC2 实例上托管的任务。有关更多信息，请参阅 [为私有 Docker 映像配置 Amazon ECS 容器实例](private-auth-container-instances.md)。

**要使用私有注册表**

1. 任务定义必须具有任务执行角色。这允许容器代理拉取容器映像。有关更多信息，请参阅 [Amazon ECS 任务执行 IAM 角色](task_execution_IAM_role.md)。

   借助私有注册表身份验证，您的 Amazon ECS 任务将可以从位于 AWS 之外且需要身份验证凭证的私有注册表（例如 Docker Hub、Quay.io 或您自己的私有注册表）拉取容器映像。此功能使用 Secrets Manager 来安全地存储注册表凭证，然后使用 `repositoryCredentials` 参数在任务定义中引用这些凭证。

   有关配置私有注册表身份验证的更多信息，请参阅[在 Amazon ECS 中使用非 AWS 容器映像](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/private-auth.html)。

   要允许访问包含您的私有注册表凭证的密钥，请将以下权限作为内联策略添加到任务执行角色中。有关更多信息，请参阅[添加和删除 IAM 策略。](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)
   + `secretsmanager:GetSecretValue`：从 Secrets Manager 检索私有注册表凭证时为必需。
   + `kms:Decrypt`：仅当您的密钥使用自定义 KMS 密钥而不是默认密钥时才需要。您的自定义密钥的 Amazon 资源名称（ARN）必须添加为资源。

   下面是添加所需权限的示例内联策略。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "kms:Decrypt",
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": [
                   "arn:aws:secretsmanager:us-east-1:111122223333:secret:secret_name",
                   "arn:aws:kms:us-east-1:111122223333:key/key_id"
               ]
           }
       ]
   }
   ```

------

1. 使用 AWS Secrets Manager 为您的私有注册表凭证创建密钥。有关如何创建密钥的信息，请参阅《AWS Secrets Manager 用户指南》**中的[创建 AWS Secrets Manager 密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

   使用以下格式输入您的私有注册表凭证：

   ```
   {
     "username" : "privateRegistryUsername",
     "password" : "privateRegistryPassword"
   }
   ```

1. 注册任务定义。有关更多信息，请参阅 [使用控制台创建 Amazon ECS 任务定义](create-task-definition.md)。

# 使用容器重启策略重启 Amazon ECS 任务中的单个容器
<a name="container-restart-policy"></a>

您可以为任务定义中定义的每个基本容器和非基本容器启用重启策略，以更快地克服暂时性失败并保持任务可用性。为容器启用重启策略后，Amazon ECS 可以在容器退出时重启该容器，而无需替换任务。

默认情况下，容器不会启用重启策略。为容器启用重启策略时，可以指定容器不会重启的退出代码。这些可能是表示成功的退出代码，例如退出代码 `0`，此类退出代码表示不需要重启。您还可以指定容器必须成功运行多长时间后才能尝试重启。有关这些参数的更多信息，请参阅 [重启策略](task_definition_parameters.md#container_definition_restart_policy)。有关指定这些值的任务定义示例，请参阅[在 Amazon ECS 任务定义中指定容器重启策略](container-restart-policy-example.md)。

您可以使用 Amazon ECS 任务元数据端点或 CloudWatch Container Insights 来监控容器重启的次数。有关任务元数据端点的更多信息，请参阅 [Amazon ECS 任务元数据端点版本 4](task-metadata-endpoint-v4.md) 和 [Fargate 上任务的 Amazon ECS 任务元数据端点版本 4](task-metadata-endpoint-v4-fargate.md)。有关适用于 Amazon ECS 的 Container Insights 指标的更多信息，请参阅《Amazon CloudWatch 用户指南》中的 [Amazon ECS Container Insights metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-metrics-ECS.html)**。

在 Fargate、Amazon EC2 实例以及使用 Amazon ECS Anywhere 的外部实例上托管的任务都支持容器重启策略。

## 注意事项
<a name="container-restart-policy-considerations"></a>

为容器启用重启策略时应注意以下几个方面：
+ Fargate 上的 Windows 容器不支持重启策略。
+ 对于 Amazon EC2 实例上托管的任务，此功能要求您具有版本 `1.86.0` 或更高版本的容器代理。但是，我们建议使用最新的容器代理版本。有关如何检查您的代理版本并更新到最新版本的信息，请参阅[更新 Amazon ECS 容器代理](ecs-agent-update.md)。
+ 如果在 `bridge` 网络模式下使用 EC2，则在重启 FireLens 日志路由器容器（容器定义中包含 `firelensConfiguration` 对象的容器）后，应用程序容器中的 `FLUENT_HOST` 环境变量可能会变得不准确。这是因为 `FLUENT_HOST` 是一个动态 IP 地址，重启后就会改变。地址改变后，直接从应用程序容器登录到 `FLUENT_HOST` IP 地址可能会失败。有关 `FLUENT_HOST`的更多信息，请参阅[配置 Amazon ECS 日志，以实现高吞吐量](firelens-docker-buffer-limit.md)。
+ Amazon ECS 代理处理容器重启策略。如果由于某些意外原因导致 Amazon ECS 代理失败或不再运行，则容器将不会重启。
+  策略中定义的重启尝试期决定了在 Amazon ECS 重启容器之前容器必须运行的时间段（以秒为单位）。

# 在 Amazon ECS 任务定义中指定容器重启策略
<a name="container-restart-policy-example"></a>

要在任务定义中为容器指定重启策略，请在容器定义中指定 `restartPolicy` 对象。有关 `restartPolicy` 对象的更多信息，请参阅[重启策略](task_definition_parameters.md#container_definition_restart_policy)。

下面的任务定义使用 Fargate 上的 Linux 容器来设置 Web 服务器。该容器定义包括 `restartPolicy` 对象，并将 `enabled` 设置为 true 以为该容器启用重启策略。容器必须运行 180 秒后才能重启，并且如果容器以退出代码 `0` 退出，则表示成功，也不会重启容器。

```
{
  "containerDefinitions": [
    {
      "command": [
        "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /usr/local/apache2/htdocs/index.html && httpd-foreground\""
      ],
      "entryPoint": ["sh", "-c"],
      "essential": true,
      "image": "public.ecr.aws/docker/library/httpd:2.4",
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/fargate-task-definition",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "name": "sample-fargate-app",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "restartPolicy": {
        "enabled": true,
        "ignoredExitCodes": [0],
        "restartAttemptPeriod": 180
      }
    }
  ],
  "cpu": "256",
  "executionRoleArn": "arn:aws:iam::012345678910:role/ecsTaskExecutionRole",
  "family": "fargate-task-definition",
  "memory": "512",
  "networkMode": "awsvpc",
  "runtimePlatform": {
    "operatingSystemFamily": "LINUX"
  },
  "requiresCompatibilities": ["FARGATE"]
}
```

将任务定义注册到容器定义中的 `restartPolicy` 对象后，您可以使用该任务定义运行任务或创建服务。有关更多信息，请参阅[将应用程序作为 Amazon ECS 任务运行](standalone-task-create.md)和[创建 Amazon ECS 滚动更新部署](create-service-console-v2.md)。

# 将敏感数据传递给 Amazon ECS 容器
<a name="specifying-sensitive-data"></a>

您可以将敏感数据（例如数据库凭证）安全地传递到容器中。

应用程序经常使用诸如 API 密钥和数据库凭证之类的密钥来访问其他系统。它们通常由用户名和密码、证书或 API 密钥组成。对这些密钥的访问应仅限于使用 IAM 并在运行时注入到容器中的特定 IAM 主体。

密钥可以从 AWS Secrets Manager 和 Amazon EC2 Systems Manager Parameter Store 无缝注入容器中。这些密钥可以在您的任务中作为以下任何内容引用。

1. 它们被引用为使用 `secrets` 容器定义参数的环境变量。

1. 如果您的日志记录平台需要身份验证，它们被引用为 `secretOptions`。有关更多信息，请参阅[日志记录配置选项](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LogConfiguration.html#API_LogConfiguration_Contents)。

1. 如果从中提取容器的注册表需要身份验证，则使用 `repositoryCredentials` 容器定义参数的映像将它们作为密钥引用。从 Amazon ECR 公开映像浏览馆中提取映像时使用此方法。有关更多信息，请参阅[任务的私有注册表身份验证](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/private-auth.html)。

在设置密钥管理时，建议您执行以下操作。

## 使用 AWS Secrets Manager 或 AWS Systems Manager Parameter Store 来存储密钥材料
<a name="security-secrets-management-recommendations-storing-secret-materials"></a>

您应该将 API 密钥、数据库凭证和其他密钥材料安全地存储在 Secrets Manager 中，或者将其作为加密参数存储在 Systems Manager Parameter Store 中。这些服务之所以相似，是因为它们都是使用 AWS KMS 加密敏感数据的托管键值存储。但是 Secrets Manager 还包括自动轮换密钥、生成随机密钥和在账户之间共享密钥的功能。要利用这些功能，请使用 Secrets Manager。否则，请使用 Systems Manager Parameter Store 中的加密参数。

**重要**  
如果您的密钥发生更改，则必须强制进行新的部署或启动新任务以检索最新的密钥值。有关更多信息，请参阅以下主题：  
任务 – 停止任务，然后启动它。有关更多信息，请参阅[停止 Amazon ECS 任务](standalone-task-stop.md)和[将应用程序作为 Amazon ECS 任务运行](standalone-task-create.md)。
服务 – 更新服务并使用强制新部署选项。有关更多信息，请参阅 [更新 Amazon ECS 服务](update-service-console-v2.md)。

## 从加密的 Amazon S3 存储桶中检索数据
<a name="security-secrets-management-recommendations-encrypted-s3-buckets"></a>

您应将密钥存储在加密的 Amazon S3 存储桶中，并使用任务角色来限制对这些密钥的访问权限。这样可以防止环境变量的值无意中泄漏到日志中，以及在运行 `docker inspect` 时被泄露。执行此操作时，必须编写应用程序以从 Amazon S3 存储桶中读取密钥。有关说明，请参阅[为 Amazon S3 存储桶设置默认服务器端加密行为](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-encryption.html)。

## 使用 sidecar 容器将密钥挂载到卷上
<a name="security-secrets-management-recommendations-mount-secret-volumes"></a>

由于环境变量会增加数据泄露的风险，因此您应该运行一个 sidecar 容器，以从 AWS Secrets Manager 中读取密钥并将其写入共享卷中。通过使用 [Amazon ECS 容器排序](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDependency.html)，此容器可以在应用程序容器之前运行和退出。当您执行此操作时，应用程序容器随后会挂载写入密钥的卷。与 Amazon S3 存储桶方法类似，必须编写您的应用程序以从共享卷中读取密钥。由于该卷的作用域仅限于任务，因此该卷将在任务停止后自动删除。有关示例，请参阅 [task-def.json](https://github.com/aws-samples/aws-secret-sidecar-injector/blob/master/ecs-task-def/task-def.json) 项目。

在 Amazon EC2 上，可使用 AWS KMS 客户托管密钥对写入密钥的卷进行加密。在 AWS Fargate 上，使用服务托管密钥自动加密卷存储。

# 将单个环境变量传递给 Amazon ECS 容器
<a name="taskdef-envfiles"></a>

**重要**  
我们建议将您的敏感数据存储在 AWS Secrets Manager 密钥或 AWS Systems Manager Parameter Store 参数中。有关更多信息，请参阅 [将敏感数据传递给 Amazon ECS 容器](specifying-sensitive-data.md)。  
任务定义中指定的环境变量可由允许执行任务定义 `DescribeTaskDefinition` 操作的所有用户和角色读取。

您可以通过以下方式将环境变量传递到容器：
+ 单独，使用 `environment` 容器定义参数。这会将 `--env` 选项映射到 [https://docs.docker.com/reference/cli/docker/container/run/](https://docs.docker.com/reference/cli/docker/container/run/)。
+ 批量，使用 `environmentFiles` 容器定义参数列出包含环境变量的一个或多个文件。该文件必须托管在 Amazon S3 中。这会将 `--env-file` 选项映射到 [https://docs.docker.com/reference/cli/docker/container/run/](https://docs.docker.com/reference/cli/docker/container/run/)。

以下是演示如何指定单个环境变量的任务定义的代码段。

```
{
    "family": "",
    "containerDefinitions": [
        {
            "name": "",
            "image": "",
            ...
            "environment": [
                {
                    "name": "variable",
                    "value": "value"
                }
            ],
            ...
        }
    ],
    ...
}
```

# 将环境变量传递给 Amazon ECS 容器
<a name="use-environment-file"></a>

**重要**  
我们建议将您的敏感数据存储在 AWS Secrets Manager 密钥或 AWS Systems Manager Parameter Store 参数中。有关更多信息，请参阅 [将敏感数据传递给 Amazon ECS 容器](specifying-sensitive-data.md)。  
环境变量文件是 Amazon S3 中的对象，所有 Amazon S3 安全注意事项都适用。  
您不能在 Windows 容器和 Fargate 上的 Windows 容器上使用 `environmentFiles` 参数。

您可以创建环境变量文件，并将其存储在 Amazon S3 中，以便将环境变量传递给您的容器。

通过在文件中指定环境变量，您可以批量注入环境变量。在容器定义中，使用包含环境变量文件的 Amazon S3 存储桶列表指定 `environmentFiles` 对象。

Amazon ECS 不对环境变量强制实施大小限制，但大型环境变量文件可能会填满磁盘空间。使用环境变量文件的每个任务都会导致文件的副本下载到磁盘。作为任务清理的一部分，Amazon ECS 会删除文件。

有关支持的环境变量的信息，请参阅[高级容器定义参数：环境](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definition_environment)。

在容器定义中指定环境变量文件时，请考虑以下因素。
+ 对于 Amazon EC2 上的 Amazon ECS 任务，您的容器实例需要版本 `1.39.0` 或更高版本的容器代理才能使用此功能。有关如何检查您的代理版本并更新到最新版本的信息，请参阅[更新 Amazon ECS 容器代理](ecs-agent-update.md)。
+ 对于 AWS Fargate 上的 Amazon ECS 任务，您的任务必须使用平台版本 `1.4.0` 或更高版本（Linux）来使用此功能。有关更多信息，请参阅 [适用于 Amazon ECS 的 Fargate 平台版本](platform-fargate.md)。

  验证操作系统平台是否支持该变量。有关更多信息，请参阅 [容器定义](task_definition_parameters.md#container_definitions) 和 [其他任务定义参数](task_definition_parameters.md#other_task_definition_params)。
+ 该文件必须使用 `.env` 文件扩展名和 UTF-8 编码。
+ 该任务执行角色需要使用此功能和 Amazon S3 的额外权限。这允许容器代理从 Amazon S3 中提取环境变量文件。有关更多信息，请参阅 [Amazon ECS 任务执行 IAM 角色](task_execution_IAM_role.md)。
+ 每个任务定义最多只能有 10 个文件。
+ 环境文件中的每一行都必须包含 `VARIABLE=VALUE` 格式的环境变量。空格或引号作为 Amazon ECS 文件的值的一部分**包含**。以开头的行 `#` 被视为注释并会被忽略。有关环境变量文件语法的更多信息，请参阅 Docker 文档中的 [Set environment variables (-e, --env, --env-file)](https://docs.docker.com/reference/cli/docker/container/run/#env)。

  以下是合适的语法。

  ```
  #This is a comment and will be ignored
  VARIABLE=VALUE
  ENVIRONMENT=PRODUCTION
  ```
+ 如果在容器定义中存在使用 `environment` 参数指定的环境变量，则这些变量的优先级高于环境文件中包含的变量。
+ 如果指定了多个环境文件并且其中包含相同变量，则会按输入顺序处理这些文件。这意味着将使用变量的第一个值，并忽略重复变量的后续值。建议您使用唯一的变量名。
+ 如果将环境文件指定为容器覆盖，则将使用它。此外，容器定义中指定的任何其他环境文件都将被忽略。
+ 以下规则适用于 Fargate：
  + 该文件的处理方式与原生 Docker env-file 类似。
  + 容器中不会出现引用了空白且存储在 Amazon S3 中的环境变量的容器定义。
  + 不支持 shell 转义处理。
  + 容器入口点解释 `VARIABLE` 值。

## 示例
<a name="environment-file-example"></a>

以下是演示如何指定环境变量文件的任务定义的代码段。

```
{
    "family": "",
    "containerDefinitions": [
        {
            "name": "",
            "image": "",
            ...
            "environmentFiles": [
                {
                    "value": "arn:aws:s3:::amzn-s3-demo-bucket/envfile_object_name.env",
                    "type": "s3"
                }
            ],
            ...
        }
    ],
    ...
}
```

# 在 Amazon ECS 中以编程方式传递 Secrets Manager 密钥
<a name="secrets-app-secrets-manager"></a>

您可以使用 Secrets Manager 来存储敏感数据，而不是在应用程序中以纯文本形式对敏感信息进行硬编码。

我们建议使用这种方法来检索敏感数据，因为如果随后更新 Secrets Manager 密钥，应用程序会自动检索该密钥的最新版本。

可以在 Secrets Manager 中创建秘密。创建 Secrets Manager 密钥后，更新应用程序代码以检索该密钥。

在 Secrets Manager 中保护敏感数据之前，请查看以下注意事项。
+ 仅存储文本数据的机密，这些机密是使用 `SecretString` 参数 [CreateSecret](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html) 支持 API。不支持存储二进制数据的密钥，这些密钥是使用 [CreateSecret](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_CreateSecret.html) API 的 `SecretBinary` 参数创建的。
+ 使用接口 VPC 端点增强安全控制。您必须为 Secrets Manager 创建接口 VPC 端点。有关 VPC 端点的信息，请参阅《AWS Secrets Manager 用户指南》**中的[创建 VPC 端点](https://docs.aws.amazon.com/secretsmanager/latest/userguide/setup-create-vpc.html)。
+ 您的任务使用的 VPC 必须使用 DNS 解析。
+ 任务定义必须使用具有额外 Secrets Manager 权限的任务角色。有关更多信息，请参阅 [Amazon ECS 任务 IAM 角色](task-iam-roles.md)。

## 创建 Secrets Manager 密钥
<a name="secrets-app-secrets-manager-create-secret"></a>

您可以使用 Secrets Manager 控制台为您的敏感数据创建密钥。有关如何创建密钥的信息，请参阅**《AWS Secrets Manager 用户指南》中的[创建 AWS Secrets Manager 密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

## 更新应用程序以通过编程方式检索 Secrets Manager 密钥
<a name="secrets-app-secrets-manager-update-app"></a>

您可以直接从应用程序调用 Secrets Manager API 来检索密钥。有关信息，请参阅《AWS Secrets Manager 用户指南》**中的[从 AWS Secrets Manager 中检索密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets.html)。

要检索存储在 AWS Secrets Manager 中的敏感数据，请参阅 *AWS SDK 代码示例代码库*中的[使用 AWS SDK 的 AWS Secrets Manager 的代码示例](https://docs.aws.amazon.com/code-library/latest/ug/secrets-manager_code_examples.html)。

# 在 Amazon ECS 中以编程方式传递 Systems Manager Parameter Store 密钥
<a name="secrets-app-ssm-paramstore"></a>

Systems Manager Parameter Store 提供了密钥的安全存储和管理。您可以将密码、数据库字符串、EC2 实例 ID 和 AMI ID 以及许可证代码等数据存储为参数值，而不是在应用程序中将这些信息硬编码。可以将值存储为纯文本或加密数据。

建议使用这种方法来检索敏感数据，因为如果随后更新 Systems Manager Parameter Store 参数，应用程序会自动检索最新版本。

在 Systems Manager Parameter Store 中保护敏感数据之前，请查看以下注意事项。
+ 仅支持存储文本数据的密钥。不支持存储二进制数据的密钥。
+ 使用接口 VPC 端点增强安全控制。
+ 您的任务使用的 VPC 必须使用 DNS 解析。
+ 对于使用 EC2 的任务，必须使用 Amazon ECS 代理配置变量 `ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE=true` 才能使用此功能。您可以在创建容器实例的过程中将其添加到 `/etc/ecs/ecs.config` 文件中，也可以将其添加到现有实例中，然后重新启动 ECS 代理。有关更多信息，请参阅 [Amazon ECS 容器代理配置](ecs-agent-config.md)。
+ 任务定义必须使用具有额外 Systems Manager Parameter Store 权限的任务角色。有关更多信息，请参阅 [Amazon ECS 任务 IAM 角色](task-iam-roles.md)。

## 创建 参数
<a name="secrets-app-ssm-paramstore-create-secret"></a>

您可以使用 Systems Manager 控制台为您的敏感数据创建 Systems Manager Parameter Store 参数。有关更多信息，请参阅**《AWS Systems Manager 用户指南》中的[创建 Systems Manager 参数（控制台）](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-create-console.html)或[创建 Systems Manager 参数（AWS CLI）](https://docs.aws.amazon.com/systems-manager/latest/userguide/param-create-cli.html)。

## 更新应用程序以通过编程方式检索 Systems Manager Parameter Store 密钥
<a name="secrets-app-ssm-paramstore-update-app"></a>

要检索存储在 Systems Manager Parameter Store 参数中存储的敏感数据，请参阅 *AWS SDK 代码示例代码库*中的[使用 AWS SDK 的 Systems Manager 的代码示例](https://docs.aws.amazon.com/code-library/latest/ug/ssm_code_examples.html)。

# 通过 Amazon ECS 环境变量传递 Secrets Manager 密钥
<a name="secrets-envvar-secrets-manager"></a>

当您将密钥作为环境变量注入时，可以指定密钥的完整内容、密钥内的特定 JSON 键。这将帮助您控制提供给容器的敏感数据。有关密钥版本控制的更多信息，请参阅《AWS Secrets Manager 用户指南》**中的 [What's in a Secrets Manager secret?](https://docs.aws.amazon.com/secretsmanager/latest/userguide/whats-in-a-secret.html#term_version)。

在使用环境变量将 Secrets Manager 密钥注入容器时，应考虑以下事项。
+ 最初启动容器时，会将敏感数据注入容器中。如果随后更新或轮换密钥，则容器将不会自动接收更新后的值。您必须启动新任务，或者如果您的任务是服务的一部分，则可以更新服务并使用**强制新部署**选项来强制服务启动新任务。
+ 在容器上运行的应用程序以及容器日志和调试工具可以访问环境变量。
+ 对于 AWS Fargate 上的 Amazon ECS 任务，请考虑以下事项：
  + 要将密钥的完整内容注入为环境变量或注入到日志配置中，您必须使用平台版本 `1.3.0` 或更高版本的平台。有关信息，请参阅[适用于 Amazon ECS 的 Fargate 平台版本](platform-fargate.md)。
  + 要将特定 JSON 密钥或密钥版本注入为环境变量或注入到日志配置中，您必须使用平台版本 `1.4.0` 或更高版本（Linux）或者 `1.0.0`（Windows）。有关信息，请参阅[适用于 Amazon ECS 的 Fargate 平台版本](platform-fargate.md)。
+ 对于 EC2 上的 Amazon ECS 任务，应注意以下事项：
  + 要使用特定的 JSON 密钥或密钥版本注入密钥，容器实例必须具有版本 `1.37.0` 或更高版本的容器代理。但是，我们建议使用最新的容器代理版本。有关检查您的代理版本并更新到最新版本的信息，请参阅[更新 Amazon ECS 容器代理](ecs-agent-update.md)。

    要将密钥的完整内容注入为环境变量或将密钥注入日志配置中，您的容器实例必须具有版本 `1.22.0` 或更高版本的容器代理。
+ 使用接口 VPC 端点增强安全控制措施，并通过私有子网连接到 Secrets Manager。您必须为 Secrets Manager 创建接口 VPC 端点。有关 VPC 端点的信息，请参阅《AWS Secrets Manager 用户指南》**中的[创建 VPC 端点](https://docs.aws.amazon.com/secretsmanager/latest/userguide/setup-create-vpc.html)。有关使用 Secrets Manager 和 Amazon VPC 的更多信息，请参阅[如何在 Amazon VPC 内连接到 Secrets Manager 服务](https://aws.amazon.com/blogs//security/how-to-connect-to-aws-secrets-manager-service-within-a-virtual-private-cloud/)。
+ 对于配置为使用 `awslogs` 日志记录驱动程序的 Windows 任务，您还必须在容器实例上设置 `ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE` 环境变量。使用以下语法：

  ```
  <powershell>
  [Environment]::SetEnvironmentVariable("ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE", $TRUE, "Machine")
  Initialize-ECSAgent -Cluster <cluster name> -EnableTaskIAMRole -LoggingDrivers '["json-file","awslogs"]'
  </powershell>
  ```
+ 任务定义必须使用具有 Secrets Manager 额外权限的任务执行角色。有关更多信息，请参阅 [Amazon ECS 任务执行 IAM 角色](task_execution_IAM_role.md)。

## 创建 AWS Secrets Manager 密钥
<a name="secrets-envvar-secrets-manager-create-secret"></a>

您可以使用 Secrets Manager 控制台为您的敏感数据创建密钥。有关更多信息，请参阅**《AWS Secrets Manager 用户指南》中的[创建 AWS Secrets Manager 密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

## 将环境变量添加到容器定义中
<a name="secrets-envvar-secrets-manager-update-container-definition"></a>

在容器定义中，可以指定以下内容：
+ `secrets` 对象，该对象包含要在容器中设置的环境变量名称
+ Secrets Manager 密钥的 Amazon 资源名称（ARN）。
+ 其他参数，这些参数包含要提供给容器的敏感数据

以下示例显示必须为 Secrets Manager 密钥指定的完整语法。

```
arn:aws:secretsmanager:region:aws_account_id:secret:secret-name:json-key:version-stage:version-id
```

下一部分介绍了其他参数。这些参数是可选的，但如果不使用它们，则必须包含冒号 `:` 以使用默认值。下面提供了示例，以便您了解更多上下文。

`json-key`  
使用要设置为环境变量值的值指定密钥-值对中密钥的名称。仅支持 JSON 格式的值。如果未指定 JSON 密钥，则使用密钥的完整内容。

`version-stage`  
指定要使用的密钥版本的暂存标签。如果指定了版本的暂存标签，则无法指定版本 ID。如果未指定版本阶段，则默认行为是使用 `AWSCURRENT` 暂存标签检索密钥。  
暂存标签用于在更新或轮换密钥的各个版本时对其进行跟踪。密钥的每个版本均有一个或多个暂存标签和一个 ID。

`version-id`  
指定要使用的密钥版本的唯一标识符。如果指定了版本 ID，则无法指定版本暂存标签。如果未指定版本 ID，则默认行为是使用 `AWSCURRENT` 暂存标签检索密钥。  
版本 ID 用于在更新或轮换密钥的各个版本时对其进行跟踪。密码的每个版本均有一个 ID。有关更多信息，请参阅 *AWS Secrets Manager 用户指南*中的 [AWS Secrets Manager 主要术语和概念。](https://docs.aws.amazon.com/secretsmanager/latest/userguide/terms-concepts.html#term_secret)

### 示例容器定义
<a name="secrets-examples"></a>

以下示例说明了可用于在容器定义中引用 Secrets Manager 密钥的方法。

**Example 引用完整密钥**  
以下是任务定义的片段，其中显示引用 Secrets Manager 密钥的完全文本时的格式。  

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-AbCdEf"
    }]
  }]
}
```
要从容器中访问此密钥的值，需要调用 `$environment_variable_name`。

**Example 引用完整密钥**  
以下是任务定义的片段，其中显示引用多个 Secrets Manager 密钥的完全文本时的格式。  

```
{
  "containerDefinitions": [{
     "secrets": [
      {
        "name": "environment_variable_name1",
         "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-AbCdEf"
      },
      {
        "name": "environment_variable_name2",
         "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-abcdef"
      },
      {
        "name": "environment_variable_name3",
        "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-ABCDEF"
      }
    ]
  }]
}
```
要从容器中访问此密钥的值，需要调用 `$environment_variable_name1`、`$environment_variable_name2` 和 `$environment_variable_name3`。

**Example 引用密钥中的特定密钥**  
下面显示了 [get-secret-value](https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/get-secret-value.html) 命令中的示例输出，其中显示了密钥的内容以及与之关联的版本暂存标签和版本 ID。  

```
{
    "ARN": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf",
    "Name": "appauthexample",
    "VersionId": "871d9eca-18aa-46a9-8785-981ddEXAMPLE",
    "SecretString": "{\"username1\":\"password1\",\"username2\":\"password2\",\"username3\":\"password3\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": 1581968848.921
}
```
通过在 ARN 的末尾指定密钥名称，引用容器定义中的上一个输出中的特定密钥。  

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf:username1::"
    }]
  }]
}
```

**Example 引用特定的密钥版本**  
下面显示了 [describe-secret](https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/describe-secret.html) 命令中的示例输出，其中显示了密钥的未加密内容以及密钥的所有版本的元数据。  

```
{
    "ARN": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf",
    "Name": "appauthexample",
    "Description": "Example of a secret containing application authorization data.",
    "RotationEnabled": false,
    "LastChangedDate": 1581968848.926,
    "LastAccessedDate": 1581897600.0,
    "Tags": [],
    "VersionIdsToStages": {
        "871d9eca-18aa-46a9-8785-981ddEXAMPLE": [
            "AWSCURRENT"
        ],
        "9d4cb84b-ad69-40c0-a0ab-cead3EXAMPLE": [
            "AWSPREVIOUS"
        ]
    }
}
```
通过在 ARN 的末尾指定密钥名称，引用容器定义中的上一个输出中的特定版本暂存标签。  

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf::AWSPREVIOUS:"
    }]
  }]
}
```
通过在 ARN 的末尾指定密钥名称，引用容器定义中的上一个输出中的特定版本 ID。  

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf:::9d4cb84b-ad69-40c0-a0ab-cead3EXAMPLE"
    }]
  }]
}
```

**Example 引用密钥的特定密钥和版本暂存标签**  
以下内容说明如何同时引用密钥中的特定密钥和特定版本暂存标签。  

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf:username1:AWSPREVIOUS:"
    }]
  }]
}
```
要指定特定密钥和版本 ID，请使用以下语法。  

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:appauthexample-AbCdEf:username1::9d4cb84b-ad69-40c0-a0ab-cead3EXAMPLE"
    }]
  }]
}
```

有关如何使用环境变量中指定的密钥创建任务定义的信息，请参阅 [使用控制台创建 Amazon ECS 任务定义](create-task-definition.md)。

# 通过 Amazon ECS 环境变量传递 Systems Manager 参数
<a name="secrets-envvar-ssm-paramstore"></a>

您可以使用 Amazon ECS 向容器中注入敏感数据，方法是将您的敏感数据存储在 AWS Systems Manager Parameter Store 参数中，然后在容器定义中引用它们。

在使用环境变量将 Systems Manager 密钥注入容器时，应注意以下事项。
+ 最初启动容器时，会将敏感数据注入容器中。如果随后更新或轮换密钥，则容器将不会自动接收更新后的值。您必须启动新任务，或者如果您的任务是服务的一部分，则可以更新服务并使用**强制新部署**选项来强制服务启动新任务。
+ 对于 AWS Fargate 上的 Amazon ECS 任务，应注意以下事项：
  + 要将密钥的完整内容注入为环境变量或注入到日志配置中，您必须使用平台版本 `1.3.0` 或更高版本的平台。有关信息，请参阅[适用于 Amazon ECS 的 Fargate 平台版本](platform-fargate.md)。
  + 要将特定 JSON 密钥或密钥版本注入为环境变量或注入到日志配置中，您必须使用平台版本 `1.4.0` 或更高版本（Linux）或者 `1.0.0`（Windows）。有关信息，请参阅[适用于 Amazon ECS 的 Fargate 平台版本](platform-fargate.md)。
+ 对于 EC2 上的 Amazon ECS 任务，应注意以下事项：
  + 要使用特定的 JSON 密钥或密钥版本注入密钥，容器实例必须具有版本 `1.37.0` 或更高版本的容器代理。但是，我们建议使用最新的容器代理版本。有关检查您的代理版本并更新到最新版本的信息，请参阅[更新 Amazon ECS 容器代理](ecs-agent-update.md)。

    要将密钥的完整内容注入为环境变量或将密钥注入日志配置中，您的容器实例必须具有版本 `1.22.0` 或更高版本的容器代理。
+ 使用接口 VPC 端点增强安全控制。您必须为 Systems Manager 创建接口 VPC 端点。有关 VPC 端点的信息，请参阅《AWS Systems Manager 用户指南》**中的[使用适用于 Systems Manager 的 VPC 端点提高 EC2 实例的安全性](https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-create-vpc.html)。
+ 任务定义必须使用具有额外 Systems Manager Parameter Store 权限的任务执行角色。有关更多信息，请参阅 [Amazon ECS 任务执行 IAM 角色](task_execution_IAM_role.md)。
+ 对于配置为使用 `awslogs` 日志记录驱动程序的 Windows 任务，您还必须在容器实例上设置 `ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE` 环境变量。使用以下语法：

  ```
  <powershell>
  [Environment]::SetEnvironmentVariable("ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE", $TRUE, "Machine")
  Initialize-ECSAgent -Cluster <cluster name> -EnableTaskIAMRole -LoggingDrivers '["json-file","awslogs"]'
  </powershell>
  ```

## 创建 Systems Manager 参数
<a name="secrets-envvar-ssm-paramstore-create-parameter"></a>

您可以使用 Systems Manager 控制台为您的敏感数据创建 Systems Manager Parameter Store 参数。有关更多信息，请参阅**《AWS Systems Manager 用户指南》中的[创建 Systems Manager 参数（控制台）](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-create-console.html)或[创建 Systems Manager 参数（AWS CLI）](https://docs.aws.amazon.com/systems-manager/latest/userguide/param-create-cli.html)。

## 将环境变量添加到容器定义中
<a name="secrets-ssm-paramstore-update-container-definition"></a>

在任务定义中的容器定义中，使用要在容器中设置的环境变量的名称以及包含要提供给容器的敏感数据的 Systems Manager Parameter Store 参数完整 ARN 指定 `secrets`。有关更多信息，请参阅 [secrets](task_definition_parameters.md#ContainerDefinition-secrets)。

以下是任务定义的片段，其中显示引用 Systems Manager Parameter Store 参数时的格式。如果 Systems Manager Parameter Store 参数存在于要启动的任务所在的区域，则可以使用参数的完整 ARN 或名称。如果参数存在于不同的区域，则指定完整的 ARN。

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:ssm:region:aws_account_id:parameter/parameter_name"
    }]
  }]
}
```

有关如何使用环境变量中指定的密钥创建任务定义的信息，请参阅 [使用控制台创建 Amazon ECS 任务定义](create-task-definition.md)。

## 更新应用程序以通过编程方式检索 Systems Manager Parameter Store 密钥
<a name="secrets-ssm-paramstore-update-app"></a>

要检索存储在 Systems Manager Parameter Store 参数中存储的敏感数据，请参阅 *AWS SDK 代码示例代码库*中的[使用 AWS SDK 的 Systems Manager 的代码示例](https://docs.aws.amazon.com/code-library/latest/ug/ssm_code_examples.html)。

# 传递用于 Amazon ECS 日志记录配置的密钥
<a name="secrets-logconfig"></a>

您可以使用 `logConfiguration` 中的 `secretOptions` 参数来传递用于日志记录的敏感数据。

您可以将密钥存储在 Secrets Manager 或 Systems Manager 中。

## 使用 Secrets Manager
<a name="secrets-logconfig-secrets-manager"></a>

在容器定义中，当指定 `logConfiguration` 时，您可以同时指定 `secretOptions`，方法是使用要在容器中设置的日志驱动程序选项的名称，以及包含要提供给容器的敏感数据的 Secrets Manager 密钥的完整 ARN。有关创建密钥的更多信息，请参阅[创建 AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

以下是任务定义的片段，其中显示引用 Secrets Manager 密钥时的格式。

```
{
  "containerDefinitions": [{
    "logConfiguration": [{
      "logDriver": "splunk",
      "options": {
        "splunk-url": "https://your_splunk_instance:8088"
      },
      "secretOptions": [{
        "name": "splunk-token",
        "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:secret_name-AbCdEf"
      }]
    }]
  }]
}
```

## 将环境变量添加到容器定义中
<a name="secrets-envvar-ssm-paramstore-update-container-definition"></a>

在容器定义中，使用要在容器中设置的环境变量的名称和包含要提供给容器的敏感数据的 Systems Manager Parameter Store 参数的完整 ARN 指定 `secrets`。有关更多信息，请参阅 [secrets](task_definition_parameters.md#ContainerDefinition-secrets)。

以下是任务定义的片段，其中显示引用 Systems Manager Parameter Store 参数时的格式。如果 Systems Manager Parameter Store 参数存在于要启动的任务所在的区域，则可以使用参数的完整 ARN 或名称。如果参数存在于不同的区域，则指定完整的 ARN。

```
{
  "containerDefinitions": [{
    "secrets": [{
      "name": "environment_variable_name",
      "valueFrom": "arn:aws:ssm:region:aws_account_id:parameter/parameter_name"
    }]
  }]
}
```

有关如何使用环境变量中指定的密钥创建任务定义的信息，请参阅 [使用控制台创建 Amazon ECS 任务定义](create-task-definition.md)。

## 使用 Systems Manager
<a name="secrets-logconfig-ssm-paramstore"></a>

您可以在日志配置中注入敏感数据。在容器定义中，当指定 `logConfiguration` 时，您可以使用要在容器中设置的日志驱动程序选项的名称以及包含要提供给容器的敏感数据的 Systems Manager Parameter Store 参数的完整 ARN 指定 `secretOptions`。

**重要**  
如果 Systems Manager Parameter Store 参数存在于要启动的任务所在的区域，则可以使用参数的完整 ARN 或名称。如果参数存在于不同的区域，则指定完整的 ARN。

以下是任务定义的片段，其中显示引用 Systems Manager Parameter Store 参数时的格式。

```
{
  "containerDefinitions": [{
    "logConfiguration": [{
      "logDriver": "fluentd",
      "options": {
        "tag": "fluentd demo"
      },
      "secretOptions": [{
        "name": "fluentd-address",
        "valueFrom": "arn:aws:ssm:region:aws_account_id:parameter:/parameter_name"
      }]
    }]
  }]
}
```

# 在 Amazon ECS 中指定使用 Secrets Manager 密钥的敏感数据
<a name="specifying-sensitive-data-tutorial"></a>

使用 Amazon ECS 时，您可以将敏感数据存储在 AWS Secrets Manager 密钥中，然后在容器定义中引用这些密钥，从而将敏感数据注入容器。有关更多信息，请参阅 [将敏感数据传递给 Amazon ECS 容器](specifying-sensitive-data.md)。

了解如何创建 Secrets Manager 密钥，在 Amazon ECS 任务定义中引用该密钥，然后通过查询显示密钥内容的容器内的环境变量来验证它是否有效。

## 先决条件
<a name="specifying-sensitive-data-tutorial-prereqs"></a>

本教程假设以下先决条件已完成：
+ [设置以使用 Amazon ECS](get-set-up-for-amazon-ecs.md) 中的步骤已完成。
+ 您的用户具有创建 Secrets Manager 和 Amazon ECS 资源所需的 IAM 权限。

## 步骤 1：创建 Secrets Manager 密钥
<a name="specifying-sensitive-data-tutorial-create-secret"></a>

您可以使用 Secrets Manager 控制台为您的敏感数据创建密钥。在本教程中，我们将创建一个基本密钥来存储用户名和密码以便稍后在容器中引用。有关更多信息，请参阅《AWS Secrets Manager 用户指南》**中的[创建 AWS Secrets Manager 密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。

**key/value pairs to be stored in this secret**（要存储在此密钥中的键/值对）是教程末尾处容器中的环境变量值。

保存**密钥 ARN** 以便在后续步骤中在任务执行 IAM 策略和任务定义中引用。

## 步骤 2：向任务执行角色添加密钥权限
<a name="specifying-sensitive-data-tutorial-update-iam"></a>

为了让 Amazon ECS 检索 Secrets Manager 密钥中的敏感数据，您必须具有任务执行角色的密钥权限。有关更多信息，请参阅 [Secrets Manager 或 Systems Manager 权限](task_execution_IAM_role.md#task-execution-secrets)。

## 步骤 3：创建任务定义
<a name="specifying-sensitive-data-tutorial-create-taskdef"></a>

可以使用 Amazon ECS 控制台创建引用了 Secrets Manager 密钥的任务定义。

**创建指定密钥的任务定义**

使用 IAM 控制台更新具有所需权限的任务执行角色。

1. 在 [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2) 打开控制台。

1. 在导航窗格中，选择 **Task definitions**（任务定义）。

1. 选择 **Create new task definition**（创建新的任务定义）、**Create new task definition with JSON**（使用 JSON 创建新的任务定义）。

1. 在 JSON 编辑器框中，输入以下任务定义 JSON 文本，确保已指定在步骤 1 中创建的 Secrets Manager 密钥的完整 ARN，以及在步骤 2 中更新的任务执行角色。选择**保存**。

1. 

   ```
   {
       "executionRoleArn": "arn:aws:iam::aws_account_id:role/ecsTaskExecutionRole",
       "containerDefinitions": [
           {
               "entryPoint": [
                   "sh",
                   "-c"
               ],
               "portMappings": [
                   {
                       "hostPort": 80,
                       "protocol": "tcp",
                       "containerPort": 80
                   }
               ],
               "command": [
                   "/bin/sh -c \"echo '<html> <head> <title>Amazon ECS Sample App</title> <style>body {margin-top: 40px; background-color: #333;} </style> </head><body> <div style=color:white;text-align:center> <h1>Amazon ECS Sample App</h1> <h2>Congratulations!</h2> <p>Your application is now running on a container in Amazon ECS.</p> </div></body></html>' >  /usr/local/apache2/htdocs/index.html && httpd-foreground\""
               ],
               "cpu": 10,
               "secrets": [
                   {
                       "valueFrom": "arn:aws:secretsmanager:region:aws_account_id:secret:username_value",
                       "name": "username_value"
                   }
               ],
               "memory": 300,
               "image": "public.ecr.aws/docker/library/httpd:2.4",
               "essential": true,
               "name": "ecs-secrets-container"
           }
       ],
       "family": "ecs-secrets-tutorial"
   }
   ```

1. 选择**创建**。

## 步骤 4：创建集群
<a name="specifying-sensitive-data-tutorial-create-cluster"></a>

您可以使用 Amazon ECS 控制台创建一个包含要运行任务的容器实例的集群。如果现有集群中至少注册了一个容器实例，并且具有可用资源来运行为本教程创建的任务定义的一个实例，则可跳到下一步。

在本教程中，我们将使用经 Amazon ECS 优化的 Amazon Linux 2 AMI 创建具有一个 `t2.micro` 容器实例的集群。

有关如何为 EC2 创建集群的信息，请参阅 [为 Amazon EC2 工作负载创建 Amazon ECS 集群](create-ec2-cluster-console-v2.md)。

## 步骤 5：运行任务
<a name="specifying-sensitive-data-tutorial-run-task"></a>

您可以使用 Amazon ECS 控制台通过创建的任务定义运行任务。在本教程中，我们将使用上一步中创建的集群来运行使用 EC2 的任务。

有关如何运行任务的信息，请参阅 [将应用程序作为 Amazon ECS 任务运行](standalone-task-create.md)。

## 步骤 6：验证
<a name="specifying-sensitive-data-tutorial-verify"></a>

您可以使用以下步骤验证是否已成功完成所有步骤并在容器中正确创建了环境变量。

**验证是否已创建环境变量**

1. 查找您的容器实例的公共 IP 或 DNS 地址。

   1. 在 [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2) 打开控制台。

   1. 在导航窗格中，选择**集群**，然后选择您创建的集群。

   1. 选择**基础设施**，然后选择容器实例。

   1. 记录您的实例的**公有 IP** 或**公有 DNS**。

1. 如果您使用的是 macOS 或 Linux 计算机，请使用以下命令连接到您的实例，并替换您的私有密钥的路径和实例的公共地址：

   ```
   $ ssh -i /path/to/my-key-pair.pem ec2-user@ec2-198-51-100-1.compute-1.amazonaws.com
   ```

   有关使用 Windows 计算机的更多信息，请参阅《Amazon EC2 用户指南》**中的[使用 PuTTY 连接到 Linux 实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-linux-inst-from-windows.html)。
**重要**  
要详细了解您在连接到实例时遇到的任何问题，请参阅《Amazon EC2 用户指南》中的[排查实例的连接问题](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/TroubleshootingInstancesConnecting.html)**。

1. 列出正在实例上运行的容器。记下 `ecs-secrets-tutorial` 容器的容器 ID。

   ```
   docker ps
   ```

1. 使用上一步的输出中的容器 ID 连接到 `ecs-secrets-tutorial` 容器。

   ```
   docker exec -it container_ID /bin/bash
   ```

1. 使用 `echo` 命令打印环境变量的值。

   ```
   echo $username_value
   ```

   如果教程成功完成，您应看到以下输出：

   ```
   password_value
   ```
**注意**  
或者，您可以使用 `env`（或 `printenv`）命令列出容器中的所有环境变量。

## 步骤 7：清除
<a name="specifying-sensitive-data-tutorial-cleanup"></a>

完成本教程后，您应清除相关资源，以避免产生与未使用的资源相关的费用。

**清除资源**

1. 在 [https://console.aws.amazon.com/ecs/v2](https://console.aws.amazon.com/ecs/v2) 打开控制台。

1. 在导航窗格中，选择**集群**。

1. 在 **Clusters**（集群）页面上，选择集群。

1. 选择**删除集群**。

1. 在确认框中，输入 **delete *cluster name***，然后选择**删除**。

1. 通过以下网址打开 IAM 控制台：[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)。

1. 在导航窗格中，选择**角色**。

1. 在角色列表中搜索 `ecsTaskExecutionRole` 并将其选定。

1. 选择**权限**，然后选择 **ECSSecretsTutorial** 旁边的 **X**。选择**移除 **。

1. 通过 [https://console.aws.amazon.com/secretsmanager/](https://console.aws.amazon.com/secretsmanager/) 打开 Secrets Manager 控制台。

1. 选择您之前创建的 **username\$1value** 密钥，然后选择**操作**、**删除密钥**。