

# 定义 Amazon ECS 将哪些容器实例用于任务
<a name="task-placement-constraints"></a>

任务放置约束是关于容器实例的规则，Amazon ECS 使用该规则来确定是否允许在实例上运行任务。必须至少有一个容器实例匹配约束条件。如果没有与约束条件匹配的实例，则任务将保持 `PENDING` 状态。创建新服务或更新现有服务时，您可以为服务的任务指定任务放置限制。

您可以使用 `placementConstraint` 参数在服务定义、任务定义或任务中指定任务放置约束。

```
"placementConstraints": [
    {
        "expression": "The expression that defines the task placement constraints",
        "type": "The placement constraint type to use"
    }
]
```

下表介绍如何使用这些参数。


| Constraint type | 可以在何时指定 | 
| --- | --- | 
| distinctInstance将每个活动任务放入不同的容器实例。Amazon ECS 会检查所需的任务状态以放置任务。例如，假设现有任务所需的状态为 `STOPPED`（但最近的状态不是该状态），则可以将新传入的任务放入同一个实例，尽管存在 `distinctInstance` 放置约束。因此，您可能会看到同一个实例上有 2 个任务最近的状态都为 `RUNNING`。 建议为其任务寻求强隔离的客户使用 Fargate。Fargate 在硬件虚拟化环境中运行每个任务。这将确保这些容器化工作负载不会与其他任务共享网络接口、Fargate 临时存储、CPU 或内存。有关更多信息，请参阅 [AWS Fargate 的安全概述](https://d1.awsstatic.com/whitepapers/AWS_Fargate_Security_Overview_Whitepaper.pdf)。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/task-placement-constraints.html)  | 
| memberOf将任务放置在满足表达式的容器实例中。 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/task-placement-constraints.html) | 

使用 `memberOf` 约束类型时，您可以使用集群查询语言创建表达式，该语言定义了 Amazon ECS 在其中放置任务的容器实例。表达式是供您按属性对容器实例进行分组的一种方式。表达式位于 `placementConstraint` 的 `expression ` 参数中。

## Amazon ECS 容器实例属性
<a name="attributes"></a>

您可以将自定义元数据添加到容器实例中，称为*属性*。每个属性都有一个名称和一个可选字符串值。您可以使用 Amazon ECS 提供的内置属性，或自定义属性。

以下部分包含示例内置、可选属性和自定义属性。

### 内置属性
<a name="ecs-automatic-attributes"></a>

Amazon ECS 会自动将以下属性应用于您的容器实例。

`ecs.ami-id`  
用于启动实例的 AMI 的 ID。本属性的示例值为 `ami-1234abcd`。

`ecs.availability-zone`  
实例所在的可用区。本属性的示例值为 `us-east-1a`。

`ecs.instance-type`  
实例的实例类型。本属性的示例值为 `g2.2xlarge`。

`ecs.os-type`  
实例的操作系统。此属性的可能值为 `linux` 和 `windows`。

`ecs.os-family`  
实例的操作系统版本。  
对于 Linux 实例，有效值为 `LINUX`。对于 Windows 实例，ECS 以 `WINDOWS_SERVER_<OS_Release>_<FULL or CORE>` 格式设置值。有效值为 `WINDOWS_SERVER_2022_FULL`、`WINDOWS_SERVER_2022_CORE`、`WINDOWS_SERVER_20H2_CORE`、`WINDOWS_SERVER_2019_FULL`、`WINDOWS_SERVER_2019_CORE` 和 `WINDOWS_SERVER_2016_FULL`。  
这对于 Windows 容器和 Windows containers on AWS Fargate 很重要，因为每个 Windows 容器的操作系统版本都必须与主机的操作系统版本相匹配。如果容器映像的 Windows 版本与主机不同，则容器无法启动。有关更多信息，请参阅 Microsoft 文档网站上的 [Windows 容器版本兼容性](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-11)。  
如果您的集群运行多个 Windows 版本，则可以使用置放约束来确保将任务放在运行相同版本的 EC2 实例上：`memberOf(attribute:ecs.os-family == WINDOWS_SERVER_<OS_Release>_<FULL or CORE>)`。有关更多信息，请参阅 [检索经 Amazon ECS 优化的 Windows AMI 元数据](retrieve-ecs-optimized_windows_AMI.md)。

`ecs.cpu-architecture`  
实例的 CPU 架构。本属性的示例值为 `x86_64` 和 `arm64`。

`ecs.vpc-id`  
启动实例的 VPC。本属性的示例值为 `vpc-1234abcd`。

`ecs.subnet-id`  
实例正在使用的子网。本属性的示例值为 `subnet-1234abcd`。

**注意**  
Amazon ECS 托管实例支持以下属性子集：  
`ecs.subnet-id`
`ecs.availability-zone`
`ecs.instance-type`
`ecs.cpu-architecture`

