Hyper-V on Windows 11 に Arch Linux をインストールする

Arch Linux on Distrod on WSL2にいろいろと限界を感じ始めたので、Hyper-V上にArch Linux環境を作ることにしました。 手順をメモします。

Hyper-VとかLinuxとかよく分かっていないので、雰囲気でやっていきます。

Hyper-V 設定

Hyper-V - ArchWikiの手順に従いながら進めていく。

仮想ネットワークの設定

今回は内部スイッチを利用する。

Windows 10 Fall Creators Update (バージョン 1803) 以降では、仮想マシンに NAT スイッチ (Default Switch) が組み込まれており、特段の設定なしでインターネットに接続できます。

とのことなので、特別な設定は不要のようだ。

仮想マシンの作成

Hyper-V マネージャー

まず、Hyper-Vマネージャーの右サイドバーの「新規」→「仮想マシン」を選択。 出てきたダイアログに値を入力しながら進めていく。

名前と場所の指定

名前と場所は適当に指定する。 今回は名前を "thyme"、場所を D ドライブ配下にした。

世代の指定

UEFIベースのファームウェアを使うため、「第2世代」を選択。

メモリの割り当て

起動メモリはひとまず1024MBを指定。 「動的メモリ」を有効にして、必要に応じて追加のメモリが割り当てられるようにする (便利!)。

ネットワークの構成

前述の通り内部スイッチを利用するため「Default Switch」を選択。

仮想ハードディスクの接続

仮想ハードディスクを新たに作成して接続します。 ディスクは容量可変で後からサイズ変更可能なため、容量はデフォルトの127GBのままとした。

インストールオプション

Arch Linux JP Project - ダウンロード よりダウンロードしたISOイメージを指定。

仮想マシンの新規作成ウィザードの完了

最後に内容を確認して、「完了」を押すと、仮想マシンが作成され仮想マシンマネージャーの画面に戻る。

仮想マシンの設定

続けて、仮想マシンを設定していく。

Hyper-V マネージャー

仮想マシンマネージャーで作成した仮想マシンを選択すると右サイドバーに表示される「設定」をクリックする。

仮想マシン設定 → ハードウェア → セキュリティ

「ハードウェア」→「セキュリティ」を選択する。 Arch Wikiの注意書きに従い、セキュアブートを無効化する。

仮想マシン設定 → ハードウェア → メモリ

「ハードウェア」→「メモリ」を選択する。 動的メモリの最大割り当て量 (最大RAM) が1048576MB (1TB!) というとんでもない値になっている。 仮想マシンが暴走した場合などに問題が起きるかもしれないため、マシンの搭載メモリ量の50%ほどを指定しておく。 今回は32768(32GB)を指定した。

※後ほどrustupでRustをインストールしようとしたところメモリ不足で失敗すたため、RAMと最小RAMを2048MBに変更した。

仮想マシン設定 → ハードウェア → プロセッサ

「ハードウェア」→「プロセッサ」を選択する。 「仮想プロセッサの数」が1になっているので、適切な値に設定する。

仮想マシンで重い処理をする場合、搭載されているプロセッサコアの半分を割り当てると良いでしょう。

とのこと。ここで言うプロセッサコア数は論理プロセッサ数のことだと思われるが、今回はホストマシンの物理プロセッサ数の半分の8を設定した。

仮想マシン設定 → 管理 → チェックポイント

「自動チェックポイントを使用する」はオフにした。

その他の設定はデフォルトのままにした。 VMの運用方法に合わせて「自動開始アクション」や「自動停止アクション」の設定をすると良いだろう。

設定完了したら、「OK」をクリックする。

仮想マシンの起動

仮想マシンマネージャーの右サイドバーの「接続」をクリックして、仮想マシン接続を表示する。

仮想マシン接続

「起動」を押すと仮想マシンが起動される。

GNU GRUB

少し待つとGRUBの画面が表示される。

"Arch Linux install medium (x86_64, UEFI)" を選択し、先に進む。 何もキーを押さずに放置していれば、自動で選択されるようだ。

archisoコンソール

少し待つとコンソールが表示される。 インターネット接続できるか、以下コマンドで確認する。

# ping archlinux.org

Arch Linuxのインストールの準備

インストールガイド - ArchWiki に従って作業を進める。

コンソールのキーボードレイアウトの設定

US配列のキーボードを利用しているため、省略。

