识别 ECS 实例的硬编码 DNS 记录
Identify Hardcoded DNS Records for ECS Instances
我有一个 docker 图像需要部署,同时保持一致的 DNS 记录。最重要的是,我希望有一个硬编码的实例数(例如,2)。我喜欢 ECS 的易用性以及维护正常运行时间的 ECS 代理,但负载均衡器对于单个实例来说太过分了。截至目前,我只是创建了一个 min/max/desired 作为 1
的 ASG,因此没有任何冲突问题。
反对在自动缩放组中对实例进行编号的争论非常激烈(here 就是一个例子),这是有道理的,尽管我认为这是一个无法避免的非常可靠的用例。
我已成功修改 meltwater/terraform-aws-asg-dns-handler,为 ASG 中的单个 ECS 实例提供硬编码的 DNS 记录(比如 instance-1.example.com
),尽管它不是很漂亮。为了让两个实例正常工作(instance-1.example.com
和 instance-2.example.com
),我想我有两个选择:
- 创建一个 hacky 解决方案来读取我的 Lambda 函数中的现有 Route53 记录,以“确定性地”决定在 ASG 生命周期挂钩中为我的实例分配哪个索引(this 可能是一个好的开始)
- 创建两个 ECS 集群,每个都有一个实例,并使用两个单独的 Lambda 函数
这些对我来说都不是非常可靠的选择,所以我想知道是否有更好的方法以类似 ECS 的方式部署单个 Docker 容器,我可以将 DNS 记录附加到.
就上下文而言,“两个 ECS 集群”方法可以正常工作,但我打算这样做三四次,所以我最终会在一个其他的很少,至少可以说是不方便。
如果您正在使用 Auto Scaling 组和带有用户数据的启动配置或模板...这是我在用户数据中添加的内容,可随时自动使 Route53 DNS 记录保持最新一个新的实例旋转起来,带有一个计数器。希望这可以帮助!
## --------------------------------------------------------------------------------------------------------------- ##
## --- 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 }' | 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
我有一个 docker 图像需要部署,同时保持一致的 DNS 记录。最重要的是,我希望有一个硬编码的实例数(例如,2)。我喜欢 ECS 的易用性以及维护正常运行时间的 ECS 代理,但负载均衡器对于单个实例来说太过分了。截至目前,我只是创建了一个 min/max/desired 作为 1
的 ASG,因此没有任何冲突问题。
反对在自动缩放组中对实例进行编号的争论非常激烈(here 就是一个例子),这是有道理的,尽管我认为这是一个无法避免的非常可靠的用例。
我已成功修改 meltwater/terraform-aws-asg-dns-handler,为 ASG 中的单个 ECS 实例提供硬编码的 DNS 记录(比如 instance-1.example.com
),尽管它不是很漂亮。为了让两个实例正常工作(instance-1.example.com
和 instance-2.example.com
),我想我有两个选择:
- 创建一个 hacky 解决方案来读取我的 Lambda 函数中的现有 Route53 记录,以“确定性地”决定在 ASG 生命周期挂钩中为我的实例分配哪个索引(this 可能是一个好的开始)
- 创建两个 ECS 集群,每个都有一个实例,并使用两个单独的 Lambda 函数
这些对我来说都不是非常可靠的选择,所以我想知道是否有更好的方法以类似 ECS 的方式部署单个 Docker 容器,我可以将 DNS 记录附加到.
就上下文而言,“两个 ECS 集群”方法可以正常工作,但我打算这样做三四次,所以我最终会在一个其他的很少,至少可以说是不方便。
如果您正在使用 Auto Scaling 组和带有用户数据的启动配置或模板...这是我在用户数据中添加的内容,可随时自动使 Route53 DNS 记录保持最新一个新的实例旋转起来,带有一个计数器。希望这可以帮助!
## --------------------------------------------------------------------------------------------------------------- ##
## --- 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 }' | 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