Win10(バージョン1909) の Hyper-V で CentOS7 をゲストOSインストールする例

2020-05時点の Windows 10 (1909) の Hyper-V で、以下の要件を満たすように CentOS7 をゲストOSインストールする方法を調査した。

- ホストとゲスト間でネットワーク通信ができること。
- ゲストからインターネットに接続できること。
- port forward などで外部NWからゲストにネットワーク接続できること。(自宅内/社内NW限定のWebサービス公開など)
- ゲストのディスプレイサイズを変更できること。(CentOS7のGNOME前提)
- ホストとゲスト間でクリップボードを共有できること。

調査環境：

- ホスト環境CPU : Intel Core i7 / メモリ : 16GB
- ホストOS: Windows 10 Pro 64bit 日本語版, バージョン1909, ビルド 18363.836
- ゲストOS: CentOS-7-x86_64-DVD-2003.iso


Windows 10 における Hyper-V 公式ドキュメント:

- `Windows 10 の Hyper-V | Microsoft Docs`
  - https://docs.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/

## 三行まとめ

1. ネットワーク関連の要件を満たすため、Hyper-Vの内部仮想スイッチを作成 + PowerShellでNATを設定する。
1. CentOS7はGUIインストールでOK
1. ディスプレイサイズの変更とクリップボード共有には xrdp をインストールしてリモートデスクトップ接続をする。(Hyper-V の拡張セッションまでは使わない)

## 内部仮想スイッチとNAT設定

今回のネットワーク関連の要件を満たすためには、Hyper-Vの内部仮想スイッチを作成した上でNATを設定する。

1. Hyper-V マネージャーから仮想スイッチマネージャを開き、内部仮想スイッチを作成する。
1. 内部仮想スイッチに接続されたホスト側の仮想NIC(ア)に対し、NATのデフォルトゲートウェイとしてIPアドレスを設定する。
   1. PowerShellを管理者権限で起動し、`Get-NetAdapter` で(ア) の `ifIndex` (イ) をメモしておく。
   1. `New-NetIPAddress -IPAddress <NAT Gateway IP> -PrefixLength <NAT Subnet Prefix Length> -InterfaceIndex <ifIndex:(イ)>` でゲートウェイとしてのIPアドレス (ウ) とサブネットマスク (エ)を設定する。
   1. `New-NetNat -Name <NAT Name> -InternalIPInterfaceAddressPrefix <NAT subnet prefix>` で (エ) のサブネット用のNATを作成する。
1. ゲストOSインストール時に、(エ) に属するような適当なIPアドレス (オ) を静的IPアドレスとして手動設定する。

これにより本記事で目指す以下の要件が満たされる。

- ホストとゲスト間でネットワーク通信ができること。
  - Hyper-V の内部仮想スイッチの特性による。
- ゲストからインターネットに接続できること。
  - NAT設定による。

ゲスト側でネットワークサービスを起動した場合、管理者権限で起動したPowerShellから以下のコマンドで port forward 設定を行う。

```
Add-NetNatStaticMapping -NatName <NAT Name> -Protocol TCP -ExternalIPAddress 0.0.0.0 -InternalIPAddress <Forward dest IP:(オ)> -ExternalPort <Forward src port> -InternalPort <Forward dest port>
```

これにより以下の要件が満たされる。

- port forward などで外部NWからゲストにネットワーク接続できること。(自宅内/社内NW限定のWebサービス公開など)

上記で紹介したコマンドの実行例、およびHyper-Vの仮想スイッチの全体像については、以下資料を参照のこと。

- Hyper-V仮想スイッチの種類と特徴,使い方の調査(2020-05)
  - https://docs.google.com/presentation/d/1hToOClc5_uN17FGZbiCdX92qKXGVq-7V89RxpSVfn7E/edit?usp=sharing
  - 「6. ユースケース実現のためのおすすめ方法」から今回のユースケースについての解説とコマンド実行例を紹介している。

ちなみに、以下の順番で設定しても問題ない。(実際、本記事の調査ではその順番で検証している)

1. ゲストOSインストール時は「デフォルトの内部仮想スイッチ」を使う。
   - デフォルトの内部仮想スイッチにはDHCPとNATが組み込まれているので手軽に外部NWにoutbound通信ができて便利。
   - ただしDHCPのIPレンジやNAT port forward などの各種設定変更ができないため、今回の要件には不向き。
1. インストール完了後に上記手順に従い内部仮想スイッチ作成 + NAT設定し、そちらに切り替え + IPアドレス手動設定。

## CentOS7のGUIインストール

すでに沢山の方が Hyper-V のゲストOSとしてCentOS7をGUIインストールする記事を書かれているので、そちらを参照すればOK.