起動モードの確認

UEFIモードで起動しているか確認する。 以下コマンドでディレクトリの内容が表示されれば、UEFIで起動していると確認できるそうだ。

# ls /sys/firmware/efi/efivars

インターネットへの接続

以下コマンドでネットワークインタフェースが認識・有効化されていることを確認する。

# ip link

ip link の結果

認識されているようだ。

システムクロックの更新

NTPを有効化してシステムクロックを正しくする。

# timedatectl set-ntp true
# timedatectl status

timedatectl の結果

正しい時刻になっていればOK。

パーティションの作成

ディスクに割り当てられたブロックデバイスを確認する。

# fdisk -l

fdisk -l の結果

/dev/sda が割り当てられたようだ。 このデバイス上にパーティションを作成する。

今回はルートディレクトリのパーティションと、UEFIで起動するためのEFIシステムパーティションの2つを作成する。 UEFIを使うのでパーティションテーブルはGPTを使用する。

まずgdiskコマンドを起動する。

# gdisk /dev/sda

gdisk 起動時の画面

gdisk を起動するとパーティションテーブルのスキャン結果の後にプロンプトが表示され、コマンド入力を求められる。

gdisk コマンド一覧

? を入力すると、利用可能なコマンドの一覧が表示される。

まず、EFIシステムパーティションを設定する。

EFIシステムパーティションの設定

n (add a new partition) を入力すると、新たにパーティションを作成するためのパラメータが聞かれるので、順番に以下を入力する。

  • Partition number: 空欄 (デフォルト値: 1)
  • First sector: 空欄 (デフォルト値: 2048)
  • Last sector: 512M
  • Hex code or GUID: ef00 (EFIシステムパーティションを意味する値)

続いて、ルートディレクトリのパーティションを設定する。 再び n を入力する。 パラメータ設定は以下の通り。

  • Partition number: 空欄 (デフォルト値: 2)
  • First sector: 空欄 (デフォルト値: EFIパーティションの直後のセクター)
  • Last sector: 空欄 (デフォルト値: ドライブ全体の最終セクター)
  • Hex code or GUID: 空欄 (デフォルト値: 8300 = Linux ファイルシステムを意味する値)

パーティション設定結果

p (print the partition table) を入力して、設定値に問題がないか確認する。

パーティションの書き込み

問題がなければ w (write table to disk and exit) を入力して、パーティション情報をディスクに書き込む。 書き込みを実行しても良いか最終確認で聞かれるので、 Y を入力する。

処理が完了すると gdisk コマンドが終了し、シェルのプロンプトが表示される。

パーティションのフォーマット

作成したパーティションをフォーマットする。 EFIシステムパーティション (/dev/sda1) はFAT32でフォーマットする。 ルートディレクトリのパーティション (/dev/sda2) はお好みのファイルシステムでフォーマットすればよい。 今回はext4でフォーマットした。

# mkfs.fat -F32 /dev/sda1
# mkfs.ext4 /dev/sda2

mkfs.fatはすぐに終わるが、mkfs.ext4 は少し時間がかかる。

ファイルシステムのマウント

ルートディレクトリのパーティション/mnt にマウントし、EFIシステムパーティション/mnt/bootにマウントする。

# mount /dev/sda2 /mnt
# mount --mkdir /dev/sda1 /mnt/boot

Arch Linuxのインストール

引き続き、インストールガイド - ArchWiki に従って作業を進める。

ミラーの選択

/etc/pacman.d/mirrorlist の中身を確認し、作業環境から近いミラーサーバーがリストの中で上の方に来るよう並べ替える。

今回はJPドメインのミラーサーバーが一覧になかったため、デフォルトの設定のままとした。

archlinux-keyringの更新

作業実施時点 (2022/7/30) ではこの後のpacstrap実行が invalid or corrupted package pacstrap というエラーで失敗してしまうため、対処として行った。

# pacman -Sy archlinux-keyring

pacman -Syuですべてのパッケージを更新しようとしたところディスク容量不足で失敗してしまったため、archlinux-keyringのみ更新している。

必須パッケージのインストール

pacstrap を実行して /mnt 以下に必要パッケージをインストールする。 この後の作業で必要になるテキストエディタ dhcpcd 等の必要パッケージもインストールしておく。

# pacstrap /mnt base linux linux-firmware vim

