最近由于你懂得的不可描述原因, 那个东西就跟疯了一样,到处封 IP,今天(2019年9月21日),我的几台 Azure VM 陆续中奖,不过 Azure 有个好处,就可以免费换 IP,这里记录一下换 IP 的几种方式。

普通方式

以下需要在 Azure portal 中操作,Azure portal 是 Azure 云的网页管理平台。

  1. 虚拟机的管理界面中:停止虚拟机
  2. 虚拟机 - 设置 - 网络 - 分离网络接口
  3. 网络接口 - 设置 - IP 配置 - 删除 IP 地址
  4. 搜索资源 - 公共 IP 地址 - 添加 IP 地址
    注意配置:
  • IP 版本:IPv4
  • SKU:标准
  • 位置:选择你 VM 所在的区域
  1. 上一步创建的 IP 地址 - 概述 - 关联 从 VM 分离的网络接口

2B 方式

同样在 Azure portal 中操作。

前提条件:
VM 的 IP 是动态分配的,默认是 动态,除非你在创建 VM 时/创建后更改为 静态

  1. 虚拟机的管理界面中:停止虚拟机,不要勾选保留IP
  2. 等待虚拟机被停止后,重新启动虚拟机,这时会重新分配一个新的 IP 地址。

这个方式是最简单的,我们可以将这种方式转换为用 Azure CLI 来实现。

进阶方式:使用 Azure CLI 更换 Azure VM IP

Azure CLI 是什么?
Azure CLI 是一个命令行工具,可为 Azure 资源管理提供绝佳体验。 CLI 旨在简化脚本编写、查询数据、支持长时间运行的操作,等等。

(Google Cloud Platform 也有提供类似的功能:CLoud Shell)

  1. 安装

对于 macOS 平台,可以通过 homebrew 包管理器安装 Azure CLI

1
brew update && brew install azure-cli

其他的请参考:https://docs.microsoft.com/zh-cn/cli/azure/install-azure-cli?view=azure-cli-latest

  1. 登陆
1
az login

CLI 会打开默认浏览器浏览器并加载登录页。

还可以用设备码登陆

1
az login --use-device-code

输入后会车,提示如下

1
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code GFJRW66MY to authenticate.

在已经登陆了 Azure 的浏览器上打开https://microsoft.com/devicelogin地址,然后输入验证码GFJRW66MY,即可通过登陆。

使用账号密码登陆(不推荐,因为密码会明文显示出来,如果使用是*nix操作系统,命令会被记录到history文件中,留下安全隐患)

1
az login -u [email protected] -p VerySecret

更多方式可以查看 help

1
az login --help

  1. 使用 Azure CLI

在本文编写时,用于测试的 VM 名为,hk-5,位于名为 hk-5 的资源组中。

在 Azure 中,资源组是一系列资源的集合。

停止分配 VM

1
az vm deallocate -g hk-5 -n hk-5

参数说明:

  • deallocate 停止分配
  • -g,指定资源组
  • -n,指定 VM 的名字

启动 VM

1
az vm start -g hk-5 -n hk-5

查看 VM 的 IP 地址

1
az vm list-ip-addresses -n hk-5 --output table

实际过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
┌─[meoww@Redacted] - [~] - [Sun Sep 22, 01:04]
└─[$] <> az vm list-ip-addresses -n hk-5 --output table
VirtualMachine PublicIPAddresses PrivateIPAddresses
---------------- ------------------- --------------------
hk-5 65.52.176.184 10.0.3.4
┌─[meoww@Redacted] - [~] - [Sun Sep 22, 01:04]
└─[$] <> az vm deallocate -g hk-5 -n hk-5 && az vm start -g hk-5 -n hk-5
┌─[meoww@Redacted] - [~] - [Sun Sep 22, 01:07]
└─[$] <> az vm list-ip-addresses -n hk-5 --output table
VirtualMachine PublicIPAddresses PrivateIPAddresses
---------------- ------------------- --------------------
hk-5 65.52.188.52 10.0.3.4

