Domain-Name-System

如何在沒有靜態外部 IP 的情況下將外部 DNS 記錄指向 GCP VM 實例?

  • March 13, 2021

我在 Google Cloud 中有很多很少需要調試的虛擬機。一直執行它們會花費很多,因此它們大部分時間都處於關閉狀態。問題是如果機器重新啟動,臨時 IP 地址會發生變化,並且 DNS 記錄將不匹配。我知道可以使用靜態 IP 地址,但是**IP 靜態 IP 地址(已分配但未使用)**非常昂貴,來源https://cloud.google.com/vpc/network-pricing

在不使用靜態外部 IP 地址的情況下,將外部 DNS 記錄指向很少重新啟動的 VM 的好方法是什麼?

我在 Google Cloud DNS 中有一個域,在其他提供商中也有外部 DNS 域。

一切順利。為了在@Sergiusz 的先前答案中添加一點內容,這就是我所做的。

  • 在 Cloud DNS 中配置了一個區域(不在問題範圍內)
  • 創建了一個分配了 DNS 管理員角色/權限的服務帳戶(可以收緊一點),然後將服務帳戶的 json 密鑰下載到 VM 上的 /root/sa-file.json
  • 使用自定義值更新了 VM 的元數據:

dns_zone_name(用於儲存區域的名稱,fe gcp-jd-zone)

dns_domain(用於儲存 fqdn,fe gcp.jabbsondude.com)

dns_record_ttl(用於儲存創建的 A 記錄的 ttl,fe 600)

key_path(使用服務帳戶密鑰儲存文件的路徑,fe /root/sa-file.json)

  • 使用啟動腳本更新了 VM 的元數據:
#!/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

以下是它在 VM 實例詳細資訊中的外觀: img

  • 重新啟動虛擬機

日誌的輸出(如果是 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

該腳本用於為使用上述腳本啟動的每個 VM 創建和更新 A 記錄。它可能可以通過更多檢查來改進,這只是我在過去一個小時裡出於好奇而想出的。

讓我知道您是否需要任何幫助,或者是否有問題。

引用自:https://serverfault.com/questions/1056851