

# 使用 AWS CLI 为 EC2 创建 Amazon ECS 任务
<a name="ECS_AWSCLI_EC2"></a>

以下步骤帮助您在 Amazon ECS 中使用 AWS CLI 设置集群、注册任务定义、运行任务和执行其他常见方案。使用最新版本的 AWS CLI。有关如何升级到最新版本的更多信息，请参阅[安装或更新到最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

**注意**  
您可以使用双堆栈服务端点通过 IPv4 和 IPv6 从 AWS CLI、SDK 和 Amazon ECS API 与 Amazon ECS 进行交互。有关更多信息，请参阅 [使用 Amazon ECS 双堆栈端点](dual-stack-endpoint.md)。

**Topics**
+ [先决条件](#AWSCLI_EC2_prereq)
+ [创建集群](#AWSCLI_EC2_create_cluster)
+ [使用 Amazon ECS AMI 启动容器实例](#AWSCLI_EC2_launch_container_instance)
+ [列出容器实例](#AWSCLI_EC2_list_container_instances)
+ [描述容器实例](#AWSCLI_EC2_describe_container_instance)
+ [注册任务定义](#AWSCLI_EC2_register_task_definition)
+ [列出任务定义](#AWSCLI_EC2_list_task_definitions)
+ [创建服务](#AWSCLI_EC2_run_task)
+ [列出服务](#AWSCLI_EC2_list_tasks)
+ [描述服务](#AWSCLI_EC2_describe_service)
+ [描述正在运行的任务](#AWSCLI_EC2_describe_task)
+ [测试 Web 服务器](#AWSCLI_EC2_test_web_server)
+ [清理 资源](#AWSCLI_EC2_clean_up_resources)

## 先决条件
<a name="AWSCLI_EC2_prereq"></a>

本教程假设以下先决条件已完成：
+ 安装并配置了最新版本的 AWS CLI。有关安装或升级 AWS CLI 的更多信息，请参阅 [Installing or updating to the latest version of the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。
+ [设置以使用 Amazon ECS](get-set-up-for-amazon-ecs.md) 中的步骤已完成。
+ 您的 IAM 用户具有 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 策略示例中指定的必需权限。
+ 您已创建了一个可供使用的容器实例 IAM 角色。有关更多信息，请参阅[Amazon ECS 容器实例 IAM 角色](instance_IAM_role.md)。
+ 您已创建了一个可供使用的 VPC。有关更多信息，请参阅 [创建虚拟私有云](get-set-up-for-amazon-ecs.md#create-a-vpc)。
+ （可选）AWS CloudShell 是一种为客户提供命令行的工具，而无需创建自己的 EC2 实例。有关更多信息，请参阅《AWS CloudShell 用户指南》**中的[什么是 AWS CloudShell？](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html)。

## 创建集群
<a name="AWSCLI_EC2_create_cluster"></a>

默认情况下，当您启动第一个容器实例时，您的账户将收到一个 `default` 集群。

**注意**  
使用为您提供的 `default` 集群的好处是您不必在后续命令中指定 `--cluster cluster_name` 选项。如果您自行创建非默认集群，您必须为您打算用于该集群的每个命令指定 `--cluster cluster_name`。

使用以下命令自行创建具有唯一名称的集群：

```
aws ecs create-cluster --cluster-name MyCluster
```

输出：

```
{
    "cluster": {
        "clusterName": "MyCluster",
        "status": "ACTIVE",
        "clusterArn": "arn:aws:ecs:region:aws_account_id:cluster/MyCluster"
    }
}
```

## 使用 Amazon ECS AMI 启动容器实例
<a name="AWSCLI_EC2_launch_container_instance"></a>

容器实例是已注册到集群并且将会运行 Amazon ECS 容器代理的 EC2 实例。在这一部分中，您将使用 ECS 优化版 AMI 启动一个 EC2 实例。

**使用 AWS CLI 启动容器实例**

1. 使用以下命令检索您所在 AWS 区域的最新 ECS 优化版 Amazon Linux 2 AMI ID。此命令使用 AWS Systems Manager Parameter Store 来获取最新 ECS 优化版 AMI ID。该 AMI 包括预装的 Amazon ECS 容器代理和 Docker 运行时。

   ```
   aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/recommended --query 'Parameters[0].Value' --output text | jq -r '.image_id'
   ```

   输出：

   ```
   ami-abcd1234
   ```

1. 创建一个允许 SSH 访问（用来管理容器实例）和 HTTP 访问（用于 Web 服务器）的安全组。

   ```
   aws ec2 create-security-group --group-name ecs-tutorial-sg --description "ECS tutorial security group"
   ```

   输出：

   ```
   {
       "GroupId": "sg-abcd1234"
   }
   ```

1. 通过运行以下命令，将一条入站规则添加到该安全组。

   ```
   aws ec2 authorize-security-group-ingress --group-id sg-abcd1234 --protocol tcp --port 80 --cidr 0.0.0.0/0
   ```

   输出：

   ```
   {
       "Return": true,
       "SecurityGroupRules": [
           {
               "SecurityGroupRuleId": "sgr-efgh5678",
               "GroupId": "sg-abcd1234",
               "GroupOwnerId": "123456789012",
               "IsEgress": false,
               "IpProtocol": "tcp",
               "FromPort": 80,
               "ToPort": 80,
               "CidrIpv4": "0.0.0.0/0"
           }
       ]
   }
   ```

   现在，该安全组将允许从指定 IP 范围进行 SSH 访问以及从任何位置进行 HTTP 访问。在生产环境中，您应仅允许从您的特定 IP 地址进行 SSH 访问，并在需要时考虑限制 HTTP 访问。

1. 创建一个 EC2 密钥对，用于对容器实例的 SSH 访问。

   ```
   aws ec2 create-key-pair --key-name ecs-tutorial-key --query 'KeyMaterial' --output text > ecs-tutorial-key.pem
   chmod 400 ecs-tutorial-key.pem
   ```

   该私有密钥将保存到具有恰当 SSH 访问权限的本地计算机中。

1. 使用 ECS 优化版 AMI 启动一个 EC2 实例，并进行配置以加入您的集群。

   ```
   aws ec2 run-instances --image-id ami-abcd1234 --instance-type t3.micro --key-name ecs-tutorial-key --security-group-ids sg-abcd1234 --iam-instance-profile Name=ecsInstanceRole --user-data '#!/bin/bash
   echo ECS_CLUSTER=MyCluster >> /etc/ecs/ecs.config'
   {
       "Instances": [
           {
               "InstanceId": "i-abcd1234",
               "ImageId": "ami-abcd1234",
               "State": {
                   "Code": 0,
                   "Name": "pending"
               },
               "PrivateDnsName": "",
               "PublicDnsName": "",
               "StateReason": {
                   "Code": "pending",
                   "Message": "pending"
               },
               "InstanceType": "t3.micro",
               "KeyName": "ecs-tutorial-key",
               "LaunchTime": "2025-01-13T10:30:00.000Z"
           }
       ]
   }
   ```

   此用户数据脚本会配置 Amazon ECS 代理，以将该实例注册到您的 `MyCluster`。该实例使用 `ecsInstanceRole` IAM 角色，从而为该代理提供所需的权限。

## 列出容器实例
<a name="AWSCLI_EC2_list_container_instances"></a>

在启动您的容器实例后的几分钟内，Amazon ECS 代理将向您的 MyCluster 集群注册该实例。您可以通过运行以下命令列出集群中的容器实例：

```
aws ecs list-container-instances --cluster MyCluster
```

输出：

```
{
    "containerInstanceArns": [
        "arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_ID"
    ]
}
```

## 描述容器实例
<a name="AWSCLI_EC2_describe_container_instance"></a>

在拥有某个容器实例的 ARN 或 ID 后，您就可以使用 **describe-container-instances** 命令获取有关该实例的有价值的信息，例如剩余的和已注册的 CPU 和内存资源。

```
aws ecs describe-container-instances --cluster MyCluster --container-instances container_instance_ID
```

输出：

```
{
    "failures": [],
    "containerInstances": [
        {
            "status": "ACTIVE",
            "registeredResources": [
                {
                    "integerValue": 1024,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "CPU",
                    "doubleValue": 0.0
                },
                {
                    "integerValue": 995,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "MEMORY",
                    "doubleValue": 0.0
                },
                {
                    "name": "PORTS",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [
                        "22",
                        "2376",
                        "2375",
                        "51678"
                    ],
                    "type": "STRINGSET",
                    "integerValue": 0
                },
                {
                    "name": "PORTS_UDP",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [],
                    "type": "STRINGSET",
                    "integerValue": 0
                }
            ],
            "ec2InstanceId": "instance_id",
            "agentConnected": true,
            "containerInstanceArn": "arn:aws:ecs:us-west-2:aws_account_id:container-instance/container_instance_ID",
            "pendingTasksCount": 0,
            "remainingResources": [
                {
                    "integerValue": 1024,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "CPU",
                    "doubleValue": 0.0
                },
                {
                    "integerValue": 995,
                    "longValue": 0,
                    "type": "INTEGER",
                    "name": "MEMORY",
                    "doubleValue": 0.0
                },
                {
                    "name": "PORTS",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [
                        "22",
                        "2376",
                        "2375",
                        "51678"
                    ],
                    "type": "STRINGSET",
                    "integerValue": 0
                },
                {
                    "name": "PORTS_UDP",
                    "longValue": 0,
                    "doubleValue": 0.0,
                    "stringSetValue": [],
                    "type": "STRINGSET",
                    "integerValue": 0
                }
            ],
            "runningTasksCount": 0,
            "attributes": [
                {
                    "name": "com.amazonaws.ecs.capability.privileged-container"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.17"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
                },
                {
                    "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.json-file"
                },
                {
                    "name": "com.amazonaws.ecs.capability.logging-driver.syslog"
                }
            ],
            "versionInfo": {
                "agentVersion": "1.5.0",
                "agentHash": "b197edd",
                "dockerVersion": "DockerVersion: 1.7.1"
            }
        }
    ]
}
```

您也可以在 Amazon EC2 控制台中或使用 **aws ec2 describe-instances --instance-id *instance\$1id*** 命令查找可用于监控实例的 Amazon EC2 实例 ID。

## 注册任务定义
<a name="AWSCLI_EC2_register_task_definition"></a>

您必须首先注册一个任务定义，然后才能在 Amazon ECS 集群上运行任务。任务定义是分组在一起的一系列容器。以下示例是一个使用 `nginx` 映像的简单任务定义。有关可用任务定义参数的更多信息，请参阅 [Amazon ECS 任务定义](task_definitions.md)。

```
{
    "family": "nginx-task",
    "containerDefinitions": [
        {
            "name": "nginx",
            "image": "public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest",
            "cpu": 256,
            "memory": 512,
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ]
        }
    ],
    "requiresCompatibilities": ["EC2"],
    "networkMode": "bridge"
}
```

上述示例 JSON 可通过两种方式传递到 AWS CLI：您可以将任务定义 JSON 保存为文件并使用 `--cli-input-json file://path_to_file.json` 选项传递它。您也可以对 JSON 中的引号进行转义并在命令行上传递 JSON 容器定义。如果您选择在命令行上传递容器定义，您的命令还需要一个 `--family` 参数，该参数用于使任务定义的多个版本保持互相关联。

将 JSON 文件用于容器定义：

```
aws ecs register-task-definition --cli-input-json file://$HOME/tasks/nginx.json
```

**register-task-definition** 将在其完成注册后返回任务定义的说明。

```
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:us-east-1:123456789012:task-definition/nginx-task:1",
        "family": "nginx-task",
        "revision": 1,
        "status": "ACTIVE",
        "containerDefinitions": [
            {
                "name": "nginx",
                "image": "public.ecr.aws/docker/library/nginx:latest",
                "cpu": 256,
                "memory": 512,
                "essential": true,
                "portMappings": [
                    {
                        "containerPort": 80,
                        "hostPort": 80,
                        "protocol": "tcp"
                    }
                ],
                "environment": [],
                "mountPoints": [],
                "volumesFrom": []
            }
        ],
        "volumes": [],
        "networkMode": "bridge",
        "compatibilities": [
            "EC2"
        ],
        "requiresCompatibilities": [
            "EC2"
        ]
    }
}
```

## 列出任务定义
<a name="AWSCLI_EC2_list_task_definitions"></a>

您可以随时使用 **list-task-definitions** 命令列出您的账户的任务定义。此命令的输出将显示 `family` 和 `revision` 值，您可以在调用 **create-service** 时将这些值一起使用。

```
aws ecs list-task-definitions
```

输出：

```
{
    "taskDefinitionArns": [
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/sleep360:1",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/sleep360:2",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/nginx-task:1",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:3",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:4",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:5",
        "arn:aws:ec2:us-east-1:aws_account_id:task-definition/wordpress:6"
    ]
}
```

## 创建服务
<a name="AWSCLI_EC2_run_task"></a>

在为账户注册任务并启动注册到集群的容器实例后，您可以创建一个 Amazon ECS 服务，从而使用所注册的任务定义同时运行和维持所需数量的任务。在本实例中，您将 `nginx:1` 任务定义的单个实例放置在 MyCluster 集群中。

```
aws ecs create-service --cluster MyCluster --service-name nginx-service --task-definition nginx-task:1 --desired-count 1
```

输出：

```
{
    "service": {
        "serviceArn": "arn:aws:ecs:us-east-1:aws_account_id:service/MyCluster/nginx-service",
        "serviceName": "nginx-service",
        "clusterArn": "arn:aws:ecs:us-east-1:aws_account_id:cluster/MyCluster",
        "taskDefinition": "arn:aws:ecs:us-east-1:aws_account_id:task-definition/nginx-task:1",
        "desiredCount": 1,
        "runningCount": 0,
        "pendingCount": 0,
        "launchType": "EC2",
        "status": "ACTIVE",
        "createdAt": "2025-01-13T10:45:00.000Z"
    }
}
```

## 列出服务
<a name="AWSCLI_EC2_list_tasks"></a>

列出您的集群的服务。您应看到您在上一部分中创建的服务。您可以记下此命令返回的服务 ID 或完整 ARN，并在稍后将其用于描述服务。

```
aws ecs list-services --cluster MyCluster
```

输出：

```
{
    "taskArns": [
        "arn:aws:ecs:us-east-1:aws_account_id:task/task_ID"
    ]
}
```

## 描述服务
<a name="AWSCLI_EC2_describe_service"></a>

使用以下命令描述服务，以获取有关该服务的更多信息。

```
aws ecs describe-services --cluster MyCluster --services nginx-service
```

输出：

```
{
    "services": [
        {
            "serviceArn": "arn:aws:ecs:us-east-1:aws_account_id:service/MyCluster/nginx-service",
            "serviceName": "nginx-service",
            "clusterArn": "arn:aws:ecs:us-east-1:aws_account_id:cluster/MyCluster",
            "taskDefinition": "arn:aws:ecs:us-east-1:aws_account_id:task-definition/nginx-task:1",
            "desiredCount": 1,
            "runningCount": 1,
            "pendingCount": 0,
            "launchType": "EC2",
            "status": "ACTIVE",
            "createdAt": "2025-01-13T10:45:00.000Z",
            "events": [
                {
                    "id": "abcd1234-5678-90ab-cdef-1234567890ab",
                    "createdAt": "2025-01-13T10:45:30.000Z",
                    "message": "(service nginx-service) has started 1 tasks: (task abcd1234-5678-90ab-cdef-1234567890ab)."
                }
            ]
        }
    ]
}
```

## 描述正在运行的任务
<a name="AWSCLI_EC2_describe_task"></a>

在描述服务后，运行以下命令可获取有关该服务中正在运行的任务的更多信息。

```
aws ecs list-tasks --cluster MyCluster --service-name nginx-service
```

 输出：

```
{
    "tasks": [
        {
            "taskArn": "arn:aws:ecs:us-east-1:aws_account_id:task/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab",
            "clusterArn": "arn:aws:ecs:us-east-1:aws_account_id:cluster/MyCluster",
            "taskDefinitionArn": "arn:aws:ecs:us-east-1:aws_account_id:task-definition/nginx-task:1",
            "containerInstanceArn": "arn:aws:ecs:us-east-1:aws_account_id:container-instance/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab",
            "lastStatus": "RUNNING",
            "desiredStatus": "RUNNING",
            "containers": [
                {
                    "containerArn": "arn:aws:ecs:us-east-1:aws_account_id:container/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab/abcd1234-5678-90ab-cdef-1234567890ab",
                    "taskArn": "arn:aws:ecs:us-east-1:aws_account_id:task/MyCluster/abcd1234-5678-90ab-cdef-1234567890ab",
                    "name": "nginx",
                    "lastStatus": "RUNNING",
                    "networkBindings": [
                        {
                            "bindIP": "0.0.0.0",
                            "containerPort": 80,
                            "hostPort": 80,
                            "protocol": "tcp"
                        }
                    ]
                }
            ],
            "createdAt": "2025-01-13T10:45:00.000Z",
            "startedAt": "2025-01-13T10:45:30.000Z"
        }
    ]
}
```

## 测试 Web 服务器
<a name="AWSCLI_EC2_test_web_server"></a>

**测试 Web 服务器**

1. 通过运行以下命令，检索容器实例的公有 IP 地址。

   ```
   aws ec2 describe-instances --instance-ids i-abcd1234 --query 'Reservations[0].Instances[0].PublicIpAddress' --output text
   ```

   输出：

   ```
   203.0.113.25
   ```

1. 检索到 IP 地址后，使用该 IP 地址运行以下 `curl` 命令。

   ```
   curl http://203.0.113.25
   ```

   输出：

   ```
   <!DOCTYPE html>
   <html>
   <head>
   <title>Welcome to nginx!</title>
   ...
   </head>
   <body>
   <h1>Welcome to nginx!</h1>
   <p>If you can see this page, the nginx web server is successfully installed and working.</p>
   ...
   </body>
   </html>
   ```

   nginx 欢迎页面会确认您的服务已成功运行并且可以从互联网访问。

## 清理 资源
<a name="AWSCLI_EC2_clean_up_resources"></a>

要避免产生费用，请清理您在本教程中创建的资源。

**清理资源**

1. 更新服务，使需要的任务数降为零，然后删除服务。

   ```
   aws ecs update-service --cluster MyCluster --service nginx-service --desired-count 0
   {
       "service": {
           "serviceArn": "arn:aws:ecs:us-east-1:123456789012:service/MyCluster/nginx-service",
           "serviceName": "nginx-service",
           "desiredCount": 0,
           "runningCount": 1,
           "pendingCount": 0,
           "status": "ACTIVE"
       }
   }
   ```

1. 等待正在运行的任务停止，然后再删除服务。

   ```
   aws ecs delete-service --cluster MyCluster --service nginx-service
   {
       "service": {
           "serviceArn": "arn:aws:ecs:us-east-1:123456789012:service/MyCluster/nginx-service",
           "serviceName": "nginx-service",
           "status": "DRAINING"
       }
   }
   ```

1. 终止您创建的容器实例。

   ```
   aws ec2 terminate-instances --instance-ids i-abcd1234
   {
       "TerminatingInstances": [
           {
               "InstanceId": "i-abcd1234",
               "CurrentState": {
                   "Code": 32,
                   "Name": "shutting-down"
               },
               "PreviousState": {
                   "Code": 16,
                   "Name": "running"
               }
           }
       ]
   }
   ```

1. 清理您创建的安全组和密钥对。

   ```
   aws ec2 delete-security-group --group-id sg-abcd1234
   aws ec2 delete-key-pair --key-name ecs-tutorial-key
   rm ecs-tutorial-key.pem
   ```

1. 删除 Amazon ECS 集群。

   ```
   aws ecs delete-cluster --cluster MyCluster
   {
       "cluster": {
           "clusterArn": "arn:aws:ecs:us-east-1:123456789012:cluster/MyCluster",
           "clusterName": "MyCluster",
           "status": "INACTIVE"
       }
   }
   ```