１ つの Azure プライベート DNS ゾーンを 2 つの VNET から使う構成を Azure CLI で作ってみた

## 背景と目的

VNET 間で相互通信する場合、VNET ピアリングを設定すれば、相互に IP アドレスで通信を行う事ができます。IP アドレスは台数が少ないうちは覚えられるので問題になりませんが、台数が増えてくると覚えられなくなり、凡ミスを誘発しやすくなります。また、IP アドレスのまま運用していると、例えば仮想マシンに不具合が生じて新しい仮想マシンを用意して入れ替えたい場合、その仮想マシンに通信している通信元の台数分の設定変更が必要ですが、名前解決なら TTL を短くしておき A レコードを書き換えるだけで済みます。そこで、ミスを減らしたりメンテナンスを楽にするため、名前解決できるようにして人間でも覚えやすい命名規則で運用します。VNET とオンプレがつながっているならオンプレ側に DNS があり、それを利用するのも可能ですが、オススメはオンプレとのネットワークが切れてしまっても影響されないよう、Azure 側に プライベート DNS ゾーンを用意する方法です。ということで今回は、下記構成図のような １ つの Azure プライベート DNS ゾーンを 2 つの VNET から使う構成を Azure CLI で作ってみました。

![pdns-2vnet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/ee0a0770-20c0-b68f-d080-a9663c02b80e.png)

## 検証用 VNET を作成

```bash:bash
# 環境変数をセットします
region=japaneast
prefix=mnrpdns

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# VNET を 2 つ作成します
for i in {1..2}; do
  az network vnet create \
    --name ${prefix}-vnet${i} \
    --resource-group ${prefix}-rg \
    --address-prefix 172.16.${i}.0/24
done

# NSG を 2 つ作成します
for i in {1..2}; do
  az network nsg create \
    --resource-group ${prefix}-rg \
    --name ${prefix}-nsg${i}
done

# それぞれの VNET にサブネットを作成します
for i in {1..2}; do
  az network vnet subnet create \
    --vnet-name ${prefix}-vnet${i} \
    --resource-group ${prefix}-rg \
    --name vm-subnet \
    --address-prefix 172.16.${i}.0/28 \
    --network-security-group ${prefix}-nsg${i}
done
```

## VNET ピアリングを作成

```bash:bash
# vnet1 から vnet2 へのピアリングを作成します
az network vnet peering create \
  --name vnet1-vnet2 \
  --resource-group ${prefix}-rg \
  --vnet-name ${prefix}-vnet1 \
  --remote-vnet ${prefix}-vnet2 \
  --allow-vnet-access

# vnet2 から vnet1 へのピアリングを作成します
az network vnet peering create \
  --name vnet2-vnet1 \
  --resource-group ${prefix}-rg \
  --vnet-name ${prefix}-vnet2 \
  --remote-vnet ${prefix}-vnet1 \
  --allow-vnet-access
```

## プライベート DNS ゾーンを作成

```bash:bash
# 1 つのプライベート DNS ゾーンを作成します
az network private-dns zone create \
  --resource-group ${prefix}-rg \
  --name ${prefix}.local

# それぞれの VNET とプライベート DNS ゾーンを紐づけます
for i in {1..2}; do
  az network private-dns link vnet create \
    --resource-group ${prefix}-rg \
    --name ${prefix}-pdns${i} \
    --zone-name ${prefix}.local \
    --virtual-network ${prefix}-vnet${i} \
    --registration-enabled true
done
```

## 仮想マシンを作成

```bash:bash
# それぞれの VNET にパブリック IP アドレスなしの仮想マシンを作成します
for i in {1..2}; do
  az vm create \
    --resource-group ${prefix}-rg \
    --name ${prefix}-vm${i} \
    --os-disk-name ${prefix}-vm${i}OSDisk \
    --image CentOS \
    --size Standard_B1s \
    --admin-username azureuser \
    --generate-ssh-keys \
    --vnet-name ${prefix}-vnet${i} \
    --subnet vm-subnet \
    --nsg "" \
    --public-ip-address "" \
    --storage-sku Standard_LRS
done
```

## プライベート DNS ゾーンに登録された情報を確認

```bash:bash
# DNS レコードのリストを表示します
az network private-dns record-set list \
  --resource-group ${prefix}-rg \
  --zone-name ${prefix}.local \
  --output table

# 表示結果を見ると 2 つの仮想マシンの A レコードが自動登録されていることが確認できます
Name         ResourceGroup    Ttl    Type    AutoRegistered    Metadata
-----------  ---------------  -----  ------  ----------------  ----------
@            mnrpdns-rg       3600   SOA     False
mnrpdns-vm1  mnrpdns-rg       10     A       True
mnrpdns-vm2  mnrpdns-rg       10     A       True
```

