😸

Hyper-VでLinux環境(ArchLinux)を立ち上げてみる

2024/05/18に公開

特にArchLinuxに詳しいとかでは無いが、なんとなくやってみたくなったのでメモ。

方針・目標など

WindowsからHyper-V上のarchlinuxへの接続にはsshを使う。
Windows Terminalのプロファイルに登録しておくことで、WSLを起動するのと大きくは変わらない使用感(?)で楽に起動できるようにする。

ゆるふわ勢なのでインストールにはarchinstall:

https://wiki.archlinux.org/title/archinstall

https://github.com/archlinux/archinstall

を使ってあまり頑張らずにやる。
https://github.com/archlinux/archinstall
(ManjaroにDesktop無しのサーバー版があればそれで良かったような、という気もする)

ユーザーの作成やssh周りの設定などは、鍵の登録を自動化しやすかったりパッケージインストールなど諸々のセットアップができるのでcloud-initを使って行う。

https://cloud-init.io/

↓なお、他のディストリビューションでも知見を使い回しやすいのも大きい

https://cloudinit.readthedocs.io/en/latest/reference/distros.html

検証環境

手順

まず、Hyper-Vの有効化はまだであれば

https://learn.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v#enable-the-hyper-v-role-through-settings

などを参考に行っておく。

仮想マシンの作成

Hyper-Vマネージャーを開いて、画面右の「新規」→「仮想マシン」を開いて仮想マシンを作っていく。

仮想マシンの新規作成ウィザードが立ち上がるので、適当に入力していく:

名前は自分がわかりやすいものを適当につける。今回はarchlinux-exampleにした。

世代は第2世代にしておく。

今回は"Default Switch"を選択する。

他の選択肢との比較については例えば

https://atmarkit.itmedia.co.jp/ait/articles/2008/14/news018.html

などを参照。

インストールオプションでarchlinuxをインストールするためのisoファイルを指定する。
(仮想マシンに仮想DVDがアタッチされた感じになる)

https://ftp.jaist.ac.jp/pub/Linux/ArchLinux/iso/2024.05.01/

先述の通り今回は↑から取得した。

https://archlinux.org/download/

に他のミラーサイトもあるので適当なところから選んで最新版を取得する。

他の項目は適当に設定する。
(今回、触れてないところは全部デフォルトで設定した)

仮想マシンの新規作成ウィザードでの作業はここまでで終わりだが、
Linux仮想マシンを起動する際はトラップがあり、すぐに起動せずに一旦作成したマシンの「設定」を開く:

↑Linuxを起動する際は必ず「セキュアブート」をOFFにする
(デフォルトではONになっているが、OFFにしないと起動できない)

セキュアブートONだと起動時に↓のようなエラーになる:

仮想ハードディスクへのarchlinuxのインストール

仮想マシンの作成と設定を一通り行ったら仮想マシンを起動する。

正しく起動できると↓

みたいなのが出て、
少し待つとroot@archisoにログインした状態になる↓:

本来的にはここから

https://wiki.archlinux.jp/index.php/インストールガイド

などを参考にインストールしていく感じになるが、
冒頭で書いたようにもう少し楽にインストールする方法としてarchinstallコマンド:

https://wiki.archlinux.jp/index.php/Archinstall

が使えるのでこれを使っていく。
先程のroot@archisoにはarchinstallコマンドへのパスが通っているため、

archinstall

と実行すれば以下のような画面が起動する:

十字キーでカーソル移動+適当に各項目を選択・入力すればOKで結構直感的に操作できる。

いくつかだけピックアップしてメモしておく:

Mirrorsでは、スラッシュ"/"を打ってから"Japan"と入力すればリポジトリに日本のミラーサイトを登録できるので、
好みで設定しておく。

キーボードレイアウトはデフォルトでUS配列となっているので、必要に応じて"Locales"から適宜変更する。
日本語配列は"jp106"なので"/jp"などと入力して検索・選択する。

"Disk configuration"は必須選択項目で、必ず設定が必要。
今回は"Use a best-effort default partition layout"を選択した。

作成した仮想ハードディスクの容量とほぼ同様になっている/dev/sdaを選択する。

ファイルシステムは"ext4"を選択した。

/homeを別パーティションに分けるかどうか。
好みや用途次第だが、今回は"no"を選択した。

"Profile"で、用途に合わせたものを選ぶと必要そうなものをある程度インストールしてくれる。
今回はホスト(Windows)側からssh接続したいのでTypeは"Server"の"sshd"を選択↑