### 可选属性
<a name="ecs-optional-attributes"></a>

Amazon ECS 可能会将以下属性添加到您的容器实例。

`ecs.awsvpc-trunk-id`  
如果此属性存在，则实例具有中继网络接口。有关更多信息，请参阅 [增加 Amazon ECS Linux 容器实例网络接口](container-instance-eni.md)。

`ecs.outpost-arn`  
如果此属性存在，则包含 Outpost 的 Amazon 资源名称（ARN）。有关更多信息，请参阅 [AWS Outposts 上的 Amazon Elastic Container Service](using-outposts.md)。

`ecs.capability.external`  
如果此属性存在，则实例将标识为外部实例。有关更多信息，请参阅 [外部实例的 Amazon ECS 集群](ecs-anywhere.md)。

### 自定义属性
<a name="ecs-custom-attributes"></a>

您可以将自定义属性应用于您的容器实例。例如，您可以定义名为 "stack"、值为 "prod" 的属性。

指定自定义属性时，必须考虑以下内容。
+ `name` 必须包含 1 到 128 个字符，名称可以包含字母（大写和小写形式）、数字、连字符、下划线、正斜杠、反斜杠或句点。
+ `value` 必须包含 1 到 128 个字符，可以包含字母（大写和小写形式）、数字、连字符、下划线、句点、符号（@）、正斜杠、反斜杠、冒号或空格。该值不能包含任何前导空格或尾随空格。

# 创建表达式，以为 Amazon ECS 任务定义容器实例
<a name="cluster-query-language"></a>

