13

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

我是否错过了什么,并且有一种更简单的方法可以通过 gcloud 将临时外部 IP 地址映射到 dns 记录?

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

4

3 回答 3

7

以下假设您在与您的 VM 相同的项目中使用 Google Cloud DNS for foo.bar.com(即 dns 名称“foo.bar.com.”),区域名称为“foo-bar-com”,并且您的VM 具有配置选项“此实例具有对所有 Google Cloud 服务的完全 API 访问权限。” 选择。您的 VM 在 DNS 中将被称为“my-vm.foo.bar.com”。

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

可能值得注意:这假设您使用的是“Google Cloud DNS”而不是(仅)“Google Domains”注册商,如果您使用后者(托管您的 DNS,而不仅仅是作为注册商),那么他们有直接支持对于具有一些动态的合成动态 IP 地址,例如更新机制(但它们在许多其他方面受到更多限制)。

另请注意,要使交易成功,必须有一条具有正确 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 "$1" && "$1" != '@' ]]; then
    local -r name="$1.${ZONE}."
  else
    local -r name="${ZONE}."
  fi
  local -r ttl="$(ttlify "$2")"
  local -r type="$3"
  shift 3
  gcloud dns record-sets transaction add      -z "${ZONENAME}" --name "${name}" --ttl "${ttl}" --type "${type}" "$@"
}

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

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

my_ip() {
  ip -4 addr show dev eth0 | sed -rn 's@^    inet ([0-9.]+).*@\1@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
}
于 2016-01-14T15:16:57.900 回答
6

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

#!/bin/bash

EXISTING=`gcloud dns record-sets list --zone="{your domain}" | grep xxx.yyyy.com | awk '{print $4}'`
NEW=`gcloud compute instances describe {your instance} --zone={your zone} | grep natIP | awk -F': ' '{print $2}'`
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
于 2018-07-17T14:02:38.843 回答
3

自从您发布此问题以来已经有一段时间了,但我会在此处发布我的答案以供将来参考。

我有类似的需求,我不想使用gcloudCLI。

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

您可以在GitHub中找到代码。

于 2017-04-15T07:47:00.667 回答