"Network configuration"では、ホストからsshしやすくしたいのでデフォルトにはせず、
Use NetworkManagerを選択する。

これによって、ゲストにログインしてip aを叩くなどしてIPアドレス(DHCPなので変わる可能性もあるらしい)をいちいち調べる必要がなくなり、<設定したホスト名>.mshome.netを指定すれば良くなる。
(ex. ssh <username>@<設定したホスト名>.mshome.net)

"Additional packages"について、インストールしたいパッケージ名を書くとはじめにインストールしてくれるようになる。
(リポジトリに存在しないものを入力するとメッセージを出した上で弾いてくれるため安心)

今回はcloud-initを使うため、

  • cloud-init
    • (後でプロビジョニングする用)
  • cloud-guest-utils
    • growpart(後からディスクを拡張した際に、自動でパーティションサイズを調整してくれる)などを使えるようにしておく

は最低限入れておく。

また、x11を使いたいため、
x11に必要なもの+動作確認用のために

  • xorg-server
  • xorg-apps
  • xf86-video-fbdev
    • GUIの表示に必要なビデオドライバー
    • xf86-video-vesaでも良いかも(xf86-video-fbdevxf86-video-vesaの順で使おうとするらしい)
    • (参考) https://wiki.archlinux.jp/index.php/Xorg
  • xorg-xeyes
    • 動作確認用

なども入れておく。
(GUIやクリップボード共有機能が一切必要無ければ↑は不要)

また、デフォルトだと結構びっくりするくらい何も入っていない(lessコマンドも無いしエディタも入っていなかったり)ので、
必要そうなものがあれば入れておく。

あとは"Root password"を適当に設定する。
※一般ユーザーは後でcloud-initで作るため今回は作成・設定しないことにする。rootでのログインは最終的には禁じた方が安心だが、最初はrootでログインする手段が残っている方がやりやすく、後から出来なくすれば良いというスタンスを取っている。

最終的に↓のような感じ:

(参考) 設定の保存

"Save configuration"を選択すると、
上記の手順で選択・入力した内容をjsonファイルとしてエクスポートできる。

https://github.com/archlinux/archinstall?tab=readme-ov-file#running-from-a-declarative-configuration-file-or-url

によるとarchinstallコマンド実行時に引数としてファイルの読み込みが可能なので、
今後同様の作業を行う可能性がある場合はここで保存しておくと良い。

"Save all"を選択し、適当なパスを指定するとそこにuser_configuration.jsonおよびuser_credentials.json(※パスワードはハッシュ化などはされておらず平文で書き込まれているので注意)を保存できる。

インストール作業完了後、すぐにrebootせずに、例えば、
まずは仮想マシンのIPアドレスをip aなどで調べておき、
保存したファイルがあるディレクトリで

python -m http.server

を実行し、8000ポートで公開すると、

Windows側で"http://<先ほど調べたIPアドレス>:8000"にアクセスすると、
user_configuration.jsonuser_configuration.jsonが見えるのでここでダウンロードしておく。

あとは"Install"を選択し、Enterを押すとインストールが開始される:

無事に一通り終わると以下のように聞かれる:

yesを選択するとインストールしたメディアにchrootして必要な初期セットアップができる。
今回はcloud-initのservice有効化をしたいのでyesを選択する。

cloud-initを有効化するため、

systemctl enable cloud-init
systemctl enable cloud-init-local
systemctl enable cloud-config
systemctl enable cloud-final

を順次実行する。

(他にも初期セットアップとしてやりたいことがあれば適宜やっておく)

exitで抜けると"Installation completed without any errors. You may now reboot."と出る。

先ほど(参考)と書いたところで説明したようにuser_configuration.jsonuser_credentials.jsonを保存したい場合はすぐにrebootやshutdownをせずに、適宜これらのファイルを回収しておく。

ここまで一通り終わったら一旦shutdownする。
(今回、cloud-initで初期設定を行うために新規で仮想DVDドライブをアタッチするのでrebootはしない)

(補足)プロキシ環境下でのインストール

プロキシ環境下ではリポジトリへのアクセスが出来なかったり一部のサービスが死んでいたりするようで、
いくつか追加手順が必要。

具体的には、archinstallコマンドを実行する前に、root@archisoユーザーで

# ↓環境に応じて適当に置き換える
proxy_url="http://username:password@X.X.X.X:80"

export http_proxy=$proxy_url
export https_proxy=$proxy_url

# 環境によっては `ftp_proxy=$proxy_url` なども要るかも

を実行しておく。これでパッケージインストール時にプロキシを突破できるようになる。

