👋

Ubuntu22.04 on WSL2(Windows10) 環境構築

2022/08/24に公開

Introduction

WSL2(Windows10)にUbuntu 22.04をインストールしたときの備忘録です。
インストール方法はいくつかありますが、Ubuntu 20.04をアップグレードする方法で行いました。

手順

Linux カーネル更新プログラム パッケージのインストール

x64マシン用WSL2Linuxカーネル更新プログラムパッケージ( https://aka.ms/wsl2kernel )をインストールします。
すでに最新版がインストール済みの場合には、インストーラを実行しても、インストール済みである旨のメッセージが表示されて何もしません。

仮想マシンプラットフォームを有効化

コントロールパネルで、仮想マシンプラットフォームを有効にします。

コントロールパネル
→ プログラム
→ Windowsの機能の有効化または無効化
→ 仮想マシンプラットフォームを有効にする

WSL 2 を既定のバージョンとして設定する

PowerShellでwslのバージョンを2に設定します。

PowerShell
> wsl --set-default-version 2

Ubuntu 20.04をインストール

現時点(2022/8/23)では、wslコマンドでUbuntu-22.04を直接インストールできませんので、Ubuntu-20.04からアップグレードすることにします。

まず、Ubuntu-20.04をインストールします。PowerShellで、以下のコマンドを実行します。

PowerShell
> wsl --install -d Ubuntu-20.04

途中、Ubuntuコンソールが起動し、Ubuntuの管理ユーザ名、パスワードを聞かれるので入力します。管理ユーザ名は、Windowsのユーザ名と一致する必要はありません。

Ubuntuコンソール
Installing, this may take a few minutes...
Please create a default UNIX user accout. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: hogehoge
New password:
Retype new password:

いったん、PowerShellに戻り、インストールしたUbuntu-20.04をWSLのデフォルトにセットします。

PowerShell
> wsl --set-default Ubuntu-20.04

DNS解決できない場合の対処

Windows10でインストールした場合、仮想ネットワークアダプターの関係なのか、うまく名前解決ができない場合があります(原因は未調査)。名前解決できない場合には、外部のDNSを設定してしまいます。
先ほどパスワードを入力したUbuntuコンソールに対して、以下の二つのコマンドを入力します。なお、すでに閉じてしまっている場合は、PowerShellからwslと入力すればokです。

Ubuntuコンソール
$ ping google.com
ping: google.com: Temporary failure in name resolution
$ ping 8.8.8.8 -c 1
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=114 time=27.5 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 27.451/27.451/27.451/0.000 ms

ping google.comで上記のようなエラーメッセージが出ていれば、DNSへの接続に失敗しています。また、ping 8.8.8.8が上気のように成功していれば、外部のDNSサーバへの接続が可能です。
ping google.comが成功していれば、この項目の対応は必要ありません。
ping 8.8.8.8が失敗していれば、そもそもネットワークに問題があるようです。

外部のDNSサーバに接続するようにするには、resolv.confファイルを設定します。ただし、WSLはデフォルトではresolv.confを毎回自動生成するので、それを抑制するために、まずwsl.confファイルを編集します。

Ubuntuコンソール
$ sudo nano /etc/wsl.conf              ← wsl.confファイルを新規作成
[sudo] password for hogehoge:

wsl.confファイルの中身は以下のように入力します。これによりresolv.confファイルが自動で更新されるのを抑制できます。

/etc/wsl.conf
[network]
generateResolvConf = false

続いて、resolv.confファイルを手動で作成します。

Ubuntuコンソール
$ sudo rm /etc/resolv.conf
$ sudo nano /etc/resolv.conf
/etc/resolv.conf
nameserver 8.8.8.8

google.comへのpingが通れば成功です。

Ubuntuコンソール
$ ping google.com -c 1
PING google.com (172.217.161.78) 56(84) bytes of data.
64 bytes from(以下略)

Ubuntu 22.04へのアップグレード

DNS名前解決できるようになりましたので、Ubuntuのアップグレードが可能になりました。
まず、apt updateとapt upgradeコマンドを入力して、20.04の最新状態へ更新します。

Ubuntuコンソール
$ sudo apt update                        ← 最新パッケージ読み込み
Get:1 http://security.ubuntu.com/ubuntu focal-security InRelease [114 kB]
...()...
Reading package lists... Done
Building dependecy tree
Reading state information... Done
278 packages can be upgraded. Run 'apt list --upgradable' to see them.

$ sudo apt upgrade                        ← 最新パッケージへの更新
Reading package lists... Done
Building dependecy tree
Reading state information... Done
Calculating upgrade... Done
...()...
278 upgraded, 32 newly installed, 0 to remove and 0 not upgraded.
Need to get 174 MB of archives.
After this operation, 305 MB of additional disk space will be used.
Do you want to continue? [Y/n] y          ← 更新確認にyを入力
...()...
$ exit                                    ← いったんUbuntuから抜ける

最新状態への更新が終わったら、いったんUbuntuを再起動します。PowerShellから以下のコマンドを実行します。

PowerShell
> wsl --shutdown                          ← WSLをいったん終了
> wsl                                     ← WSLを再起動

いよいよ、Ubuntuコンソールで、20.04を22.04にアップグレードします。いったん、アップグレードを開始すると、少々時間がかかり途中キャンセルできないけど続けますかと聞かれますので、yと答えます。

Ubuntuコンソール
$ sudo do-release-upgrade                 ← 最新のディストリビューションに更新
...()...
Installing the upgrade can take several hours. Once the download has
finished, the process cannot be canceled.

 Continue [yN]  Details [d] y             ← 処理を続行するか聞かれるのでyを入力

Fetching
...()...
Building dependency tree
Reading state information... Done

Searching for obsolete software
Reading state information... Done

Remove obsolete packages?

70 packages are going to be removed.

 Continue [yN] Details [d] y          ← 使わないパッケージ消していいか聞かれるのでyを入力
...()...
System upgrade is complete.

Action required

Exit all other instances of Ubuntu WSL before continuing.

Unsaved progress may otherwise be lost.

To continue please press [ENTER]      ← ENTERキーを入力

WSL restart required

Exit this instance of Ubuntu WSL.

The upgrade will then be complete.

To continue please press [ENTER]      ← ENTERキーを入力
...()...

$ exit                                    ← いったんUbuntuから抜ける

再びUbuntuを再起動します。PowerShellから以下のコマンドを実行します。

PowerShell
> wsl --shutdown                          ← WSLをいったん終了
> wsl                                     ← WSLを再起動

WSL用の対処

WSLでUbuntu 22.04を稼働させる際に、サポートしていない機能への対処などいくつか必要な作業があります。

needrestart

パッケージをインストールした際の再起動の判定などを行うneedrestartパッケージが、WSLでは正常に動作しません。
したがって、以下のようにneedrestartの設定を2か所変更します。

Ubuntuコンソール
$ sudo nano /etc/needrestart/needrestart.conf
/etc/needrestart/needrestart.conf
...()...
#$nrconf{kernelhints} = -1;                ← この行の下に
$nrconf{kernelhints} = 0;                  ← この行を追加
...()...
#$nrconf{ucodehints} = 0;                  ← この行の下に
$nrconf{ucodehints} = 0;                   ← この行を追加
...()...

iptables

WSLではnftablesをサポートしていないので、iptablesをlegacyモードに変更します。

Ubuntuコンソール
$ sudo update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).

  Selection   Path                       Priority   Status