※dhcpcdをやめ、 systemd-networkd に移行したため、削除

パッケージのインストールが正常に終了していることをきちんと確認すること。

システムの設定

更に引き続き、インストールガイド - ArchWiki に従って作業を進める。

fstabの設定

genfstabコマンドを使ってfstabを設定する。

# genfstab -U /mnt >> /mnt/etc/fstab

chroot

arch-chrootコマンドを使って、/mnt配下にインストールしたシステムにchrootする。

# arch-chroot /mnt

タイムゾーン設定

タイムゾーンJSTに設定し、hwclockコマンドを使って/etc/adjtimeを生成する。

# ln -sf /usr/share/zoneinfo/Asis/Tokyo /etc/localtime
# hwclock --systohc
# date

dateコマンドの実行結果がJSTになっていればOK。

ローカリゼーション

/etc/locale.gen の内容を編集して、en_US.UTF-8 UTF-8ja_JP.UTF-8 UTF-8の行をコメントを外す。 その後locale-genコマンドを使いロケールを生成する。

# vim /etc/locale.gen
...
# locale-gen

ロケールが生成されたら、/etc/locale.confを作成し、LANG環境変数を設定する。

# echo "LANG=en_US.UTF-8" > /etc/locale.conf
...

ネットワーク設定

/etc/hostname ファイルを作成し、ホスト名を書き込む。

# echo "thyme" > /etc/hostname

今回は thyme と名付けた。

再起動に備えて、ネットワーク機能を有効化しておく。

# systemctl enable systemd-networkd.service
# /etc/systemd/network/20-wired.network
[Match]
Name=eth0

[Network]
DHCP=yes

rootパスワード設定

passwdコマンドでrootユーザーのパスワードを設定する。 設定しておかないと、再起動後ログインできなくなってしまう。

ブートローダーの設定

今回はsystemd-bootを利用することにした。

systemd-boot - ArchWiki を参考に設定していく。

EFIブートマネージャのインストール

bootctlコマンドを使ってEFIブートマネージャをインストールする。

# bootctl --path=/boot install

成功すると/boot/EFI等のファイルが作成される。

ローダー設定

/boot/loader/loader.confを以下のように書き換える。

default arch
timeout 3
editor  no

ローダーエントリの追加

ブートローダーのエントリを追加する。 まず、サンプルのブートローダーエントリファイルをコピーして編集する。

# cp /usr/share/systemd/bootctl/arch.conf /boot/loader/entries/
# vim /boot/loader/entries/arch.conf

以下のように編集する。 * optionsの行のroot=PARTUUID=XXXXXXXXをPARTUUIDに置き換える * PARTUUIDの値は blkid -s PARTUUID -o value /dev/sda2 で取得できる * optionsの行のrootfstype=XXXXXXXXファイルシステム種別に置き換える * 今回はext4

bootctl list を実行すると、登録されたローダーエントリを確認できる。

再起動

exitコマンドまたはCtrl-d入力によりchroot環境より抜け、rebootコマンドでマシンを再起動する。 成功すればログイン画面が表示されるはず。

ブート後の設定

まずはrootユーザーでログインする。

一般ユーザの追加

ユーザーとグループ - ArchWiki を参考に作業を進める。

まず、wheelグループに属したユーザーを作成し、ログインパスワードを設定する。

# useradd -m -G wheel -s /bin/bash nksm
# passwd nksm

今回はnksmというユーザー名のユーザーを作成した。

次に、sudo が使えるよう設定する。

まず、sudoをインストールする。

# pacman -S sudo

続いて、 /etc/sudoers を編集してwheelグループに属するユーザーがsudoを使えるようにする。 安全のため、visudoで編集する。

# EDITOR=vim visudo

以下の行のコメントを解除する。

%wheel ALL=(ALL:ALL) ALL

ここまで編集したら一旦rootユーザーのセッションからログアウト後、作成したユーザーのアカウントでログインしsudoが使えることを確認する。

manページのインストール

この後の設定作業で参照する機会も多いので、manを使えるようにしておく。

$ sudo pacman -S man-db

SSH設定

Hyper-Vのコンソールからの作業は大変なので、SSHでログインできるようにする。

まず、opensshをインストールする。

$ sudo pacman -S openssh

次に、SSHデーモンの設定を編集する。

$ EDITOR=vim sudoedit /etc/ssh/sshd_config