ただ、これだけでは不十分で、

https://github.com/archlinux/archinstall/issues/1852

のような問題が起こる。
すなわちreflector.serviceなるものが正常に動作しなくなるようで、
このためにarchinstallコマンドが途中で停止してしまう。

同issue中であるように、自身の環境では

# root@archiso

# `archinstall`コマンド実行前に↓を実施する
systemctl stop reflector.service

とすることで直った。

cloud-initによる初期セットアップ

meta-data, user-dataの記入とcloud-init用のメディア作成

やることとしては、cloud-initによる初期セットアップのために以下の2ファイル:

  • meta-data
  • user-data

を作成し、これらをisoファイルとして書き出す形になる。

なお、これはDatasourceをNoCloudとした場合(のMethod 1)に相当する:

https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html

ここで、

https://docs.aws.amazon.com/ja_jp/linux/al2023/ug/seed-iso.html

などを参考に、まずはmeta-dataファイル:

を作成する。(<vm-hostname>部分は適当に変更する)
ちなみに今回の手順ではhyperv-archlinuxとした。

先述の通り、ここで設定した内容を使って(IPアドレスをいちいち調べずに)今回立てるarchlinuxのゲストOSにアクセスできる。

archinstallコマンドで同内容の設定項目(デフォルトではarchlinuxとなっている)があり、後から変えないのであればそちらで設定してmeta-dataは無し、ということでも良いのかもしれない(未検証)

次にuser-dataを作っていく。

前準備として、ssh用の鍵を作る必要があるので、ssh-keygenコマンド(WSLなどでやっても良いし、Windows上でもたぶんC:\Windows\System32\OpenSSH\ssh-keygen.exeにある)を使って予め作っておく。

今回は例えば、

# archlinux_key_ed25519(秘密鍵), archlinux_key_ed25519.pub(公開鍵)が生成される
ssh-keygen -t ed25519 -f ./archlinux_key_ed25519

# パスフレーズ無しで良ければ↓ など(PowerShellではうまく動かなかった)
ssh-keygen -t ed25519 -f ./archlinux_key_ed25519 -N ""

のように作っている。

次にuser-dataの中身に関して、

https://cloudinit.readthedocs.io/en/latest/reference/examples.html#yaml-examples

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html-single/configuring_and_managing_cloud-init_for_rhel_8/index

や、その他諸々を参考にして設定していく。

今回は、大まかなところでいうと

  • uid: 1000のユーザーを作成
    • 今回、名前はvm-userとしている(適宜好きに変える)
    • パスワード無しでsudoを使えるようにする
    • sshの公開鍵を設定しておく(password認証は禁止しておく)
  • sshにおける認証は公開鍵の使用を義務付け
  • rootへのsshログインは禁止
    • (ただし、Hyper-Vの「接続」からのログインは禁止されていないので注意。)

みたいな感じになる。
(他にも若干設定している)

具体的には例えば以下のような感じ:

user-data
#cloud-config
timezone: Asia/Tokyo
locale: en_US.utf8
ssh_pwauth: False
disable_root: True
users:
  - name: vm-user
    ssh_authorized_keys:
      # ↓sshにおけるログインで使う公開鍵の内容(ここではed25519にしているが他のでも良い)
      - ssh-ed25519 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX xxxxxxxx@XXXXXXXXX
    shell: /usr/bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: [wheel, users, sudo, adm]
    uid: 1000

package_update: true
package_upgrade: true
# 追加でインストールしたいものを↓に列挙していく
packages:
  - tmux
  - xclip
  - xsel
  - neovim
  - bash
  - bash-completion
  - zsh
  - zsh-completions
  - man-db
  - man-pages

# ↓最後に以下で設定した内容が順次実行される
runcmd:
# ↓Portをデフォルトから変えたい場合はコメントアウトを解除して適当に変える
# - sed -i -e 's/^#Port 22/Port 2022/' /etc/ssh/sshd_config
- sed -i -e 's/^#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i -e 's/^#X11Forwarding no/X11Forwarding yes/' /etc/ssh/sshd_config
- systemctl restart sshd

packageで書く部分は前の手順のarchinstall部分でやってスキップでも良い。
が、手打ちで沢山書くのは大変だし、archinstallのオプションにファイルを読み込ませるのが意外と面倒そう(isoイメージ側にうまくファイルを渡すか、入力しやすいURLでファイルをネット上に公開するか...)だったので、ごく最低限のものとデバッグに必要なもの以外はcloud-initで入れるのもアリだと考えている。