-----------------------------------------------------------
* 0           /usr/sbin/iptables-nft      20        auto mode
  1           /usr/sbin/iptables-legacy   10        manual mode
  2           /usr/sbin/iptables-nft      20        manual mode

Press <enter> to keep the current choice[*], or type selection number: 11を入力
update-alternatives: using /usr/sbin/iptables-legacy to provide /usr/sbin/iptables (iptables) in manual mode

起動時のエラー

WSLのUbuntu-20.04にあるバグで、起動時にPermission deniedのエラーがでることがあります。それを避けるために以下のコマンドでファイルを削除します。

Ubuntuコンソール
$ sudo rm /var/lib/ubuntu-release-upgrader/ubuntu-release-upgrader

landscapeの削除

Ubuntu-22.04のlandscape機能が原因で起動時にエラーが出ることがあります。

/etc/update-motd.d/50-landscape-sysinfo: 17: cannot create /var/lib/landscape/landscape-sysinfo.cache: Permission denied

landscape機能は使わないので削除してしまいます。

Ubuntuコンソール
$ sudo apt remove landscape-core

systemd

WSLでは、Windowsとの相互運用を行うためのプロセスがPID=1で動作しており、そのため、systemctlを実行するためのsystemdが作動していません。
さまざまな方法がネットには上がっていますが、Ubuntu 22.04では、WSLでsystemdを動作させるためのスクリプトwsl-systemdが用意されており、これを起動時に実行させることにします。
Windows11では、wsl.confに[boot]セクションが用意されておりこれを使えば良いのですが、Windows10では起動プロセスに紛れ込ませることになります。

まず、起動時に実行するスクリプトを新規に作成します。

Ubuntuコンソール
$ sudo nano /etc/profile.d/00-wsl-systemd.sh
/etc/profile.d/00-wsl-systemd.sh
SYSTEMD_PID=$(ps -fe | grep '/lib/systemd/systemd --unit=multi-user.target$' | grep -v unshare | awk '{print $2}')

if [ -z "$SYSTEMD_PID" ]; then
	sudo /usr/libexec/wsl-systemd
fi

スクリプト内のwsl-systemdを実行されるときに管理パスワードを尋ねられないように、wsl-systemdをsudoersに記述します。

Ubuntuコンソール
$ sudo nano /etc/sudoers.d/wsl-systemd
/etc/sudoers.d/wsl-systemd
%adm ALL=(ALL:ALL) NOPASSWD: /usr/libexec/wsl-systemd

