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.
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