ネットワーク設定については個々人の環境によって何がベストか変わってくるため、要件に応じて適切な方式を選択する必要がある。前掲の[「Hyper-V仮想スイッチの種類と特徴,使い方の調査(2020-05)」](https://docs.google.com/presentation/d/1hToOClc5_uN17FGZbiCdX92qKXGVq-7V89RxpSVfn7E/edit?usp=sharing) を参照のこと。

事前に一読して予習しておくのにオススメな参考記事:

- `CentOSをHyper-V上に入れるときのポイント（第一世代 vs 第二世代) - Qiita`
  - https://qiita.com/___monta___/items/7c180e56282e3f1c87d0
  - Hyper-Vで仮想マシンを作るときの「第一世代」「第二世代」の違いについて簡潔に紹介されている。
- `Hyper-VにCentOS7をインストール - Qiita`
  - https://qiita.com/gate9/items/6a179f4ef5c2fcee2ae5
  - GUIインストールの一通りの手順がスクリーンショット画像を元に丁寧に紹介されている。
- `Windows10 Pro Hyper-VにCentOS7をインストールする | 楽しいブログ`
  - https://cs.machijun.net/install-centos7-on-hyperv-on-windows10-pro.html
  - こちらもGUIインストールの一通りの手順がスクリーンショット画像を元に丁寧に紹介されている。

Ubuntuをインストールしてみたい方向け:

- `Windows 10のHyper-VでLinuxの仮想マシンを作成する：Tech TIPS - ＠IT`
  - https://www.atmarkit.co.jp/ait/articles/1807/05/news028.html
  - 「Hyper-V クイック作成」からのUbuntuマシン構築の紹介。(今回は未調査・未検証)
- `Windows10 ProでHyper-Vを使ってみた - Qiita`
  - https://qiita.com/hideki0145/items/844f003b6f6647cab081
  - Ubuntu のインストール手順の解説と、拡張セッションへの対応方法の紹介。

## xrdpを使ったリモートデスクトップ接続

今回の環境でCentOS7をインストールすると、ディスプレイ解像度が 1152 x 864 となってしまい、変更できなかった。
またホスト側とのクリップボードも共有されず、ファイルのやり取りもscpなどを介する必要がある。

Linuxゲスト側にxrdpをインストールすると、ホストのWindows10からリモートデスクトップ接続が可能になる。
これにより本記事で目指す以下の要件が満たされる。

- ゲストのディスプレイサイズを変更できること。(CentOS7のGNOME前提)
  - リモートデスクトップ接続開始時にディスプレイ解像度を変更可能。
- ホストとゲスト間でクリップボードを共有できること。
  - リモートデスクトップ接続のデフォルト設定でクリップボード共有が有効になっている。

今回の調査では以下の手順でxrdpをインストールした。

```
(EPELからのxrdpインストール)
$ sudo yum install -y epel-release
$ sudo yum install xrdp

(xrdpサービス起動)
$ sudo systemctl start xrdp.service

(ゲストOS:CentOS7起動時にxrdp自動実行を有効化)
$ sudo systemctl enable xrdp.service

(ファイアウォールでxrdpポート番号への接続を許可)
$ sudo firewall-cmd --permanent --add-port=3389/tcp
$ sudo firewall-cmd --reload
```

リモートデスクトップ接続の手順：

1. Windows + R →「ファイル名を指定して実行」で `mstsc` と入力して Enter → リモートデスクトップ接続を開く。
1. 「オプションの表示」をクリックし、コンピュータ名にゲストOSに手動設定したIPアドレスを入力、ユーザ名にログインユーザ名を入力して「接続」
   - この時「画面」タブ→「画面の設定」でディスプレイサイズをカスタマイズできる。
   - 証明書エラーなどで警告が表示されても、警告を無視してそのまま接続。
1. xrdp のログイン画面が表示される。
   - 今回の検証環境では、"Session" -> "Xvnc" が選択済み, "username" -> 上記で入力したユーザ名が入力済みとなっていたので、そのまま "password" でログインパスワードを入力。
   - しばらく待つと、GNOMEデスクトップが表示された。
1. リモートデスクトップ接続を終了するには、ログイン中のGNOMEデスクトップセッションからログアウトすればOK.

以上でWin10ホストからCentOS7ゲストにリモートデスクトップ接続に成功し、クリップボードの共有も確認できた。

なおリモートデスクトップ接続先の画面において Alt + Tab などのキーボードショートカットを使うには、以下の記事にあるように専用のショートカットキーを使う。

- `【リモートワーク自由自在】リモートデスクトップの便利なショートカットキー（Windows編）：Tech TIPS - ＠IT`
  - https://www.atmarkit.co.jp/ait/articles/0508/27/news022.html
  - この記事ではリモートデスクトップ接続先に Windows を想定しているようだが、いくつかのショートカットキーについては CentOS7(GNOME) でも有効に動作した。


以下参考資料:

- `WindowsのリモートデスクトップでCentOS 7に接続してみた | GMOクラウドアカデミー`
  - https://academy.gmocloud.com/know/20190704/6705
  - この記事では `/etc/yum.repos.d/epel.repo` の enabled を 0 に手動で変更している。おそらく環境特有か？EPELをそのまま使い続けるのであればデフォルトの1のままで問題ないし、その後に続く xrdp のインストールでも `--enablerepo=epel` オプションは不要。

その他参考 : xrdp の他に tigervnc-server を一緒にインストールする記事が見つかったが、今回の検証では不要だった。また `/etc/xrdp/xrdp.ini` で `max_bpp` を 24 に変更する解説もあったが、これも今回の検証では不要で、デフォルトの 32 のまま正常に動作した。

- `CentOS7にWindowsリモートデスクトップ接続する方法 - Qiita`
  - https://qiita.com/SkyLaptor/items/56c9b5f5784f19cac225
- `CentOS7 windowsからRDP(リモートデスクトップ)で接続する。 | itcore 2017年`
  - https://www.itcore.jp/tips/xrdp.php
- `CentOS7にxrdpを導入しWindowsからリモートデスクトップで接続 - Qiita`
  - https://qiita.com/shinoere/items/35793d9c6155145cb37c
  - こちらでは日本語キーボードのカスタム設定についても解説があったが、今回はデフォルト設定のまま日本語キーボードが認識されたため、不要だった。

## LinuxゲストVMにおける拡張セッション

本記事が目指す要件ではクリップボードの共有までとし、ホスト/ゲスト間のファイル共有についてはスコープ外とした(ネットワーク接続があれば、scpなどでファイルをやり取りできるため)。もしこれを要件に含めるのであれば、Hyper-V およびHyper-Vの仮想マシンで拡張セッションを有効にする。

Windows 10 ではバージョン 1803 からLinux仮想マシンの拡張セッションモードサポートが始まった。

- `Windows 10の最新「クライアントHyper-V」の新機能 (2/2)：企業ユーザーに贈るWindows 10への乗り換え案内（31） - ＠IT`
  - https://www.atmarkit.co.jp/ait/articles/1808/30/news024_2.html
- `Windows Windows 10でHyper-V拡張セッションモードを無効/有効にする方法`
  - https://soundartifacts.com/ja/how-to/287-how-to-disable-enable-hyper-v-enhanced-session-mode-in-windows-10.html
- `Use local resources on Hyper-V virtual machine with VMConnect | Microsoft Docs`
  - https://docs.microsoft.com/ja-jp/windows-server/virtualization/hyper-v/learn-more/Use-local-resources-on-Hyper-V-virtual-machine-with-VMConnect

Hyper-V専用のsocket機構 (hv_sock) が提供されているらしく、hv_sock に対応したxrdpを経由することでファイル共有が可能になるらしい。このため linux カーネル側で hv_sock をサポートしている+それを有効にした上で、xrdpについてもhv_sock対応版にする。

xrdpについてだが、少しググった限りではデフォルトでは未対応となっており、対応させるにはビルド時の設定をカスタマイズする必要があるらしい。つまりソースコードをダウンロードしてきて、ゲスト環境でビルドすることになる。

今回はスコープ外としたため、以下、参考資料として見つけたURLを紹介するに留める。

ubuntu(18.04以降?) と arch だと 、xrdpのビルドを簡略可するためのスクリプトがMSから提供されている。

- `Hyper-V Linux で拡張セッションを使う方法 | SEECK.JP サポート`
  - https://kb.seeck.jp/archives/12477
  - https://github.com/Microsoft/linux-vm-tools/
- `Hyper-V Linux で拡張セッションを使う方法 | SEECK.JP サポート`
  - https://kb.seeck.jp/archives/12477

CentOS7 だと xrdp/xorgxrdp をソースコードからビルドする必要があるらしい。(ビルド時の設定が必要)

- `【Hyper-V】ホストOSからCentOS7のデスクトップにファイルをコピペする方法(クリップボード共有) | オプティマル・システムデザイン・ワークス`
  - https://optimal-sdw.com/blog/code-virtual-technology/article_94

Fedora28の例。こちらは xrdp だけで、xorgxrdp は使ってない。

- `Enhanced Session Mode under Fedora 28 – Secana Blog`
  - https://secanablog.wordpress.com/2018/10/24/enhanced-session-mode-under-fedora-28/

## VirtualBox Guest Additions との比較

VirtualBox の場合、VirtualBox Guest Addition をゲストOSにインストールすることでディスプレイサイズの変更とクリップボードの共有、ホストとのファイル共有が可能になる。

比べてみた感想:

- VirtualBox の方が、仮想マシンのウインドウサイズに応じて起動後もリアルタイムにディスプレイサイズ変更をしてくれるので使いやすい。
- クリップボード共有についてはどちらもサポートしてるので違和感無し。
- VirtualBoxであればデスクトップ用のショートカットキーがそのまま動くので楽。
  - Hyper-Vへのリモートデスクトップ接続だと、専用のショートカットキーに都度意識して読み替えないといけない。
- ファイル共有については正直なところ VirtualBox 時代から scp とかでファイルやり取りしてきたので、どちらもそれほど期待してなかったし未検証なのでなんとも。

全体的に、VirtualBox はクライアント用途で仮想マシンを使うのに向いてて、Hyper-Vの方はサーバ用途で使うのに向いてる感じがした。
昨今は仮想マシン上で本格的にデスクトップ操作を必要とする機会が少なくなってきた印象もあり、仮想マシンよりはCLIによるコンテナ管理が主役と感じる。多少デスクトップ操作に不便なところがあっても dockerと親和性の高い Hyper-V に慣れていくのがコンテナ時代にはベターなのかもしれない。