Ubuntuを再起動します。PowerShellから以下のコマンドを実行します。

PowerShell
> wsl --shutdown                          ← WSLをいったん終了
> wsl                                     ← WSLを再起動

systemdプロセスが動いていることを確認します。

Ubuntuコンソール
$ ps -fe | grep '/lib/systemd'
...()...
root    24   22 0 00:00 ?     00:00:00 /lib/systemd/systemd --unit=multi-user.target
...()...

nsloginすれば、systemdプロセスがpid=1で動作する環境に入ることができます。

Ubuntuコンソール
$ /usr/libexec/nslogin
$ ps -fe | grep '/lib/systemd'
root     1    0 0 00:00 ?     00:00:00 /lib/systemd/systemd --unit=multi-user.target
...()...

最初からsystemd pid=1

毎回/usr/libexec/nsloginと打つのが面倒なので、bashrcにnslogin仕組みを書いてしまいます。

Ubuntuコンソール
$ vi ~/.bashrc
~/.bashrc
...()...
# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

↓ 追加ここから
SYSTEMD_PID=$(ps -fe | grep '/lib/systemd/systemd --unit=multi-user.target$' | grep -v unshare | awk '{print $2}')
if [ -n "$SYSTEMD_PID" ] && [ "$SYSTEMD_PID" != "1" ]; then
    if [ -z "$1" ]; then
        /usr/libexec/nslogin
	exit
    fi
fi
↑ 追加ここまで
...()...

これで、wslコマンド実行後は、systemdがpid=1にある状態になります。

WSLにおけるsystemdの問題

WSL上のsystemdにはいろいろ問題が発生します( https://github.com/arkane-systems/genie/wiki/Systemd-units-known-to-be-problematic-under-WSL )。

特に大きな影響はありませんが、修正しておきます。

systemd-remount-fs.service

systemd起動時に以下のエラーが発生します。

mount: /: can't find LABEL=cloudimg-rootfs

これを回避するために、fstabファイルの先頭行をコメントアウト(#)します。

Ubuntuコンソール
$ sudo vi /etc/fstab
/etc/fstab
#LABEL=cloudimg-rootfs  /        ext4   defaults        0 0    ← 先頭に"#"を追加する

systemd-sysusers.service

systemd起動時に以下のエラーが発生します。

systemd-sysusers.service: Failed to set up credentials: Protocol error

これを回避するために、以下のコマンドを実行します。

Ubuntuコンソール
$ sudo systemctl edit systemd-sysusers.service

編集画面になりますので、"Lines below this comment will be discarded"よりも上に二行追加します。

/etc/systemd/system/systemd-sysusers.service.d/override.conf
### Editing /etc/systemd/system/systemd-sysusers.service.d/override.conf
### Anything between here and the comment below will become the new contents of the file

[Service]                                     ← 追加する行
LoadCredential=                               ← 追加する行

### Lines below this comment will be discarded
...()...

不要サービスの停止

不要なサービスと不要モジュールの整理を行います。

Ubuntuコンソール
$ sudo apt remove modemmanager
...()...
Do you want to continue? [Y/n]                 ← yを入力

$ sudo apt autoremove
Reading package lists.. Done
...()...
Do you want to continue> [Y/n]                 ← yを入力

ディストリビューション名の変更

今のままではディストリビューション名が"Ubuntu-20.04"なので、"Ubuntu-22.04"や別の名前に以下の方法で変更することができます。
ただし、レジストリをいじることになるので、よく分からない場合は、変更しない方が無難です。

PowerShell
> wsl --export "Ubuntu-20.04" D:\backup\wsl-ubuntu.tar
> wsl --import "Ubuntu-22.04" D:\wsl\wsl-ubuntu D:\backup\wsl-ubuntu.tar
> wsl --set-default "Ubuntu-22.04"
> wsl --unregister "Ubuntu-20.04"

D:\backup\wsl-ubuntu.tarは、移行用に一時的に使うファイルなので、変更後は削除してかまいません。
D:\wsl\wsl-ubuntuは、ディスクイメージになります。任意のディレクトリが指定できます。
"Ubuntu-22.04"が新しいディストリビューション名です。

なお、このままだとwslコマンドを入力したときのデフォルトログインユーザがexport-importでは保存されないため、rootがデフォルトユーザになってしまいます。
デフォルトユーザを設定するには、レジストリエディタで値を編集します。

まず、以下の場所を開きます。

\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss\

この下に、ディストリビューションが格納されますが、キーがUUIDなので一目でどれが対象なのかが分かりません。対象となるディストリビューションを見つけるには、それぞれのキーを開き、DistributionNameがimportした名前のものを見つけます。

Lxss\
  {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
    DefaultUid       REG_DWORD 0x00000000
    DistributionName REG_SZ    Ubuntu-22.04

DefaultUidをログインしたいユーザのuidに設定します。管理ユーザのuidは、標準通りインストールしていれば1000なので、1000を入力します (10進数で入力することを間違えなく)。

Discussion