集群查询是允许您将对象分组的表达式。例如，您可以按属性（例如可用区、实例类型或自定义元数据）将容器实例分组。有关更多信息，请参阅 [Amazon ECS 容器实例属性](task-placement-constraints.md#attributes)。

在您定义了一组容器实例后，可以自定义 Amazon ECS，根据组在容器实例上放置任务。有关更多信息，请参阅[将应用程序作为 Amazon ECS 任务运行](standalone-task-create.md)和[创建 Amazon ECS 滚动更新部署](create-service-console-v2.md)。您还可以在列出容器实例时应用组筛选条件。

## 表达式语法
<a name="expression-syntax"></a>

表达式有如下语法：

```
subject operator [argument]
```

**主题**  
要评估的属性或字段。

`agentConnected`  
按 Amazon ECS 容器代理连接状态选择容器实例。您可以使用此过滤器来搜索具有已断开连接的容器代理的实例。  
有效运算符：equals (==)、not\$1equals (\$1=)、in、not\$1in (\$1in)、matches (=\$1)、not\$1matches (\$1\$1)

`agentVersion`  
按 Amazon ECS 容器代理版本选择容器实例。您可以使用此过滤器查找运行过期版本的 Amazon ECS 容器代理的实例。  
有效运算符：equals (==)、not\$1equals (\$1=)、greater\$1than (>)、greater\$1than\$1equal (>=)、less\$1than (<)、less\$1than\$1equal (<=)

`attribute:attribute-name`  
按属性选择容器实例。有关更多信息，请参阅 [Amazon ECS 容器实例属性](task-placement-constraints.md#attributes)。

`ec2InstanceId`  
按 Amazon EC2 实例 ID 选择容器实例。  
有效运算符：equals (==)、not\$1equals (\$1=)、in、not\$1in (\$1in)、matches (=\$1)、not\$1matches (\$1\$1)

`registeredAt`  
按容器实例注册日期选择容器实例。您可以使用此过滤器查找新注册的实例或已注册很久的实例。  
有效运算符：equals (==)、not\$1equals (\$1=)、greater\$1than (>)、greater\$1than\$1equal (>=)、less\$1than (<)、less\$1than\$1equal (<=)  
有效日期格式：2018-06-18T22:28:28\$100:00、2018-06-18T22:28:28Z、2018-06-18T22:28:28、2018-06-18

`runningTasksCount`  
按运行任务数选择容器实例。您可以使用此过滤器查找空或接近空的实例（在其上运行的任务很少）。  
有效运算符：equals (==)、not\$1equals (\$1=)、greater\$1than (>)、greater\$1than\$1equal (>=)、less\$1than (<)、less\$1than\$1equal (<=)

`task:group`  
按任务组选择容器实例。有关更多信息，请参阅 [与组相关的 Amazon ECS 任务](task-groups.md)。

**运算符**  
比较运算符。支持以下运算符。


|  运算符  |  说明  | 
| --- | --- | 
|  ==, equals  |  字符串相等  | 
|  \$1=, not\$1equals  |  字符串不相等  | 
|  >, greater\$1than  |  Greater than  | 
|  >=, greater\$1than\$1equal  |  大于或等于  | 
|  <, less\$1than  |  Less than  | 
|  <=, less\$1than\$1equal  |  小于或等于  | 
|  exists  |  主题存在  | 
|  \$1exists, not\$1exists  |  主题不存在  | 
|  in  |  值在参数列表中  | 
|  \$1in, not\$1in  |  值不在参数列表中  | 
|  =\$1, matches  |  模式匹配  | 
|  \$1\$1, not\$1matches  |  模式不匹配  | 

**注意**  
单个表达式不能包含圆括号。但是，可以使用圆括号来指定复合表达式中的优先顺序。

**参数**  
很多运算符的参数是一个文本值。

`in` 和 `not_in` 运算符要求参数是一个参数列表。按如下所示指定参数列表：

```
[argument1, argument2, ..., argumentN]
```

matches 和 not\$1matches 运算符要求参数符合 Java 正则表达式的语法。有关更多信息，请参阅 [java.util.regex.Pattern](http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html)。

**复合表达式**

您可以使用以下布尔值运算符组合表达式：
+ &&, 和
+ \$1\$1 或者
+ \$1, 非

您可以使用圆括号指定优先顺序：

```
(expression1 or expression2) and expression3
```

## 表达式示例
<a name="expression-examples"></a>

以下为表达式示例。

**示例：字符串相等**  
以下表达式选择具有指定实例类型的实例。

```
attribute:ecs.instance-type == t2.small
```

**示例：参数列表**  
以下表达式选择在 us-east-1a 或 us-east-1b 可用区中的实例。

```
attribute:ecs.availability-zone in [us-east-1a, us-east-1b]
```

**示例：复合表达式**  
以下表达式选择不在 us-east-1d 可用区内的 G2 实例。

```
attribute:ecs.instance-type =~ g2.* and attribute:ecs.availability-zone != us-east-1d
```

**示例：任务关联**  
以下表达式选择在 `service:production` 组中托管任务的实例。

```
task:group == service:production
```

**示例：任务反关联**  
以下表达式选择未在数据库组中托管任务的实例。

```
not(task:group == database)
```

**示例：运行任务数**  
以下表达式选择仅运行一个任务的实例。

```
runningTasksCount == 1
```

**示例：Amazon ECS 容器代理版本**  
以下表达式选择运行版本低于 1.14.5 的容器代理的实例。

```
agentVersion < 1.14.5
```

**示例：实例注册时间**  
以下表达式选择在 2018 年 2 月 13 日前注册的实例。

```
registeredAt < 2018-02-13
```

**示例：Amazon EC2 实例 ID**  
以下表达式选择具有以下 Amazon EC2 实例 ID 的实例。

```
ec2InstanceId in ['i-abcd1234', 'i-wxyx7890']
```

# Amazon ECS 任务放置约束示例
<a name="constraint-examples"></a>

下面是一些任务放置约束示例。

此示例使用 `memberOf` 约束在 t2 实例上放置任务。可以使用以下操作指定此约束：[CreateService](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html)、[UpdateService](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html)、[RegisterTaskDefinition](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RegisterTaskDefinition.html) 和 [RunTask](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html)。

```
"placementConstraints": [
    {
        "expression": "attribute:ecs.instance-type =~ t2.*",
        "type": "memberOf"
    }
]
```

该示例使用 `memberOf` 约束将任务放置在进程守护程序服务 `daemon-service` 任务组中具有任务的实例上，同时考虑到同时指定的任何任务放置策略。此约束可确保进程守护程序服务任务在副本服务任务之前放置在 EC2 实例上。

将 `daemon-service` 替换为进程守护程序服务的名称。

```
"placementConstraints": [
    {
        "expression": "task:group == service:daemon-service",
        "type": "memberOf"
    }
]
```

该示例使用 `memberOf` 约束将任务放置在 `databases` 任务组中具有其他任务的实例上，同时考虑到也指定的任何任务放置策略。有关任务组的更多信息，请参阅 [与组相关的 Amazon ECS 任务](task-groups.md)。可以使用以下操作指定此约束：[CreateService](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html)、[UpdateService](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html)、[RegisterTaskDefinition](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RegisterTaskDefinition.html) 和 [RunTask](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html)。

```
"placementConstraints": [
    {
        "expression": "task:group == databases",
        "type": "memberOf"
    }
]
```

`distinctInstance` 约束将组中的每项任务放置于不同实例上。可以使用以下操作指定此约束：[CreateService](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html)、[UpdateService](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateService.html) 和 [RunTask](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_RunTask.html)。

Amazon ECS 会检查所需的任务状态以放置任务。例如，假设现有任务所需的状态为 `STOPPED`（但最近的状态不是该状态），则可以将新传入的任务放入同一个实例，尽管存在 `distinctInstance` 放置约束。因此，您可能会看到同一个实例上有 2 个任务最近的状态都为 `RUNNING`。

```
"placementConstraints": [
    {
        "type": "distinctInstance"
    }
]
```