Mike N.
Mike N.

Reputation: 1732

How do I retrieve the public IP for a fargate task using the CLI?

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

Upvotes: 36

Views: 30124

Answers (6)

Inx Maurya
Inx Maurya

Reputation: 1155

ECS Get PublicDnsName and PublicIp in case of FARGATE

Step-1

aws ecs list-tasks --cluster <cluster-name> --service-name <service-name>
CLI: aws ecs list-tasks --cluster inx --service-name inx-service

Step-2

aws ecs describe-tasks --cluster <cluster-name> --tasks <arn-of-task>
CLI: aws ecs describe-tasks --cluster inx --tasks arn:aws:ecs:ap-south-1:123456789012:task/inx/3b2902d17ca64d7e96eb412253fd8cf9

Inside attachments section get networkInterfaceId that should be like eni-0e07d16ba740ecf8d

...
{
 "name": "networkInterfaceId",
 "value": "eni-0e07d16ba740ecf8d"
},
...

Step-3

aws ec2 describe-network-interfaces --network-interface-ids <eni-id>
                    
CLI: aws ec2 describe-network-interfaces --network-interface-ids eni-0e07d16ba740ecf8d

...
{
  "NetworkInterfaces": [
  {
    "Association": {
    "IpOwnerId": "amazon",
    "PublicDnsName": "ec2-11-123-11-111.ap-south-1.compute.amazonaws.com",
    "PublicIp": "11.123.11.111"
  }
...

finally

Have a look into Step-3 Here "PublicDnsName": "ec2-11-123-11-111.ap-south-1.compute.amazonaws.com" is your Public Dns Name address and "PublicIp": "11.123.11.111" is your Public Ip address

Upvotes: 0

Simeon Borisov
Simeon Borisov

Reputation: 614

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.

Upvotes: 2

Thomas Smart
Thomas Smart

Reputation: 145

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);
      });
    }
  });
}

Upvotes: 9

Stephen
Stephen

Reputation: 4296

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"

Upvotes: 10

AlexGera
AlexGera

Reputation: 783

describe-addresses

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

Upvotes: -6

Mike N.
Mike N.

Reputation: 1732

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

Upvotes: 39

Related Questions