## それぞれの仮想マシンから名前解決と相互通信を確認

```bash:bash
# 名前解決を確認します
for i in {1..2}; do
  az vm run-command invoke \
    --resource-group ${prefix}-rg \
    --name ${prefix}-vm${i} \
    --command-id RunShellScript \
    --scripts "host ${prefix}-vm1.${prefix}.local; host ${prefix}-vm2.${prefix}.local" \
    --query value[].message \
    --output tsv
done

# vm1 側の出力結果
Enable succeeded: 
[stdout]
mnrpdns-vm1.mnrpdns.local has address 172.16.1.4
mnrpdns-vm2.mnrpdns.local has address 172.16.2.4

[stderr]

# vm2 側の出力結果
Enable succeeded: 
[stdout]
mnrpdns-vm1.mnrpdns.local has address 172.16.1.4
mnrpdns-vm2.mnrpdns.local has address 172.16.2.4

[stderr]

# 相互通信を確認します
for i in {1..2}; do
  az vm run-command invoke \
    --resource-group ${prefix}-rg \
    --name ${prefix}-vm${i} \
    --command-id RunShellScript \
    --scripts "ping -c 4 ${prefix}-vm1.${prefix}.local; ping -c 4 ${prefix}-vm2.${prefix}.local" \
    --query value[].message \
    --output tsv
done

# vm1 側の出力結果
Enable succeeded: 
[stdout]
PING mnrpdns-vm1.mnrpdns.local (172.16.1.4) 56(84) bytes of data.
64 bytes from mnrpdns-vm1.internal.cloudapp.net (172.16.1.4): icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from mnrpdns-vm1.internal.cloudapp.net (172.16.1.4): icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from mnrpdns-vm1.internal.cloudapp.net (172.16.1.4): icmp_seq=3 ttl=64 time=0.042 ms
64 bytes from mnrpdns-vm1.internal.cloudapp.net (172.16.1.4): icmp_seq=4 ttl=64 time=0.048 ms

--- mnrpdns-vm1.mnrpdns.local ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.020/0.039/0.049/0.014 ms
PING mnrpdns-vm2.mnrpdns.local (172.16.2.4) 56(84) bytes of data.
64 bytes from 172.16.2.4 (172.16.2.4): icmp_seq=1 ttl=64 time=3.68 ms
64 bytes from 172.16.2.4 (172.16.2.4): icmp_seq=2 ttl=64 time=1.11 ms
64 bytes from 172.16.2.4 (172.16.2.4): icmp_seq=3 ttl=64 time=1.14 ms
64 bytes from 172.16.2.4 (172.16.2.4): icmp_seq=4 ttl=64 time=1.37 ms

--- mnrpdns-vm2.mnrpdns.local ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.112/1.829/3.682/1.075 ms

[stderr]

# vm2 側の出力結果
Enable succeeded: 
[stdout]
PING mnrpdns-vm1.mnrpdns.local (172.16.1.4) 56(84) bytes of data.
64 bytes from 172.16.1.4 (172.16.1.4): icmp_seq=1 ttl=64 time=0.951 ms
64 bytes from 172.16.1.4 (172.16.1.4): icmp_seq=2 ttl=64 time=4.15 ms
64 bytes from 172.16.1.4 (172.16.1.4): icmp_seq=3 ttl=64 time=1.28 ms
64 bytes from 172.16.1.4 (172.16.1.4): icmp_seq=4 ttl=64 time=1.51 ms

--- mnrpdns-vm1.mnrpdns.local ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 0.951/1.975/4.159/1.277 ms
PING mnrpdns-vm2.mnrpdns.local (172.16.2.4) 56(84) bytes of data.
64 bytes from mnrpdns-vm2.internal.cloudapp.net (172.16.2.4): icmp_seq=1 ttl=64 time=0.024 ms
64 bytes from mnrpdns-vm2.internal.cloudapp.net (172.16.2.4): icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from mnrpdns-vm2.internal.cloudapp.net (172.16.2.4): icmp_seq=3 ttl=64 time=0.054 ms
64 bytes from mnrpdns-vm2.internal.cloudapp.net (172.16.2.4): icmp_seq=4 ttl=64 time=0.056 ms

--- mnrpdns-vm2.mnrpdns.local ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.024/0.049/0.063/0.015 ms

[stderr]
```

## 検証環境を削除

```bash:bash
# リソースグループを削除します
az group delete \
  --name ${prefix}-rg \
  --yes
```

## 参考

https://learn.microsoft.com/ja-jp/azure/dns/private-dns-scenarios#scenario-name-resolution-across-virtual-networks