36

I have a cluster running with services and am also able to launch fargate tasks from the command line. I can get the taskArn as a response to launching the task and I can wait for the task to be in the running state by using "aws ecs wait". I'm stuck figuring out how to get the the public IP of the task. I can find it via the web page easily enough and can access the machine via it's public IP...

How do I get the public IP of a fargate task using the CLI interface?

I'm using the following commands to launch the task, wait for it to run and retrieve the task description:

$ aws ecs run-task --launch-type FARGATE --cluster xxxx --task-definition xxxx --network-configuration xxxx
$ aws ecs wait <taskArn>
$ aws ecs describe-tasks --cluster xxxx --task <taskArn> | grep -i ipv4

The last command only gives me the private IP...

"privateIpv4Address": "10.0.1.252",
"name": "privateIPv4Address"

I've also tried using:

$ ecs-cli ps --cluster xxxx

But the Ports column is blank.

Name                                       State    Ports  TaskDefinition
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxxx  RUNNING         xxxx:1
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxxx  RUNNING         xxxx:1
Mike N.
  • 1,662
  • 1
  • 13
  • 19

5 Answers5

37

Once I realized that describe-tasks gave me the ENI id along with the private IP I was able to get the public IP with:

$ aws ec2 describe-network-interfaces --network-interface-ids eni-xxxxxxxx
Mike N.
  • 1,662
  • 1
  • 13
  • 19
9

This was specific to my usecase, but perhaps its useful to someone else (intended to be run as javascript in Lambda just after you run ecs.createService() )

Yes, I know this topic is for CLI but this is the first result that popped up when looking for "Fargate public IP" and i was looking for a javascript based solution.

// get container IP
getContainerIP(myServiceName).then(ip => {
  console.log("Container IP address is: ", ip);

}).catch(err => {
  console.log(err);
});



function getContainerIP(servicename) {
  // note: assumes that only 1 task with 1 container is in the provided service, and that a container only has 1 network interface

  return new Promise(function (resolve, reject) {
    // get task arns (needs a delay because we just launched it)
    setTimeout(getTasks, 6000);

    // get task arns
    function getTasks() {
      ecs.listTasks({
        cluster: process.env.ecs_cluster,
        launchType: "FARGATE",
        serviceName: servicename
      }, function (err, res) {
        if (err) {
          reject("Unable to get task list");
          return;
        }

        // loop until we have a result
        if (!res.taskArns.length) {
          setTimeout(getTasks, 2000);
          return;
        }

        // get details
        getTaskDetails(res.taskArns);
      });
    }

    // get the details of the task (we assume only one task because that's how its configured)
    function getTaskDetails(taskArns) {
      ecs.describeTasks({
        cluster: process.env.ecs_cluster,
        tasks: taskArns
      }, function (err, res) {
        if (err) {
          reject("Unable to get task details");
          return;
        }

        // no results
        if (!res.tasks.length || !res.tasks[0].attachments.length) {
          reject("No tasks available");
          return;
        }

        // network needs to be in status ATTACHING to see the eni, else wait
        if (res.tasks[0].attachments[0].status !== "ATTACHING") {
          setTimeout(function () { getTaskDetails(taskArns); }, 2000);
          return;
        }

        // get network ID from result
        let eni = "";
        for (let i in res.tasks[0].attachments[0].details) {
          if (!res.tasks[0].attachments[0].details.hasOwnProperty(i)) continue;
          if (res.tasks[0].attachments[0].details[i].name !== "networkInterfaceId") continue;

          // get the eni
          eni = res.tasks[0].attachments[0].details[i].value;
          break;
        }

        // no eni
        if (eni === "") {
          reject("Unable to retrieve container ENI");
          return;
        }

        // get network details
        getNetworkDetails(eni);
      });
    }

    // get network details
    function getNetworkDetails(eni) {

      // get the ENI details
      ec2.describeNetworkInterfaces({
        NetworkInterfaceIds: [eni]
      }, function (err, res) {
        if (err) {
          reject("Unable to retrieve ENI details");
          return;
        }

        // confirm available data
        if (!res.NetworkInterfaces.length || typeof res.NetworkInterfaces[0].Association === "undefined" || typeof res.NetworkInterfaces[0].Association.PublicIp === "undefined") {
          reject("Unable to retrieve IP from ENI details");
          return;
        }

        // resolve the public IP address
        resolve(res.NetworkInterfaces[0].Association.PublicIp);
      });
    }
  });
}
Eric Jiang
  • 544
  • 7
  • 13
Thomas Smart
  • 135
  • 1
  • 9
8

You can use a script like this.

SERVICE_NAME="my-service"

TASK_ARN=$(aws ecs list-tasks --service-name "$SERVICE_NAME" --query 'taskArns[0]' --output text)
TASK_DETAILS=$(aws ecs describe-tasks --task "${TASK_ARN}" --query 'tasks[0].attachments[0].details')
ENI=$(echo $TASK_DETAILS | jq -r '.[] | select(.name=="networkInterfaceId").value')
IP=$(aws ec2 describe-network-interfaces --network-interface-ids "${ENI}" --query 'NetworkInterfaces[0].Association.PublicIp' --output text)

echo "$IP"
Stephen
  • 4,228
  • 4
  • 29
  • 40
  • 2
    You can also get the network interface ID in one line without using jq (which I don't have) using the following query: ```tasks[0].attachments[0].details[?name==`networkInterfaceId`].value``` – user2217751 Apr 12 '22 at 20:51
  • 2
    Thanks for this! I just needed to add the parameter `--cluster "${CLUSTER_NAME}"` to the commands `aws ecs list-tasks` and `aws ecs describe-tasks` and it worked :) – Ewa Aug 06 '22 at 01:05
0

I tinkered around with one of the comments here and came up with the following shell script:

#!/bin/bash

# Take the cluster name from the script arguments
CLUSTER_NAME=$1

# Get a list of tasks in the cluster
TASKS=$(aws ecs list-tasks --cluster "$CLUSTER_NAME" --query "taskArns" --output text)

# Loop through each task to get the container instance ARN
for TASK_ARN in $TASKS
do
  # Get a human readable ARN.
  TASK_ID=$(basename $TASK_ARN)
  
  # Get the network interface ID for the task
  NETWORK_INTERFACE_ID=$(aws ecs describe-tasks --cluster $CLUSTER_NAME --tasks $TASK_ARN --query 'tasks[0].attachments[0].details[?name==`networkInterfaceId`].value' --output text)
  
  #Get the public IP of the network interface
  PUBLIC_IP=$(aws ec2 describe-network-interfaces --network-interface-ids $NETWORK_INTERFACE_ID --query 'NetworkInterfaces[0].Association.PublicIp')

  echo "Task: $TASK_ID -- Public IP: $PUBLIC_IP"
done

you can call your script like ./list-ecs-tasks.sh <your-cluster-arn> and it loops through the tasks in your cluster and prints out the TaskID and Public IP of each one.

Simeon Borisov
  • 417
  • 2
  • 6
-5
describe-addresses

the docs are here: https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-addresses.html

AlexGera
  • 756
  • 9
  • 19