Hyper-VのUbuntu Server22.04で固定プライベートIPを設定して内外部と通信できるようにする

## はじめに
はじめまして！

[ディップ株式会社](https://www.dip-net.co.jp/)にて11月より24新卒内定者インターンとしてインフラエンジニア見習いをしている者です。
こちらは[ディップ株式会社 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/dip-dev)の25日目の記事となります！
メリークリスマス！

本記事では、弊社の業務とは関係のないものですが、私がHyper-VにUbuntu Server 22.04 LTSで仮想マシンを構築する際に得た知見を共有していきたいと思います。

## やりたかったこと
仮想マシン(VM)へデータベースの構築やWordpressのホスティング、Ansible実行等、様々な学習用途で利用したいことが目的でしたが、1点問題が発生しました。

Hyper-VのDefault SwitchはDHCPで仮想マシンへ自動でIPアドレスが振られるのですが、これがくせ者で、頻繁にセグメントやIPアドレスが**勝手に変更されます**。毎回Hyper-VからVMに接続してIPを確認した上でSSH接続しないと、コピペができない。。。

決まったIPアドレスに諸々を繋ぎたかったのですが、ｺﾛｺﾛｺﾛｺﾛIPが変わるため、非常にやりづらく、IPを固定化しようと考えましたが、上記で示した通りの事情と、仮想マシンのUbuntuが比較的新しいバージョンで従来の方法で設定できず、調べてもこの状況にピッタリ合う文献が少なく少し時間を要したので私が行った方法を共有します。

（VirtualBox使えよ！という突っ込みはナシでお願いします！笑 Hyper-Vの軽さには勝てず。。。）

手順として、
**①仮想スイッチの作成**
**②NATの設定**
**③仮想マシンのIPアドレス固定化**
が必要になります。順番に説明します。

## ①仮想スイッチの作成
Hyper-Vの仮想ネットワークは、デフォルトの仮想スイッチ(vSwitch)が標準で有効になっている(無効化、削除は基本的にできません)他に、VirtualBoxやVMWare Workstation Player等と同様に自由に仮想スイッチを作成し、VMをアタッチできます。
そこで、固定セグメントの仮想スイッチを新たに作成します。

Hyper-Vマネージャを開き、**仮想スイッチ マネージャー**を開きます。
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/d75d312e-063a-1353-7496-9df04e0d1bbc.png)

↓

**新しい仮想ネットワーク スイッチ**をクリックし、**内部**ネットワークを選択し、**仮想スイッチの作成**をクリックします。
![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/cbe62fdb-e346-bd5e-6322-51182de34120.png)

↓

