Terraform-provider-aws: How can I access IP from aws_ecs_service using `assign_public_ip`

Created on 19 Feb 2018  路  18Comments  路  Source: hashicorp/terraform-provider-aws

I'm creating a ECS service with launch_type = "FARGATE" and assign_public_ip = true.

I would like to be able to access the public IP of the service after it's created,
so that I could create a Route53 record. It doesn't look like there is any way currently to accomplish this.

Could we add a public_ip attribute to the aws_ecs_service resource?

Thanks!

Terraform Version

Terraform v0.11.3
+ provider.aws v1.9.0

Affected Resource(s)

  • aws_ecs_service

Terraform Configuration Files

resource "aws_ecs_service" "mysvc" {
  name = "my_svc"
  cluster = "${aws_ecs_cluster.ecs_cluster.arn}"
  task_definition = "${aws_ecs_task_definition.my_task.arn}"
  desired_count = 1
  launch_type = "FARGATE"

  network_configuration {
    subnets = ["${local.subnet_id}"]
    assign_public_ip = true
    security_groups = ["${aws_security_group.my_sg.id}"]
  }
}

Debug Output

N/A

Panic Output

N/A

Expected Behavior

N/A

Actual Behavior

N/A

Steps to Reproduce

N/A

Important Factoids

N/A

References

  • #2559
enhancement servicecs

Most helpful comment

would be nice to have private_ip of host as well, i need that for setting an environment variable (local host ip) to a container.

All 18 comments

  1. Information of public ip is not included in DescribeServices api response. We might need some custom logic to export the attribute.

  2. Curious about your user case. The public ip seems like dynamic. Do you plan another trigger to update dns record on each ecs task change?

Curious about your user case. The public ip seems like dynamic. Do you plan another trigger to update dns record on each ecs task change?

I'm trying to create a route53 record, to point at the public IP. So yes, whenever the ECS task changes, it would update the Route53 record

would be nice to have private_ip of host as well, i need that for setting an environment variable (local host ip) to a container.

+1

I am running into a very similar issue when attempting to create an aws_lb_target_group_attachment resource. Perhaps I am missing something there though.

EDIT:

I was missing the fact that with Fargate you don't have to specify aws_lb_target_group_attachment because it is specified in aws_ecs_service (facepalm).

As for this original issue:

You can have a Fargate aws_ecs_service with multiple containers so I am not sure that public_ip would be a valid attribute. Even if there was a public_ips attribute added, then there would still be the issue that everytime a container was deprovisioned you would have to do another terraform apply so that your new container was recognized by route53.

