Best way to pass elasticache node addresses to webservers?

527 views
Skip to first unread message

David Winterbottom

unread,
Aug 31, 2015, 4:38:16 PM8/31/15
to terrafo...@googlegroups.com
Hi,

I'm looking to pass the DNS address of each elasticache node to my AWS webservers but am not sure of the best approach.

One approach I'm trying is to write the node addresses into a config file using the EC2 metadata, something like this:

resource "template_file" "web-userdata" {
    filename = "userdata/web.sh"
    vars {
        cache_node_1 = "${aws_elasticache_cluster.web.cache_nodes.0.address}"
        cache_node_2 = "${aws_elasticache_cluster.web.cache_nodes.1.address}"
    }
}

resource "aws_launch_configuration" "webserver" {
    image_id = "${var.web_ami}"
    instance_type = "t2.micro"
    user_data = "${template_file.web-userdata.rendered}"
    ...
}

This works but seems ugly. Is there a way to avoid individually specifying each node address as template vars? I couldn't seem to pass a list of address, nor grab the a list attribute from the elasticache resource itself.

Is there a better way? Does elasticache work well with Consul (which I haven't looked into in detail yet)?

Aside: there also doesn't seem to be a resource attribute for the "configuration endpoint" address, which is another option although I don't want to use a custom memcache client.

Thanks in advance, David

One option is to use Elasticache exposes a "configuration endpoint" 

Paul Hinze

unread,
Sep 2, 2015, 11:30:22 AM9/2/15
to terrafo...@googlegroups.com
Hi David,

You should be able to use the `join()` interpolation function along with the "splat" notation to get a delimited list into your template.

Like this:

resource "template_file" "web-userdata" {
    filename = "userdata/web.sh"
    vars {
        cache_nodes = "${join(",", aws_elasticache_cluster.web.cache_nodes.*.address)}"
    }
}

While config-time setup like this tends to work out fine for the most part, the reality is that cluster node discovery is probably more of a runtime thing. Another approach I've used in the past is to give your instance an Instance Role that allows API calls to DescribeCacheClusters, then you just yield the Cluster ID to your app and let it discover the nodes itself. It's more complexity pushed to the application, but it does allow you more flexibility to deal with cache node changes at runtime.

And good call on the configuration endpoint being missing - we should definitely expose that. Filed as https://github.com/hashicorp/terraform/issues/3149

You're welcome to take a shot at a PR if you like! :)

Paul

--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
 
GitHub Issues: https://github.com/hashicorp/terraform/issues
IRC: #terraform-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Terraform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to terraform-too...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/CANaXhwn-5jnwc%3Dmc0qgdpK5rq%3DnEXp0F%2BMmNAGabrm9ne93KNQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

David Winterbottom

unread,
Sep 3, 2015, 6:03:34 AM9/3/15
to Terraform
Paul,


On Wednesday, 2 September 2015 16:30:22 UTC+1, Paul Hinze wrote:
Hi David,

You should be able to use the `join()` interpolation function along with the "splat" notation to get a delimited list into your template.

Like this:

resource "template_file" "web-userdata" {
    filename = "userdata/web.sh"
    vars {
        cache_nodes = "${join(",", aws_elasticache_cluster.web.cache_nodes.*.address)}"
    }
}

While config-time setup like this tends to work out fine for the most part, the reality is that cluster node discovery is probably more of a runtime thing. Another approach I've used in the past is to give your instance an Instance Role that allows API calls to DescribeCacheClusters, then you just yield the Cluster ID to your app and let it discover the nodes itself. It's more complexity pushed to the application, but it does allow you more flexibility to deal with cache node changes at runtime.

Yes, that's a better idea. 

For the record, this userdata does the trick, writing the elasticache configuration endpoint to /etc/aws/elasticache where my application can read it from:

#!/usr/bin/env bash
apt-get update
apt-get install -y python-pip jq

echo "Installing AWS command line SDK"
pip install -U pip
pip install awscli

mkdir -p /etc/aws/

echo "Discovering EC2 metadata"
ec2metadata \
    | grep availability-zone \
    | awk '{print substr($2, 1, length($2) - 1)}' \
    > /etc/aws/region

echo "Discovering elasticache endpoints"
REGION=$(cat /etc/aws/region)
aws --region=$REGION elasticache describe-cache-clusters \
    | jq '.CacheClusters[] | select(.CacheSubnetGroupName=="web") | .ConfigurationEndpoint.Address' \
    | tr -d '"' \
    > /etc/aws/elasticache

 

And good call on the configuration endpoint being missing - we should definitely expose that. Filed as https://github.com/hashicorp/terraform/issues/3149

I'll have a look at that - although it will be next week before I have the time.
Reply all
Reply to author
Forward
0 new messages