左側に作成されたvSwitchが表示されるので、分かりやすい名前に変更し、**適用**をクリックします。
![スクリーンショット (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/6b1bf5ff-85ef-0944-d992-f8711983306a.png)

続いてvSwitchのネットワーク設定とVMのDGWとなるアドレスを設定します。
まず、コントロールパネルを開き、**ネットワークと共有センター**に移動します。
(Windowsが新しくなり、コントロールパネルに馴染みのない方が増えてきていることに驚きを感じつつ、一応開き方も手順として掲載します。)

WindowsキーとRキーを同時に押し、テキストボックスに**Control**と入力しEnterキーを押します。
![スクリーンショット (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/9c6e1126-5067-7af6-1a18-ec2d2231e0b7.png)

↓

表示方法を**小さいアイコン**にし、**ネットワークと共有センター**をクリックします。
![スクリーンショット (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/a50c4837-8b4d-37af-60f8-f65917d7f46f.png)
![スクリーンショット (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/cad5c5a5-7714-4623-6195-1b7772ba2248.png)

↓

左上周辺の**アダプター設定の変更**をクリックします。
![スクリーンショット (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/060a3b0d-28b9-b614-7390-c15b0fccfd4a.png)

↓
vEthernet(設定したvSwitch)のvNICをダブルクリックします。
![スクリーンショット (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/6ee33356-cd02-ec7a-33fc-15e6ecbf0567.png)

↓

下の画像を右から**プロパティ**→**インターネット プロトコル バージョン4**→**プロパティ**→**次の IP アドレスを使う**の順にクリックし、IPアドレスとサブネットマスクの欄にそれぞれ適切な値を入力します。ここで入力したIPアドレスがこの後IPアドレスを固定設定するVMのDGWとなる点に留意してください。

:::note info
ネットワークアドレスは自由ですが、Default SwitchがクラスBプライベートアドレス(`172.16.0.0/12`)の一部をセグメントとして設定されるため、クラスA(`10.0.0.0/8`)かクラスC(`192.168.0.0/16`)のサブネットで作成することをおすすめします。私は他のサービスとの干渉が少なそうな`192.168.100.0/24`を設定しました。
:::
![スクリーンショット (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/d180db32-ce13-03d5-ac10-c24c2e146862.png)

以上がvSwitch作成の手順です。

## ②NATの設定
上記で作成したvSwitchは内部ネットワークです。
利用する仕組みとしては、物理NICや物理ネットワークとは繋がっていないvSwitchを作成し、そこにVM(Ubuntu)とホストPC(Windows)のvNICを接続している状態になります。
つまり、この状態だとホストPCとVM同士の通信は可能なのですが、vSwitchが物理ネットワークと接続されていないため外部(インターネット)と通信することができません。
そこで、NATでアドレスを変換し、外部と通信できるように設定する必要があります。

まず、管理者権限でWindows Powershellを起動します。
（スタートメニュー→Windows ツール→Windows Powershellを右クリック→管理者として実行で起動できます）

↓

以下のコマンドを入力します。
```:PowerShell
New-NetNat -Name "vNetToExt" -InternalIPInterfaceAddressPrefix 192.168.100.0/24
```
:::note info
名前は自由です。ネットワークアドレスは仮想ネットワークと同じものにしてください。
:::

実行すればNATの設定は完了です。

誤ったアドレスを設定してしまったり、仮想環境を畳むなどの場合で設定を削除したい場合は以下のコマンドを入力してください。
```:PowerShell
Remove-NetNat -Name "vNetToExt"
```

## ③仮想マシンのIPアドレス固定化
最後に、VMのIPアドレスを固定設定(DHCPを使わずに任意のアドレスを設定する)します。

Hyper-V マネージャーを起動し、VMを起動せずに仮想マシン欄にある設定したいVMを右クリックし、設定を開きます。

↓

**ネットワーク アダプター**をクリックし、仮想スイッチの選択リストを設定したvSwitchに変更し、**適用**をクリックします。
![スクリーンショット (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3013039/00072f1c-eb3a-ded8-1151-825a91adc949.png)

↓

設定を閉じ、VMを起動・接続します。

:::note info
(少し時間がかかります。途中でブートプロセスが止まっているように見えますが、異常ではなく、DHCPサーバが存在していない仮想ネットワークでDHCP discoveryのブロードキャストを行ってしまっている状態なので、タイムアウトし画面が進むまで気長に待ちましょう。)
:::
:::note warn
この時点ではVMにDHCPが設定されているため、IPアドレスが割り当てられず、SSH接続ができません。以降完了するまでのコマンド入力はHyper-Vからマシンを直接接続して編集してください。
:::

↓

`/etc/netplan`ディレクトリへ移動します。
```bash:bash
cd /etc/netplan
```
↓

`ls -l`などでディレクトリ内のファイルを確認し、.yaml拡張子のファイルを確認します。
(Hyper-VでUbuntu Server 22.04 LTSをisoからインストーラを利用しインストールした場合、`00-installer-config.yaml`という名前で存在しているはずです。)

↓

このファイルをバックアップとして変更します。
```bash:bash
sudo mv 00-installer-config.yaml 00-installer-config.yaml.bak
```
:::note info
Ubuntuの現在のネットワークマネージャは.yamlファイルを認識して設定を実行するので、バックアップとして変更するファイルの拡張子は.yaml以外にしてください。
:::

↓

新規ファイル名でvim等で編集します。ファイル名は拡張子が.yamlであれば自由です。
```bash:bash
sudo vim 01-staticip-config.yaml
```

↓

以下ものを、アドレス、NIC名(`ip a`で確認可能)等を設定したものに適宜変更し記述してください。

```yaml:01-staticip-config.yaml
network:
   version: 2
   renderer: networkd
   ethernets:
      eth0:
         addresses: [192.168.100.1/24]
         nameservers:
            addresses: [1.1.1.1 , 1.0.0.1]
         routes:
            - to: default
              via: 192.168.100.254
```

:::note info
eth0の部分はVMのvNIC名です。
eth0:addressesはVMに設定したいアドレスを入力してください。
eth0:nameservers:addressesはDNSサーバのアドレスを入力してください。例にはCloudflareのパブリックDNSを設定しています。
routes:viaのアドレスはDGWとして設定したホストPCのvNICのアドレスです。
:::

↓

入力後、**Escキー**→ **:wq**→**Enterキー**で保存します。

↓

設定を反映させます。以下のコマンドを実行してください。
```bash:bash
sudo netplan apply
```

これで設定完了です。`ip a`コマンドでIPアドレスが変更されていることを確認してください。
ついでに`ping google.com`等で外部疎通の確認も済ませておくと良いと思います。
例：↓(以下のものと同じであれば成功しています。)
```bash:bash
user@ubuntu:/etc/netplan$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:01:20:0c brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.1/24 brd 192.168.100.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::215:5dff:fe01:200c/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:d4:dd:c8:ae brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
user@ubuntu:/etc/netplan$ ping google.com
PING google.com (142.251.42.206) 56(84) bytes of data.
64 bytes from nrt12s47-in-f14.1e100.net (142.251.42.206): icmp_seq=1 ttl=107 time=36.0 ms
64 bytes from nrt12s47-in-f14.1e100.net (142.251.42.206): icmp_seq=2 ttl=107 time=20.8 ms
64 bytes from nrt12s47-in-f14.1e100.net (142.251.42.206): icmp_seq=3 ttl=107 time=21.1 ms
64 bytes from nrt12s47-in-f14.1e100.net (142.251.42.206): icmp_seq=4 ttl=107 time=24.2 ms
^C
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3006ms
rtt min/avg/max/mdev = 20.829/25.536/36.024/6.198 ms
user@ubuntu:/etc/netplan$ 
```

## さいごに
説明が長くなってしまい申し訳ありませんが、以下が手順です。

あまりホストPCの環境への影響も抑えつつ対応したかったので、このように行いましたが、かなり扱いやすくなりました。

色々説明したので簡潔で分かりやすく無くなってしまいましたが、最後までお読みいただきありがとうございました！