一通り記入したら、これらをディスクイメージに書き出す。

例えばWSL(Ubuntu)などを使う場合、

# WSLのUbuntu

# genisoimageのインストール
sudo apt install genisoimage

# イメージ作成
mkisofs -output arch-seed.iso -volid cidata -joliet -rock user-data meta-data

のような感じでできる。(参考)

cloud-initによる初期セットアップの実行

仮想マシンにアタッチされているインストールメディア(isoファイル)を除去し、
代わりに先ほどgenisoimageを使って作成したisoファイルをアタッチする。

この状態で仮想マシンを起動すれば、自動でcloud-initが走ってmeta-dataおよびuser-dataで記述した内容が設定される。

仮想マシンの「接続」を開いておくと(※ログインはしない)、↑のような感じで実行状況が表示される。
(実行状況はrootなどでログインして/var/log/cloud-init.logなどを見て確認することもできる)

(あとどうでも良いが、前の手順でxf86-video-fbdevを入れ忘れていたのでここで入れている)

無事に終わってそうであれば一度shutdownして再起動すると確実かも?しれない
(設定内容次第ではしなくても良いのかも)

うまくいってなさそうなら、/var/log/cloud-init.logの内容を参照しつつuser-dataとisoファイルを作り直し、
再実行していく。

cloud-initの再実行は

https://cloudinit.readthedocs.io/en/latest/howto/rerun_cloud_init.html

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/configuring_and_managing_cloud-init_for_rhel_8/troubleshooting-cloud-init_configuring-cloud-init

https://qiita.com/sonots/items/e60261ea28c61e322631

https://qiita.com/ksk_ha/items/468101e9deb63aab5acd

などを参考

一通り終わったら、仮想マシンにアタッチされているcloud-init用のisoファイルを外しておく。

ホスト(Windows)からゲスト(archlinux)へのログイン

仮想マシンを起動しておけば、自動でsshdサーバーが起動しているためホスト(Windows)側からssh接続することができる。

Windowsにもおそらくデフォルトでsshは入っている(C:\Windows\System32\OpenSSH\ssh.exeなど)ので、それを使ってログインする。

powershell
# 秘密鍵はuser-dataに記入した公開鍵と対になっているものを指定
# `vm-user`部分はuser-dataで作成したユーザー名に、
# `hyper-v-archlinux`はmeta-dataで指定したホスト名にそれぞれ置き換える
ssh.exe -i <作成した秘密鍵のパス> vm-user@hyperv-archlinux.mshome.net

↑のように無事、PowerShellなどからsshログインできる。
(※archinstall時にNetworkManagerを設定しなかった場合、<ホスト名>.mshome.netを指定してsshすることは出来ず、別途IPアドレスを調べる必要がある)

なお、Hyper-VのDefault SwitchとWSLのネットワークは通常つながっていないため、
WSLからHyper-Vのゲストにsshにすることは出来ない。(設定を頑張れば出来るらしいが今回はやらない)

X11の動作確認(VcXsrv)

個人的にはCUIベースの操作が多くてもclipboardの共有などのためX11(X Window System)を使えるようにしたいことがある。

先述の通り、WSLからではなく素の(?)Windowsからsshしているため、そのままではX11は使えないので、別途入れる。

無償で使えるものとしてはVcXsrv:

https://sourceforge.net/projects/vcxsrv/

などがあるのでこの辺を使う。
なお、wingetが使える状況であれば、

powershell
winget install vcxsrv

などとしてインストールできる。

インストールしたらWindowsキーを押して"xlaunch"などと入力して検索すると"XLaunch"が起動する。

こだわりが無ければひたすらEnterを押しまくれば良い。
するとWindowsから見てlocalhost:0.0にXクライアントを起動出来る。

(今回はやらないが、都度X Launchを起動するのが面倒であれば自動起動する方法もあるので、「VcXsrv 自動起動」「x launch 自動起動」などでググる)

sshするときに上記を環境変数DISPLAYとしてセットすると、リモート側(ゲストOSのarchlinux)のGUIアプリをWindows側で実行できる。

powershell
# PowerShellでは、環境変数は $env:<環境変数名> = <設定内容>で設定できる
# GUIを使う場合、X11の自動転送を有効化するためsshのオプションに`-XY`を追加する
$env:DISPLAY = "localhost:0.0"; ssh.exe -XY -i .\archlinux_key_ed25519 vm-user@hyperv-archlinux.mshome.net

↑ちゃんとxeyesが動いており、Windows側で操作できる。

