【问题标题】:Get EC2 instance id that hosts an ECS task for a specific service name获取托管特定服务名称的 ECS 任务的 EC2 实例 ID
【发布时间】:2021-02-25 18:54:51
【问题描述】:

使用 AWS SSM 插件,您可以通过以下方式登录 ECS 容器:

aws ssm start-session --target i-<ec2 instance target id>
sudo su
docker ps
docker exec -it <image id> bash

诀窍是您需要首先找到正确的 ec2 实例 ID。这可以通过几个命令行调用手动完成。例如

aws ecs list-container-instances --cluster <cluster name>
aws ecs list-tasks --cluster <cluster name>

但这并不能完全满足我的需求,即快速脚本或单行程序能够指定 ECS 服务名称并立即登录到托管该服务任务的 EC2 实例。

显然可能有多个实例托管来自服务的多个任务 - 第一个是可以的。

总而言之,我如何获取承载特定服务名称任务的 EC2 实例 ID。理想情况下,此实例 ID 可以通过管道传输到 aws ssm 命令中。

【问题讨论】:

    标签: amazon-web-services amazon-ec2 amazon-ecs


    【解决方案1】:

    每个容器都有一个容器元数据文件。文件位置自动放置在环境变量ECS_CONTAINER_METADATA_FILE 中。

    根据the docs,您必须启用容器元数据,因为它默认不可用。这可以通过在您的 ECS EC2 实例的 /etc/ecs/ecs.config 文件中设置 ECS_ENABLE_CONTAINER_METADATA=true 来完成。 (更新文件后必须重启ECS代理)。

    您可以通过运行cat $ECS_CONTAINER_METADATA_FILE 查看容器中文件的内容。例如,

    {
        "Cluster": "default",
        "ContainerInstanceARN": "arn:aws:ecs:us-west-2:012345678910:container-instance/1f73d099-b914-411c-a9ff-81633b7741dd",
        "TaskARN": "arn:aws:ecs:us-west-2:012345678910:task/2b88376d-aba3-4950-9ddf-bcb0f388a40c",
        "ContainerID": "98e44444008169587b826b4cd76c6732e5899747e753af1e19a35db64f9e9c32",
        "ContainerName": "metadata",
        "DockerContainerName": "/ecs-metadata-7-metadata-f0edfbd6d09fdef20800",
        "ImageID": "sha256:c24f66af34b4d76558f7743109e2476b6325fcf6cc167c6e1e07cd121a22b341",
        "ImageName": "httpd:2.4",
        "PortMappings": [
            {
                "ContainerPort": 80,
                "HostPort": 80,
                "BindIp": "",
                "Protocol": "tcp"
            }
        ],
        "Networks": [
            {
                "NetworkMode": "bridge",
                "IPv4Addresses": [
                    "172.17.0.2"
                ]
            }
        ],
        "MetadataFileStatus": "READY"
    }
    

    有了这些信息,我们可以进行 API 调用来获取容器正在运行的 EC2 实例 ID。对于以下示例,我假设 jqaws-cli 已安装在您的容器中。我还假设您已将环境变量 ECS_CLUSTER 添加到您的 Task Definition,其中包含您的 ECS 集群的名称。

    #!/bin/bash -e
    CONTAINER_ARN=$(cat ${ECS_CONTAINER_METADATA_FILE} | jq -r '.ContainerInstanceARN')
    
    CONTAINER_DESCRIPTION=$(aws ecs describe-container-instances --container-instances ${CONTAINER_ARN} --cluster ${ECS_CLUSTER} --region ${YOUR_REGION})
    
    EC2_INSTANCE_ID=$(echo ${CONTAINER_DESCRIPTION} | jq -r '.containerInstances[0].ec2InstanceId')
    
    echo ${EC2_INSTANCE_ID}
    

    我正在我的容器中运行一个类似的脚本。请务必配置与任务的 IAM 角色关联的 IAM 策略,以便它有权执行 ecs:DescribeContainerInstances 操作。

    【讨论】:

    • 谢谢,知道这肯定很有趣。但是,它似乎需要先登录到特定的容器。这里的问题是以编程方式在许多运行特定任务的容器中找到 ec2 容器实例。
    • @PeterP。实际上,这旨在作为启动脚本的一部分在容器内运行。您无需登录,只需确保您在构建 docker 容器时,您的 docker 命令指向包装您的实际服务的脚本。
    【解决方案2】:

    终于弄清楚了如何在 Ruby 中轻松完成此操作,只需对 AWS CLI 进行一些系统调用,即可将 ec2InstanceId 的映射输出到服务组

    #!/usr/bin/env ruby
    require 'json'
    cluster = ARGV[0]
    container_instances = JSON.parse(`aws ecs list-container-instances --cluster #{cluster} |jq`)["containerInstanceArns"]
    container_instances_metadata = JSON.parse(`aws ecs describe-container-instances --cluster #{cluster} --container-instances #{container_instances.join(' ')}|jq`)["containerInstances"]
    target_map = container_instances_metadata.inject({}){|map, cim| map[cim["containerInstanceArn"]] = cim["ec2InstanceId"]; map}
    
    tasks = JSON.parse(`aws ecs list-tasks --cluster #{cluster} |jq`)["taskArns"]
    tasks_metadata = JSON.parse(`aws ecs describe-tasks --cluster #{cluster} --tasks #{tasks.join(' ')} |jq`)["tasks"]
    
    final_map = tasks_metadata.map do |task|
      ec2InstanceId = target_map[task["containerInstanceArn"]]
      [ec2InstanceId, task["group"], task['overrides']]
    end
    puts final_map.map{|i| i.join(' ')}
    

    【讨论】:

      【解决方案3】:

      也可以通过更简单的方式实现,不客气:?

      CLUSTER=$1
      ServiceName=$2
      TASKARN=$(aws ecs list-tasks --cluster $CLUSTER --service-name $ServiceName  --output text | awk 'NR==1 {print $2}')
      CONTAINER_INSTANCE=$(aws ecs describe-tasks --cluster $CLUSTER --tasks $TASKARN | jq -r '.tasks[0].containerInstanceArn')
      InstanceId=$(aws ecs describe-container-instances --cluster $CLUSTER --container-instances  $CONTAINER_INSTANCE  | jq -r '.containerInstances[0].ec2InstanceId')
      InstanceIp=$(aws ec2 describe-instances --instance-id $InstanceId | jq -r '.Reservations[0].Instances[0].PrivateIpAddress')
      echo $InstanceIp
      

      【讨论】:

        猜你喜欢
        • 2020-01-20
        • 2019-01-23
        • 1970-01-01
        • 1970-01-01
        • 2020-09-20
        • 2019-01-18
        • 1970-01-01
        • 1970-01-01
        • 2017-06-04
        相关资源
        最近更新 更多