我在 Google Cloud 中有很多虚拟机,很少需要用于调试。一直运行它们会花费很多钱,所以它们大部分时间都处于关闭状态。问题是,如果机器重新启动,临时 IP 地址会发生变化,DNS 记录会不匹配。我知道可以使用静态 IP 地址,但是IP 静态 IP 地址(已分配但未使用)相当昂贵,来源https://cloud.google.com/vpc/network-pricing
有什么好方法可以将外部 DNS 记录指向很少重启的虚拟机,而无需使用静态外部 IP 地址?
我在 Google Cloud DNS 中有一个域名,在其他提供商中也有外部 DNS 域名。
答案1
希望你一切都好。为了补充@Sergiusz 之前的回答,我做了以下事情。
在 Cloud DNS 中配置了一个区域(超出了问题范围)
创建一个分配有 DNS 管理员角色/权限的服务帐户(可以稍微收紧一点),然后将服务帐户的 json 密钥下载到虚拟机上的 /root/sa-file.json
使用自定义值更新了虚拟机的元数据:
dns_zone_name(存储区域的名称,fe gcp-jd-zone)
dns_域名(存储 fqdn,fe gcp.jabbsondude.com)
dns_record_ttl(存储创建的 A 记录的 ttl,fe 600)
密钥路径(存储服务帐户密钥文件的路径,fe /root/sa-file.json)使用启动脚本更新了虚拟机的元数据:
#!/bin/bash
host=$HOSTNAME
url_project_id="http://metadata.google.internal/computeMetadata/v1/project/project-id"
url_ip_address="http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip"
url_attributes="http://metadata.google.internal/computeMetadata/v1/instance/attributes"
get_metadata() {
local data=`curl -s -f $url_attributes/$1 -H "Metadata-Flavor: Google"`
if [ -z "$data" ]; then
echo "$1 does not exist in metadata. Exiting."
exit 1
fi
echo "$data"
}
auth_gcloud() {
project=`curl -s $url_project_id -H "Metadata-Flavor: Google"`
echo "Authenticating gcloud with service account ($key_path), project ($project)."
gcloud auth activate-service-account --project=$project --key-file=$key_path >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Authentication succeeded."
else
echo "Authentication failed. Exiting."
exit 2
fi
}
dns_check_record_exists() {
echo "Checking if record ($host.$dns_domain) already exists in Cloud DNS"
dns_data=`gcloud beta dns record-sets list --zone=$dns_zone_name --name=$host.$dns_domain --format=text`
if [ $? -eq 0 ]; then
echo "Received answer from Cloud DNS."
else
echo "Didn't receive any data from Cloud DNS. Exiting."
exit 3
fi
if [[ -n "$dns_data" ]]; then
echo "Found existing record."
return 1 # data exists
else
echo "Didn't find existing record."
return 0 # no data
fi
}
dns_record_create() {
echo "Creating new record in Cloud DNS ($host.$dns_domain) in zone ($dns_zone_name) with ip ($ip) and ttl ($dns_record_ttl)"
gcloud beta dns record-sets create $host.$dns_domain --rrdatas=$ip --type=A --zone=$dns_zone_name --ttl=$dns_record_ttl >/dev/null 2>&1
}
dns_record_update() {
echo "Updating existing record in Cloud DNS ($host.$dns_domain) in zone ($dns_zone_name) with ip ($ip) and ttl ($dns_record_ttl)"
gcloud beta dns record-sets update $host.$dns_domain --rrdatas=$ip --type=A --zone=$dns_zone_name --ttl=$dns_record_ttl >/dev/null 2>&1
}
# getting metadata
dns_zone_name="$(get_metadata dns_zone_name)"
dns_domain="$(get_metadata dns_domain)"
dns_record_ttl="$(get_metadata dns_record_ttl)"
key_path="$(get_metadata key_path)"
# getting exterinal ip
ip=`curl -s $url_ip_address -H "Metadata-Flavor: Google"`
# validating external ip
if [[ -n "$ip" && $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
echo "External ip detected: $ip"
auth_gcloud
dns_check_record_exists
if [ $? -eq 0 ]; then
dns_record_create
else
dns_record_update
fi
else
echo "No external ip detected. Exiting."
exit 5
fi
虚拟机实例详细信息中的内容如下: 图片
- 重新启动虚拟机
日志的输出(对于 Debian 来说,是 /var/log/daemon.log):
Found startup-script in metadata.
startup-script: External ip detected: 123.213.132.2
startup-script: Authenticating gcloud with service account (/root/sa-file.json), project (jabbsondude-proj).
startup-script: Authentication succeeded.
startup-script: Checking if record (instance-1.gcp.jabbsondude.com) already exists in Cloud DNS
startup-script: Received answer from Cloud DNS.
startup-script: Didn't find existing record.
startup-script: Creating new record in Cloud DNS (instance-1.gcp.jabbsondude.com) in zone (gcp-jd-zone) with ip (123.213.132.2) and ttl (600)
startup-script exit status 0
该脚本用于为使用上述脚本启动的每个虚拟机创建和更新 A 记录。通过更多检查,它可能会得到改进,这只是我在过去一小时出于好奇而想到的。
如果您需要任何帮助或者出现任何问题,请告诉我。
答案2
如果您很少使用这些虚拟机,最好使用命令检查当前的外部 IP:gcloud compute addresses list --filter="VM-NAME"
无论如何,这是我的(丑陋的)解决方案:
- 创造公共 DNS 区域并添加指向VM当前外部IP的A记录。
- 在注册商页面上添加 NS 记录,将您的域名重定向到 Google DNS,它将是以下之一(它们将在您的区域中列出):
ns-cloud-a1.googledomains.com.
ns-cloud-b1.googledomains.com.
ns-cloud-c1.googledomains.com.
- 添加启动脚本这将检查虚拟机的临时公共 IP 并更新公共 DNS 区域:
#!/bin/bash
IP=$(curl -s api.ipify.org)
gcloud beta dns record-sets delete mydomain.com \
--type=A \
--zone=ZONE-NAME
gcloud beta dns record-sets create mydomain.com \
--rrdatas=$IP \
--ttl=TTL \
--type=A \
--zone=ZONE-NAME
您可以找到有关 DNS 记录的更多信息这里。