Here are a couple of solutions though:

  1. Create an alb and make an alias record in route53. This is what I am doing. (Not ideal if you are worried about the cost for one container, but then again why use Fargate if that's the case).
  2. Create a lambda function to get the container's IP address and update route53 via boto3. (Ideal for cost-effective one-off solutions.)

Let me know if you need any help with the above solutions, and I would be happy to assist.

Curious about your user case. The public ip seems like dynamic. Do you plan another trigger to update dns record on each ecs task change?

I'm trying to create a route53 record, to point at the public IP. So yes, whenever the ECS task changes, it would update the Route53 record

nice! +1

This would be really useful when creating a running task in Fargate via a service. Was hoping that maybe there would be a data source associated with the ECS cluster and the associated tasks in it that would provide this information. But there is not.

I have a related use case. I am trying to deploy a grafana instance in Fargate and then use the terraform grafana provider to configure it. I need a way to pass the IP address of the instance to the provider so that the provider will know what it's configuring.

No news about this?

Not sure it helps but I am looking to do this as well and my workaround plan
is to use this
https://github.com/matti/terraform-shell-resource

with ecs-cli ps command to get the ip into terraform https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cmd-ecs-cli-ps.html

Having the same issue with fargate.

Whenever I update ECS or Task Definition (SSM parameters and such) I need to point my routing to this new public ip

however as @loivis its on Amazon's side

Just wanted to add that I would also like to get the public IP from the task. In my case it doesn't matter that the IP changes.

Via terraform, I spin up the task, spin up a VM, and then there is an app on the VM that has to connect to the tasks public IP.

Both the task and VM are brought up/down at the same time.

I want to just pass the public IP directly to my terraform VM code.

would be nice to have private_ip of host as well, i need that for setting an environment variable (local host ip) to a container.

Is there any update on how i can access the private ip?
I'm trying to send custom metrics to a datadog sidecar and can't seem to figure out how to get the private ip once the task definition is running.

Hi, I worked around the issue of obtaining the public and private IPs by:

  1. Define a new security group for the ECS service
  2. Define the ECS service and opt to put it in the new security group
  3. The security group will automatically have a network interface attached to it which is owned by the service
  4. Pull out the private and public IPs from the network interface

It is a bit of a faff, you have to make sure you only have the single ECS service using the security group, otherwise you have multiple network interfaces and you cannot determine which one is for the ECS service via terraform.

It takes a few seconds for the network interface to be created. Terraform reports the ECS service resource creation is complete even though the network interface will not yet be available. So you need to set a "sleep" step in terraform (I waited 30 secs) before querying the network interface.

Also (and I cannot remember the exact issue as it was a while ago I tested this), if your ECS service has issues and keeps going up and down, it will keep getting a new public IP each time (and IIRC it deletes and redefines the network interface each time). If you decide to run a terraform apply/destroy at this point, then depending on timing, terraform can get confused as the interface it thinks is there, will not be.

I have the code I used, you are welcome to it, but the code/workaround isn't really suitable for production use due to the issue of changing network interfaces and IPs when the ECS service restarts. But then that's an AWS "feature".

Scott

Thank you @scott-doyland-burrows !
It turns out that my issue wasn't really an issue and a lapse in my understanding of networking in Fargate.

With multiple containers in the same Fargate task, you can use localhost/127.0.0.1 to communicate between containers.

Hi, I worked around the issue of obtaining the public and private IPs by:

  1. Define a new security group for the ECS service
  2. Define the ECS service and opt to put it in the new security group
  3. The security group will automatically have a network interface attached to it which is owned by the service
  4. Pull out the private and public IPs from the network interface

It is a bit of a faff, you have to make sure you only have the single ECS service using the security group, otherwise you have multiple network interfaces and you cannot determine which one is for the ECS service via terraform.

It takes a few seconds for the network interface to be created. Terraform reports the ECS service resource creation is complete even though the network interface will not yet be available. So you need to set a "sleep" step in terraform (I waited 30 secs) before querying the network interface.

Also (and I cannot remember the exact issue as it was a while ago I tested this), if your ECS service has issues and keeps going up and down, it will keep getting a new public IP each time (and IIRC it deletes and redefines the network interface each time). If you decide to run a terraform apply/destroy at this point, then depending on timing, terraform can get confused as the interface it thinks is there, will not be.

I have the code I used, you are welcome to it, but the code/workaround isn't really suitable for production use due to the issue of changing network interfaces and IPs when the ECS service restarts. But then that's an AWS "feature".

Scott

@scott-doyland-burrows I am new to Terraform, can you put a sample code for pulling he network interface IPs?

Hi, I have the same requirement. I need to extract the Private Ip of the Fargate task and need to pass the same in the container template as a parameter to the COMMAND so that the application can be run on that IP. I am trying the below command to run consul but it asks for IP.

"command": [
"consul agent -server -data-dir=/consul/data -bootstrap -ui -client=0.0.0.0 -bind=0.0.0.0"
],

Instead of 0.0.0.0 need to pass the private IP address, and couldn't find any solution yet.

It was a few months ago so I cannot remember exactly how this works - as I have not had to touch it since then...

Create a security group (not shown below - but I did this via a module).

Create your ecs service (not shown below - but I did this via a module) and put in in the security group.

Then wait 30 seconds (required as it takes a few secs for the NIC to be defined). The NIC will be tied to a security group.

Then call the first data block below, this will get a list of all NICs in the security group (you must have just ONE NIC per security group for this to work).
So you end up with one NIC ID.

The second data block gets the attributes for the ID of the NIC from the first data block.

The first output block displays the private IP of the NIC.

The second output block displays the public IP of the NIC.

resource "time_sleep" "sigserv_30_seconds" {
  depends_on = [module.ecsservicesigserv]

  create_duration = "30s"
}

data "aws_network_interfaces" "networkinterfacesigserv" {
  depends_on = [time_sleep.sigserv_30_seconds]

  filter {
    name   = "group-id"
    values = [module.securitygroupsigserv.security_group_id]
  }
}

data "aws_network_interface" "networkinterfacesigserv" {
  id = join(",", data.aws_network_interfaces.networkinterfacesigserv.ids)
}

output "ecs_privateipv4_sigserv" {
  value = data.aws_network_interface.networkinterfacesigserv.private_ip
}

output "ecs_publicipv4_sigserv" {
  value = join(",", data.aws_network_interface.networkinterfacesigserv[*].association[0].public_ip)
}

The problem you will have is that if the ecs service dies and restarts itself, it will get a different public IP (IIRC) so you would need to manage this by rerunning terraform, so I think you'd need a terraform apply to force terraform to pick up the new IP in terraform output.

I sort of gave up with this in the end as it was all a bit messy, it was fine for just some dev work, but I wouldn't suggest you use it for more than that.

Was this page helpful?
0 / 5 - 0 ratings