traw1233
traw1233

Reputation: 1945

Identify Hardcoded DNS Records for ECS Instances

I have a docker image that I need to deploy, while maintaining a consistent DNS record. On top of that, I'd like to have a hard coded number of instances (for example, 2). I like the ease of ECS as well as ECS agent maintaining uptime, but a load balancer is overkill for a single instance. As of now I just create an ASG with min/max/desired as 1 so there isn't any conflicting issues.

There is a very heavy argument against numbering instances in an autoscaling group (here is one example), and that makes sense, though I think this is a pretty solid use case where it cannot be avoided.

I've successfully modified meltwater/terraform-aws-asg-dns-handler to give a single ECS instance within an ASG a hardcoded DNS record (say instance-1.example.com), though its not very pretty. In order to get two instances working though (instance-1.example.com and instance-2.example.com), I think I have two options:

Neither of these seem like very solid options to me so I'm wondering if there is a better way to deploy a single Docker container in an ECS-like manner that I can attach a DNS record to.

For context, the "two ECS cluster" approach would work fine, but I'm going to do this three or four times, so I would end up with 8 ECS clusters on top of a few others, which is inconvenient to say the least.

Upvotes: 0

Views: 286

Answers (1)

paulg
paulg

Reputation: 738

If you are using an Auto Scaling Group and a Launch Config or Template with user-data... this is something I've added in the user-data to automatically keep the Route53 DNS Records up to date any time a new Instance spins up, with a counter. Hopefully this can help!

## --------------------------------------------------------------------------------------------------------------- ##
## --- AUTO SCALING LOGIC for user-data -------------------------------------------------------------------------- ##
## --------------------------------------------------------------------------------------------------------------- ##
## --- Get ip addresses of existing app DNS Entries (that point to app nodes, not load balancer) ----- ##
## --- Get this ip address --------------------------------------------------------------------------------------- ##
## --- If this IP Address matches any in existing list, do not create a new DNS record --------------------------- ##
## --- If this IP Address does not match any in existing list, create a new DNS record --------------------------- ##
## --------------------------------------------------------------------------------------------------------------- ##

region="us-east-1"
hosted_zone="ROUTE53-HOSTED-ZONE-ID"
vpc="vpc-ID"
r53_domain="example.com"
asg_desired="2"
application="app"

echo "USING EC2 INSTANCE META DATA TO OBTAIN IP ADDRESS ..."
echo "IF YOU ARE NOT USING DEFAULT AMZN INSTANCE, USE ifconfig OR ANOTHER METHOD TO OBTAIN THIS INSTANCE IP ..."

# CHOOSE THE PRIVATE (local-ipv4) OR PUBLIC IP DEPENDING ON USE CASE 
#this_ip=`curl http://169.254.169.254/latest/meta-data/local-ipv4`
this_ip=`curl http://169.254.169.254/latest/meta-data/public-ipv4`
echo $this_ip > /tmp/this-ip.txt

# FILTER BASED ON UNIQUE TAGS FOR YOUR TARGETED INSTANCE(S)
# THIS IS USING Application Tag. 
aws --region $region ec2 describe-instances --query "Reservations[*].Instances[? Tags[? (Key=='Application') && Value=='$application']].PublicIpAddress" --output text >> /tmp/existing-ec2-ips.txt

counter=1
until [ $counter -gt $asg_desired ]
do
  aws --region $region route53 list-resource-record-sets --hosted-zone-id $hosted_zone --query "ResourceRecordSets[?Name == 'instance-$counter.$r53_domain.'].ResourceRecords" --output text >> /tmp/existing-ips.txt
  aws --region $region route53 list-resource-record-sets --hosted-zone-id $hosted_zone --query "ResourceRecordSets[?Name == 'instance-$counter.$r53_domain.']" --output text >> /tmp/existing-records.txt
  ((counter++))
done

diff /tmp/existing-ips.txt /tmp/this-ip.txt

echo "Does this instance IP exist in a $application route53 record?"
this_ip_result=`grep $this_ip /tmp/existing-ips.txt | wc -l`

if [[ $this_ip_result -gt 0 ]]
then
  echo "Yes, this instance IP already exists in a $application route53 record."
  echo "Nothing left to do"
else
  echo "No, this instance IP does not exist in a $application route53 record."
  echo "Adding route53 record... "
  counter=1
    until [ $counter -gt $asg_desired ]
    do
        grep -L instance-$counter.$r53_domain /tmp/existing-records.txt > /tmp/instance-$counter.$r53_domain.txt
        if [ -s /tmp/instance-$counter.$r53_domain.txt ]
            then
                echo "instance-$counter.$r53_domain does not exist... Adding!"
                aws --region $region route53 change-resource-record-sets --hosted-zone-id $hosted_zone --change-batch '{ "Comment": "Auto Scaling Creating Record Set", "Changes": [ { "Action": "CREATE", "ResourceRecordSet": { "Name": "instance-'$counter'.'$r53_domain'", "Type": "A", "TTL": 120, "ResourceRecords": [ { "Value": "'"$this_ip"'" } ] } } ] }'
            else
                echo "Updating Record Set!"
                echo "Updating Route53 Records with the following IPs ..."
                diff /tmp/existing-ec2-ips.txt /tmp/existing-ips.txt | grep ">" | sed 's/> //g'
                ip_update=`diff /tmp/existing-ec2-ips.txt /tmp/existing-ips.txt | grep ">" | sed 's/> //g'`
                record_update=`grep -B 1 $ip_update /tmp/existing-records.txt | grep $application | awk '{print $1}' | awk 'FNR == 1 {print}'`
                aws --region $region route53 change-resource-record-sets --hosted-zone-id $hosted_zone --change-batch '{ "Comment": "Auto Scaling Updating Record Set", "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "'"$record_update"'", "Type": "A", "TTL": 120, "ResourceRecords": [ { "Value": "'"$this_ip"'" } ] } } ] }'
            fi
        ((counter++))
    done
fi

Upvotes: 1

Related Questions