你可以看到,以这样的方式,换一个 IP 大概需要 2-3 分钟,而且不用等到 VM 停止后再去点击“开启”。

如果你仔细看,在执行az vm deallocate -g hk-5 -n hk-5 && az vm start -g hk-5 -n hk-5时,会显示两次

1
- Running ..

这是两次操作分别执行的状态

其实,Azure CLI 的命令是很方便记忆的。
格式如下:

1
az [要操作的资源类型] [对资源进行的操作] [资源目标] [辅助参数]

第一个,az 是主命令.
第二个,要操作的资源类型,比如 vm , functionapp, mysql.
第三个,对资源进行的操作,比如 create , delete , list.
第四个,要操作的资源目标,可以 -n -g 来指定.
辅助参数,比如 --output table,返回结果以 表格方式 展示.

这里还有个小插曲。

一开始,我被 Portal 上的“停止”按钮误导了,以为这个“停止”对应的 az vm stop,然后尝试了下,重启 VM后,IP 并没有改变,我以为是有个参数对应那个勾选的问题,找了一下,又没有那样的参数,一度以为az是不支持。

后来,突然抓了下 XHR 请求,一般来说,这些大厂的 API Call 都会很规范的。

当我点击“停止”按钮后,有一个 POST 请求,地址如下

1
https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Compute/virtualMachines/<virtual-machine-name>/deallocate?api-version=2019-03-01

原来是 deallocate ,这就是翻译的问题了。

后续

虽然有 az vm list-ip-addresses 可以很方便的得到更换后的 IP 地址,但是如果你有多台设备,难道要到每台设备上去换下 IP 么?

最好的方式,自然是为 VM 的 IP 创建一个 域名记录。

我的域名放在 Cloudflare 进行管理。

将以下脚本放到 VM 上,因为换 IP 必然会涉及到关机再开机,我们可以将此脚本设置为开机运行。

我在 Azure 上常用的是 Ubuntu 18.04 LTS。

Ubuntu 16.04 以上 /etc/rc.local 作为开机自启就失效了,可以参考 Ubuntu18设置开机启动项 进行设置。

运行前,你需要自行替换:

  • domain
  • cloudflare_mail_address
  • cloudflare_api_key

脚本参考:https://gist.github.com/benkulbertis/fff10759c2391b6618dd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env bash

# CHANGE THESE
auth_email="[email protected]"
auth_key="c2547eb745079dac9320b638f5e225cf483cc5cfdda41" # found in cloudflare account settings
zone_name="domain.com"
prefix="az-"
record_name=$prefix$(hostname).$zone_name

# MAYBE CHANGE THESE
ip=$(curl ip.sb)
ip_file="ip.txt"
id_file="cloudflare.ids"
log_file="cloudflare.log"

# LOGGER
log() {
if [ "$1" ]; then
echo -e "[$(date)] - $1" >> $log_file
fi
}

# SCRIPT START
log "Check Initiated"

if [ -f $ip_file ]; then
old_ip=$(cat $ip_file)
if [ $ip == $old_ip ]; then
echo "IP has not changed."
exit 0
fi
fi

if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
zone_identifier=$(head -1 $id_file)
record_identifier=$(tail -1 $id_file)
else
zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*')
echo "$zone_identifier" > $id_file
echo "$record_identifier" >> $id_file
fi

update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"name\":\"$record_name\",\"content\":\"$ip\"}")

if [[ $update == *"\"success\":false"* ]]; then
message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
log "$message"
echo -e "$message"
exit 1
else
message="IP changed to: $ip"
echo "$ip" > $ip_file
log "$message"
echo "$message"
fi

这台 hostname 为 hk-5 的 VM,开机后则会请求 Cloudflare 的 API,创建一条域名记录:

1
az-hk-5.domain.com A 65.52.188.52

这下,你应该也明白了,为什么 VM 的命名是 hk-5 这种形式了吧。

参考:

  1. https://docs.microsoft.com/zh-cn/cli/Azure/vm?view=Azure-cli-latest
  2. https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record