今回は内部ネットワークにしか接続しないことから、デフォルト設定のままにしている。

最後に、SSHデーモンを有効化し、起動する。

$ sudo systemctl enable --now sshd.service

ホストマシンからsshログインできることを確認する。 仮想マシンIPアドレスip addrで調べておく。

$ ssh nksm@<仮想マシンのIP>

ssh-copy-id を実行するなどして、公開鍵でログインできるようにしておくと良い。

ネットワーク設定を変更する

Hyper-Vのデフォルトの仮想スイッチ"Default Switch"ではVM起動の度に異なるサブネット/IPアドレスが割り振られるため、外部からSSHログインするためには毎回IPアドレスを調べる必要がある。 これでは不便なのでネットワーク設定を変更する。

今回は外部ネットワークに直接接続させ、仮想マシンIPアドレスは外部ネットワーク上のDHCPサーバーにより自動割り当てさせることとする。

Hyper-V マネージャー

まず、Hyper-Vマネージャーの右サイドバーの「仮想スイッチマネージャー」をクリックする。

仮想スイッチの作成

仮想スイッチマネージャーの「新しい仮想ネットワークスイッチ」で「外部」を選択し、「仮想スイッチの作成」をクリックする。

仮想スイッチのプロパティ

仮想スイッチのプロパティで適当な名前を設定し、「OK」をクリックしスイッチを作成する。 このとき、ネットワークが一瞬切断される旨の警告ダイアログが表示される。

仮想マシンの設定

仮想スイッチ作成後、仮想マシン設定の「ネットワークアダプター」で、「仮想スイッチ」を先ほど作成したスイッチ (今回は External Switch) に変更し、「OK」ボタンを押す。

少し待つと、外部ネットワーク上のDHCPサービスにより仮想マシンIPアドレスが割り当てられる。

ホスト名で名前解決できるようにする

mDNSの仕組みを使うと、ローカルネットワーク上のホストについて ホスト名.local で名前解決できるようになる。 mDNSを有効にするためには、systemd-resolvedを有効化すれば良い。

$ sudo systemctl enable --now systemd-resolved.service

これでホスト環境から ssh <ホスト名>.local仮想マシンへログインできるようになる。

Hyper-V Integration Servicesを導入する

Hyper-Vの動的メモリ機能等を有効にするため、Hyper-V Integration Servicesをインストールし、起動・有効化する。

$ sudo pacman -S hyperv
$ systemctl enable --now hv_fcopy_daemon.service hv_kvp_daemon.service hv_vss_daemon.service

AURヘルパーを入れる

AURからのパッケージインストールを簡単にするため、AURヘルパーを入れる。 今回はparuを導入する。

GitHubのREADMEの手順に従いインストール。 途中rustを入れろと言われるので、入れる。

$ sudo pacman -S --needed base-devel
$ sudo pacman -S git
$ git clone https://aur.archlinux.org/paru.git
$ cd paru
$ makepkg -si

paruの新バージョンがリリースされた時に自動アップデートできるよう、AURからparu-binをインストールし、paruを上書きする。

$ paru -S paru-bin

systemd-boot更新時にbootctl updateを自動実行する

systemd-bootが更新された場合、EFIブートマネージャを更新できる。 更新のためには bootctl update を実行する必要がある。 作業を自動化するためにAURよりpacmanのhookをインストールする。

$ paru -S systemd-boot-pacman-hook

NTPの有効化

timedatectlで有効化する

$ sudo timedatectl set-ntp true
$ timedatectl
               Local time: Sat 2022-07-30 19:13:32 JST
           Universal time: Sat 2022-07-30 10:13:32 UTC
                 RTC time: Sat 2022-07-30 10:13:32
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

NTP serviceがactiveになった。

swap の有効化

ひとまず4GBのswapfileを用意する。

スワップ - ArchWikiを参考に設定する。

$ sudo dd if=/dev/zero of=/swapfile bs=1M count=4096 status=progress
$ sudo chmod 600 /swapfile
$ sudo mkswap -U clear /swapfile
Setting up swapspace version 1, size = 4 GiB (4294963200 bytes)
no label, UUID=00000000-0000-0000-0000-000000000000
$ sudo swapon /swapfile

自動的にswapfileが有効化されるよう、/etc/fstabに以下を追加する。

/swapfile none swap defaults 0 0

以降、随時追加予定