※Warning: No xauth data; using fake authentication data for X11 forwarding. が出るが、個人的に使う範囲で実害はたぶん無いのでここでは放置する。
※リモート側の/etc/ssh/sshd_configファイルなどでX11Forwarding yesが設定されている必要があるので、うまく動かない場合はその辺も確認すること

ssh_configの設定

秘密鍵の指定やX11の転送設定、更にはホスト名もmshome.netまで入れると結構長くて都度打つのは疲れてくる。
(設定次第では当然もっとオプションは増えてくる。ポート番号など)

これだと大変なので、ssh_configを作成する。

https://nxmnpg.lemoda.net/ja/5/ssh_config

https://linux.die.net/man/5/ssh_config

Windows(C:\Windows\System32\OpenSSH\ssh.exe)ではC:\Users\<ユーザー名>\.ssh\config(あるいは、同じ意味だが%USERPROFILE%\.ssh\config)を作成・編集すれば良い。

記載例:

%USERPROFILE%\.ssh\config
# ↓必要に応じて全プロファイル共通の設定
ServerAliveInterval 60
ServerAliveCountMax 5

# ↓Hostは自分な好きな名前を適当につける
Host archlinux
  HostName hyperv-archlinux.mshome.net
  User vm-user
  # デフォルト(22)なら記述不要だが、ポート番号を変えている場合は書いておく
  # Port 22
  # 秘密鍵のパスを記述しておく。(Windowsでも書き方はUnix系の書き方になる)今回は%USERPROFILE%\.sshに秘密鍵も置くことにしている
  IdentityFile ~/.ssh/archlinux_key_ed25519
  # ↓X11の転送設定。それぞれ順にX, Yオプションに相当
  ForwardX11 yes
  ForwardX11Trusted yes
  # (その他適宜オプションを追加)

上記のような設定を書いておくと、↓のようにsshできる。

powershell
# sshの引数にはssh_configで設定したHost名を指定できる
$env:DISPLAY = "localhost:0.0"; ssh.exe archlinux

また、Windows側とリモート側でファイルのやり取りをする際にscpコマンドを便利に使えるようになる:

scpコマンドでもリモートマシンの指定にssh_configで記述したHost名を指定できるので、ssh同様長いオプションなどを省略できる。

Windows TerminalでのProfile設定

X11転送をしてGUIを使う場合、環境変数の設定はまだ直打ちになっており不便である。
また、それがなかったとしてもWindows TerminalでWSLのディストリビューションを選ぶのと同じ感覚でリモートマシンに入れるとより便利である。

↑の"+ 新しい空のプロファイル"から作成・追加する。

名前はわかりやすいものをつけておく(ここでは"ArchLinux(Hyper-V)"とした)。

後はコマンドラインでsshする部分を設定してあげる必要がある。

DIAPLAY環境変数を永続的に設定したくない場合は前の手順のように都度ワンライナー的に設定する形になり、sshする部分と合わせて最低2コマンド分をProfileに設定しないといけないので少し大変になる。

https://github.com/microsoft/terminal/issues/6477

などを参考に、ここでは

コマンドライン
%SystemRoot%\System32\cmd.exe /k "set DISPLAY=localhost:0.0&& C:\Windows\System32\OpenSSH\ssh.exe archlinux"

のように設定している。
後は好みでアイコンやフォントなど適当に設定する。

設定したプロファイルをWindows Terminalで選択して開くと:

のようにsshコマンドを打たなくてもはじめからリモートにログインした状態になる。
スクショの通り、X11転送もしっかりできている。

事前に仮想マシンおよびXLaunchの起動をやっておく必要はあるものの、これでかなり手軽に起動できるようになった。

まとめ、雑感

WSL2は便利で大好きなのだが、稀にWSL特有の制約事項で困るケースが稀にある(稀だが...)ので、
どうしても本物のLinuxを使いたかったりするときや、
あるいはセキュリティ的にホストとの隔離度を強くしたい場合には使えそう、
みたいなモチベーションでやってみた。

あと、意外とHyper-V特有の話は少なく、本質的には仮想マシンで立てたsshサーバーにホストからなるべく楽にsshできるようにする、という話でしかない。
なので、例えばLinuxのデスクトップを母艦にしてkvmで作業環境を作る(Gnome Terminalにプロファイル設定する)、といった場合にもほとんど同様の手順でできる。
(サードパーティのX11を使う手順が無くなるのでむしろ楽)

どちらかというと、そういう応用が効くような気がしたのでやってみたというモチベーションが大きかったりする。

その他の参考リンクなど

GitHubで編集を提案

Discussion