如何使用实例的临时 IP 更新 Google Cloud DNS

How to update Google Cloud DNS with ephemeral IP for an instance

我在 GCE 上有几个实例,我真的不需要静态地址,但我仍然需要通过 dns 名称访问它们。由于每次重新启动实例时临时外部 IP 地址都会更改,我想我可以使用某种启动脚本来更新 Google Cloud DNS(有点像 dyndns)中该实例的 dns 条目。

我是不是错过了什么,还有更简单的方法可以通过 gcloud 将临时外部 ip 地址映射到 dns 记录?

如果没有,将不胜感激有关如何编写此类脚本的任何指示!

以下假设您在与您的项目相同的项目中使用区域名称 "foo-bar-com" 的 Google Cloud DNS for foo.bar.com(即 dns 名称 "foo.bar.com.") VM,并且您的 VM 选择了配置选项 "This instance has full API access to all Google Cloud services."。 您的虚拟机将在 DNS 中被称为 "my-vm.foo.bar.com"。

我确信这可以适当修改以在不同的项目中使用 DNS and/or 更有限的权限。

可能值得注意:这假设您使用的是 'Google Cloud DNS' 而不是(只是) 'Google Domains' 注册商,如果您使用的是后者(托管您的 DNS,而不仅仅是注册商) ) 然后他们直接支持合成动态 ip 地址和一些像更新机制一样的 dyndns(但他们在许多其他方面受到更多限制)。

另请注意,要使交易成功,必须已经有一条具有正确 IP 和正确 TTL 的记录(即,您第一次 运行 可能需要通过以下方式手动删除任何条目UI 和 运行 这段代码 dns_del 被注释掉了)。

#!/bin/bash

ttlify() {
  local i
  for i in "$@"; do
    [[ "${i}" =~ ^([0-9]+)([a-z]*)$ ]] || continue
    local num="${BASH_REMATCH[1]}"
    local unit="${BASH_REMATCH[2]}"
    case "${unit}" in
                     weeks|week|wee|we|w) unit=''; num=$[num*60*60*24*7];;
                           days|day|da|d) unit=''; num=$[num*60*60*24];;
                     hours|hour|hou|ho|h) unit=''; num=$[num*60*60];;
      minutes|minute|minut|minu|min|mi|m) unit=''; num=$[num*60];;
      seconds|second|secon|seco|sec|se|s) unit=''; num=$[num];;
    esac
    echo "${num}${unit}"
  done
}

dns_start() {
  gcloud dns record-sets transaction start    -z "${ZONENAME}"
}

dns_info() {
  gcloud dns record-sets transaction describe -z "${ZONENAME}"
}

dns_abort() {
  gcloud dns record-sets transaction abort    -z "${ZONENAME}"
}

dns_commit() {
  gcloud dns record-sets transaction execute  -z "${ZONENAME}"
}

dns_add() {
  if [[ -n "" && "" != '@' ]]; then
    local -r name=".${ZONE}."
  else
    local -r name="${ZONE}."
  fi
  local -r ttl="$(ttlify "")"
  local -r type=""
  shift 3
  gcloud dns record-sets transaction add      -z "${ZONENAME}" --name "${name}" --ttl "${ttl}" --type "${type}" "$@"
}

dns_del() {
  if [[ -n "" && "" != '@' ]]; then
    local -r name=".${ZONE}."
  else
    local -r name="${ZONE}."
  fi
  local -r ttl="$(ttlify "")"
  local -r type=""
  shift 3
  gcloud dns record-sets transaction remove   -z "${ZONENAME}" --name "${name}" --ttl "${ttl}" --type "${type}" "$@"
}

lookup_dns_ip() {
  host "" | sed -rn 's@^.* has address @@p'
}

my_ip() {
  ip -4 addr show dev eth0 | sed -rn 's@^    inet ([0-9.]+).*@@p'
}

doit() {
  ZONE=foo.bar.com
  ZONENAME=foo-bar-com
  dns_start
  dns_del my-vm 5min A `lookup_dns_ip "my-vm.${ZONE}."`
  dns_add my-vm 5min A `my_ip`
  dns_commit
}

你 post 回答这个问题已经有一段时间了,但我会 post 在这里回答以供将来参考。

我有类似的需求,但我不想使用 gcloud CLI。

我创建了一个简单的 python 脚本,其功能与上面的 bash 脚本几乎相同,但使用 Apache LibcloudGoogle Cloud API 凭据(服务帐户和密钥)。

您可以在 GitHub 中找到代码。

我将对@MaZe 的回答稍加改动。此外,我将展示如何使用 systemd,因此如果您使用 Ubuntu 或其他使用 systemd 的发行版,此脚本会在启动时自动启动。

#!/bin/bash

EXISTING=`gcloud dns record-sets list --zone="{your domain}" | grep xxx.yyyy.com | awk '{print }'`
NEW=`gcloud compute instances describe {your instance} --zone={your zone} | grep natIP | awk -F': ' '{print }'`
gcloud dns record-sets transaction start -z={your domain}
gcloud dns record-sets transaction remove -z={your domain} \
    --name="xxx.yyyy.com." \
    --type=A \
    --ttl=300 "$EXISTING"
gcloud dns record-sets transaction add -z={your domain} \
   --name="xxx.yyyy.com." \
   --type=A \
   --ttl=300 "$NEW"
gcloud dns record-sets transaction execute -z={your domain}

将其保存到/path/to/script.sh 并在systemd 中启动它:

[Unit]
Description=Set xxx.yyyy.com to the correct external ip address of this instance
After=network.target auditd.service

[Service]
ExecStart=/path/to/script.sh
Type=oneshot

[Install]
WantedBy=multi-user.target

在 /etc/systemd/system 中将其保存为 filename.service 并启用它:

sudo systemctl enable filename.service