第679回 ではLXD/VMの上にWindows 10をインストールしました。そのWindowsにおいて、本連載の読者層の多くがインストールしたくなるキラーアプリで、さらにUbuntuでは使えないアプリと言えばなんでしょう。そう、WSL(Windows Subsystem for Linux)ですね。 今回は家でも仕事場でもWindowsマシンが存在しないが故に、タイムラインのWSL談義にまったくついていけない人に向けて、LXDコンテナ上のWindowsでWSL2を楽しむ方法をお伝えします。
その行為に意味はあるのか
第679回 の話をまとめると次のとおりです。
[1] 「Kata Container」や「Hyper-Vコンテナ」なんて単語があるように、仮想マシンも「隔離環境」と考えると広義の「システムコンテナ」と言えます。よって仮想マシンであってもLXDが作るインスタンスと考えれば「LXDコンテナ」と言えなくもありません。逆に狭義のコンテナはOSの機能に拠って立つため「OSレベルの仮想化」と表現することがあるようです。
一度Windowsをインストールしてしまえば、あとは各自の好きなソフトウェアをインストールすればOKです。ただしインストールしただけでは次の制約が存在します。
3Dアクセラレーション無効:つまり3Dゲーム等は期待できません。VirGLもWindowsでは未対応なのでLXD側の設定でGPUパススルーなどを別途検討する必要があります。
音声が使えない:仮想マシン上にはオーディオデバイスがありません。よってWebミーティング等ができません。これについてはRDPを使うことで解決できる可能性があります。
USBデバイスが使えない:Webカメラを含むUSBデバイスが使えません。LXDのUSBパススルーやRDPもUSBリダイレクトで解決できる可能性があります。
一部のネットワークサービスが使えない:LXDのブリッジインターフェース経由の通信なので、Windowsの外とのLAN通信に制約があります。LXD側の設定で解決できます。
だいたいLXDかRemmina/RDPの設定で片付きそうな雰囲気ではあるものの、これらが使えなくても十分に価値のあるアプリケーションもたくさんあります。その最たる例が、冒頭でもお伝えしたWindows Subsystem for Linux(WSL) です。
本連載の読者であれば、「 WSLとはなんぞや」という点については説明するまでもないでしょう。簡単に言うと「Microsoftが作ったWindows上で動くUbuntuのCLI環境」 です。
正式にアナウンスされたのは2016年3月末のこと(Ubuntu Weekly Topics 2016年4月1日号 ) 。当時は「Bash on Windows」とも呼ばれていました。「 Windows Subsystem for Linux(WSL) 」と呼ばれるLinux向けバイナリをWindows上で動かすサブシステムが用意され、そのサブシステムを利用してBashとその周辺ツールをUbuntuベースで構築しました、というものです。その後、機能の拡充に伴いWSLが正式名称となり、正式なリリースとバージョンアップを経て、現在では開発者を中心に広く使われるツールとなりました。
WSLの一番のポイントはMicrosoft製であることです。サードパーティのアプリケーションを追加でインストールする必要はありません。環境の構築方法も何ステップ化で済む簡単なもので、さらに将来的にはもっと楽になる見込みです[2] 。現在はCLIのツールを動かすことがメインではあるものの、開発版ではGUIアプリケーションのサポート(WSLg)も進んでいます。
ちなみにたとえばWSL2の場合、技術的にはHyper-Vの上で動いている軽量Linux環境でしかありません。「 Ubuntu以外も使いたい」というユーザーは多く存在するため、WSL1/WSL2ともに現在ではUbuntuに限らず、さまざまなディストリビューションのイメージが公開されています。
WSL2のインストール
いろいろ御託を並べたものの、WSL2のインストール自体はMicrosoftの公式ドキュメント も含めていろんな媒体で紹介されているため、そこまで困ることはないでしょう。たとえばSoftware Designでも2021年7月号 では、特別企画として「WSL 2本格入門」が掲載されています。
Windows Insider Programに参加した環境であれば、管理者権限でコマンドプロンプトやPowerShellを開き「wsl --install
」を実行して再起動するだけのようです。今回は上記のドキュメントに従って、手動インストールを試してみましょう。
まずはCPUの仮想化支援技術を有効化しておきます。IntelならVT-xとか、AMDならAMD-Vとか言われるあれです。通常であれば「BIOSメニューで確認しましょう」になるのですが、今回はLXD上のWinodwsです。よってまずはホスト側の仮想化支援技術の有効化を確認したのちに、Nested KVMが有効化されているかを確認します。
$ egrep -m1 -w '^flags*:' /proc/cpuinfo | egrep -wo '(vmx|svm)'
vmx
上記コマンドでvmxないしsmxが表示されるなら仮想化支援技術は有効化されています。「 vmx」の場合はIntel CPUであるため、次の方法でNested KVMが有効化されているか確認できます。
$ cat /sys/module/kvm_intel/parameters/nested
Y
Yなら有効化、Nなら無効化です。「 smx」と表示された場合はAMD CPUなので上記ファイルパスの「kvm_intel
」を「kvm_amd
」に置き換えてください。
Ubuntuの19.04以降の公式のカーネルを使っているのであれば、Nested KVMは標準で有効化されています。18.04などで有効化したい場合は第609回の「LXDからコンテナではなく仮想マシンを起動する 」も参照してください。
無事にNested KVMが起動していたら、Windowsのタスクマネージャーからも次のように確認できます。
図1 詳細表示のパフォーマンスタブにあるCPUが「仮想マシン:はい」になっていたらOK
あとはMicrosoftのドキュメントに従うだけです。スタートメニューを右クリックし「Windows PowerShell(管理者)」を選択します。次のコマンドで、WSLと仮想マシンプラットフォームを有効化します。
> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
この状態で一度再起動して、上記の設定を反映します。次に「Linuxカーネル更新プログラムパッケージ」をダウンロードしてインストールします。URLは上記ドキュメントを参照してください。
もしPowerShellで実行したいならこんな感じです。今回は管理者版のシェルである必要はありません。
> cd $env:TEMP
> wget -UseBasicParsing https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi -OutFile wsl_update_x63.msi
> .\wsl_update_x64.msi
> rm .\wsl_update_x64.msi
あとは画面の支持に従ってNextを押していけば設定完了となります。最後にWSLを標準で使うバージョンをWSL2に変更しておきましょう。
> wsl --set-default-version 2
次にWSLにUbuntuをインストールします。左下の検索ウィンドウから「Microsoft Store」を検索して起動し、右上の検索ウィンドウで「ubuntu」を検索します。表示されるアイテムのうち「Ubuntu」か「Ubuntu 20.04 LTS」を選択してください。「 Ubuntu」は「インストール時点での推奨リリース」が選択されるため現時点でこれらは同じものを意味します。
図2 Microsoft Storeで「ubuntu」を検索した結果
「入手」ボタンを押してしばらく待てばインストール完了です。「 起動」ボタンを押すと初回セットアップが行われます。ユーザー名とパスワードを設定してください。
図3 Ubuntu環境を構築できた
ついでにMicrosoft Storeから「Windows Terminal」もインストールしておきましょう。
WSL2の起動と初期設定
Windows Terminalを起動したら「wsl」と入力します。これでWindowsの上でUbuntuのCLI環境が整いました。
図4 Windows TerminalでのWSL
いくつかやっておいたほうが良い設定を列挙しておきましょう。
リポジトリを日本のミラーに変更
日本に住んでいるのなら、日本のミラーリポジトリに変更しておいたほうが便利です。合わせてシステムのパッケージを更新しておきましょう。
$ sudo sed -i 's,//archive.ub,//jp.archive.ub,g' /etc/apt/sources.list
$ sudo apt update
$ sudo apt full-upgrade
もし「is not valid yet」などのエラーメッセージが出る場合は、時刻がずれている可能性があります。Windows側の時刻とタイムゾーンが正しいかどうかを確認の上、ずれているようなら設定の「時刻と言語」から正しい時刻に設定しておきましょう。なおシステム時刻を変更した場合は、WSLを再起動しないと反映されないようです。
なお、WSL環境ではsystemd-timesyncdのようなNTPクライアントは動いていません。そもそもinitがsystemdではなく、各種デーモンも起動していません。よって多少なりともずれが発生することは覚悟しておいてください[3] 。
日本語ロケールの設定
これは人によりけりだと思いますが、もし日本語ロケールで使い、さらに各種メッセージも日本語で表示してほしいなら、次のように設定します。
$ sudo apt install language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
たとえば単に日本語ロケールになれば良く、メッセージの翻訳(Language Packのインストール)までは不要なら、次のような方法も存在します。
$ sudo locale-gen ja_JP.UTF-8
$ sudo update-locale LANG=ja_JP.UTF-8
ただしaptコマンドのように翻訳データがLanguage Pack以外の方法で提供されるソフトウェアについては、日本語で表示されます。
WSLの再起動
systemdが動いていないため、rebootコマンドは使えません。もしどうしても再起動したい場合は、Windows Terminal等から次のように実行します。
> wsl -t ubuntu
> wsl
「-t
」で指定したシステムを終了させます。起動はもう一度wslコマンドを実行するだけです。
WSL起動時のカレントディレクトリを変更する
Windows Terminalを起動すると、自動的に「%USERPROFILE%(C:\Users\<ユーザー名>)
」に移動します。この状態でWSLを起動すると、そのディレクトリのWSL上の表現である「/mnt/c/Users/<ユーザー名>
」となってしまいます。
普通のUbuntuのようにホームディレクトリにしたい場合は、「 ~/.profile
」の末尾に「cd "$HOME/"
」の行を追加するという方法もありますが、Windows Terminal側でも設定できます。
まずはWindows Terminalのタブの右端にある、プルダウンメニューから「設定」を選択します。次にサイドバーのプロファイルから「Ubuntu」を選択します。「 ディレクトリの開始」を「//wsl$/<ディストリビューション>/home/<ユーザー名>
」にしましょう。ディストリビューションはおそらく「Ubuntu」か「Ubuntu-20.04」になるはずです。
図5 Windows Terminalの設定
これによりWindows Terminalのプルダウンメニューもしくはタスクバーのアイコンを右クリックして「Ubuntu」を選べば、ホームディレクトリの位置でWSLが起動するようになります。
なお、Windows Terminalの起動時の状態は、スタートアップ設定の「既定のプロファイル」で設定できます。初期値は「Windows PowerShell」になっているため、PowerShellプロファイルの「ディレクトリの開始」を変更すれば、起動時のディレクトリを常に変更できます。また、既定のプロファイル自体を「Ubuntu」にしてしまえば、Windows Terminalを立ち上げると常にWSL2の中に入った状態で起動できます。
ちなみにWindows TerminalはJSONスクリプトからさらに細かい設定が可能 です。好みに応じて追加の設定をすると良いでしょう。
プロンプトの調整方法
WSLはコマンドのプロンプト文字列として「ユーザー名@マシン名:カレントディレクトリ$
」となっています。この部分はbashなり任意のシェルに依存するため、変更方法はUbuntuのときと同じです[4] 。
[4] 「WSL プロンプト」で検索すると高確率で「コマンドプロンプト(cmd.exe) 」の情報がヒットしてしまいます。CLIにおいてコマンドプロンプト(command prompt)とは、cmd.exeではなく、直前のコマンドが完了し次のコマンドの入力を促す(prompt)ための文字列を意味します。Ubuntuで端末を起動したときに表示される「ユーザー名@ホスト名:カレントディレクトリ$
」がコマンドプロンプトです。これはOSやシェルによって異なりますし、ユーザーが任意の値を設定できます。ちなみにWindowsのコマンドプロンプトはpromptコマンドでコマンドプロンプトを変更できます。言い換えると、Windowsのcmd.exeはpromptコマンドでコマンドプロンプト文字列を変更できるということです。
ただUbuntuホストの時は上記の設定でもそれなりに実用的ではあるのですが、WSLだとマシン名部分が大文字だったり、Windowsのファイルシステムだとディレクトリパスが長くなりがちだったりするので、若干不便です。よってよくある例を元に、bashにおける最低限の調整方法だけ説明しておきましょう。
bashの場合、設定自体は「~/.bashrc
」の末尾に次の行を追加します。
case "$TERM" in
xterm*|rxvt*)
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]WSL@$WSL_DISTRO_NAME\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
;;
screen*)
PS1="${debian_chroot:+($debian_chroot)}\[\e[38;5;202m\]\$(byobu_prompt_status)\[\e[38;5;245m\]WSL\[\e[00m\]@\[\e[38;5;172m\]$WSL_DISTRO_NAME\[\e[00m\]:\[\e[38;5;5m\]\w\[\e[00m\]\$(byobu_prompt_symbol) "
;;
*)
;;
esac
これによりプロンプトが、WSL起動直後は「WSL@Ubuntu:~$
」となります。
環境変数PS1
がプロンプトを司る部分です。これに適切な値を代入すれば、それに応じたプロンプトが表示されます。最初のPS1
は.bashrc
に書いてあったものをベースに作っています。環境変数TERM
がscreen*
のほうは、/usr/share/byobu/profiles/bashrc
からByobuのPS1
を持ってきています。
オリジナルからの変更点は次の2箇所です。
ユーザー名を表示する「\u
」を「WSL
」に固定化
マシン名を表示する「\h
」を「$WSL_DISTRO_NAME
」に変更
ユーザー名の固定化はどうせWSLにおいてマルチユーザー的な使い方はしないだろうという措置です。ただし「sudo -i
」などを多用するならユーザー名を表示していてもいいかもしれません。
ホスト名はWindowsのマシン名の代わりにWSLのディストリビューション名を表示するようにしてみました。
プロンプトのカスタマイズは、上級のエンジニアも嗜む高尚な趣味の世界です。興味がでてきたらぜひ「自分にとって一番良いプロンプト」を探してみてください。簡単に時間が溶けます。
UbuntuとWSLの間のファイルの送受信
SSHなどのサービスが動いていない状態でのWSL/Windows間、WSL/ホスト間のファイルの送受信の方法を考えてみましょう。
WSLとWindowsの間のファイルの送受信
WSLとWindowsの間のファイルの送受信についてはWSL関連の説明サイトならおそらくどこにでも書かれていることでしょう。よってここでは基本的な部分だけ説明します。
まずWSLからWindowsですが、WSLの中は/mnt/c
以下にCドライブがそっくりそのまま見えています。よってあとは必要な場所に普通のCLIのやり方でコピーすれば良いだけです。もちろん一般ユーザーで書ける場所は限られています。 たとえばWindows上の「ダウンロード」なら「/mnt/c/Users/<Windows上のユーザー名>/Downloads/
」となります。Windowsのパスは比較的安易に半角スペース等が含まれる点は注意してください。
Windowsからならファイルエクスプローラーを開いた上で、「 Ctrl-l」を押し、アドレスバーに「\\wsl$
」と入力します。これでディストリビューションごとのファイルシステムがネットワークファイルシステムとしてアクセスできます。 GUIでアクセスしたい場合はこちらが便利でしょう。
図6 ファイルブラウザーからホームディレクトリを見た様子
WSLとホストのUbuntuの間のファイル送受信
今回はホスト上のUbuntuマシンの上で動いているLXDのインスタンスとしてWindowsを起動し、そこにWSLをインストールする想定でした。 つまりホストのUbuntuがメイン環境であり、WSLはサブ環境になります。この2点間でファイルのやりとりができると便利です。
一番わかりやすいのはホスト側にSSHサーバーかSambaクライアントを入れてしまうことです。 しかしながらたまにしかやりとりしないなら若干オーバーキル気味です。
そこで今回はRemminaのファイル共有を使ってみましょう。 前回の手順通りに実施していたら、WindowsにはRemminaでRDP経由の接続を行っていると思います。まずは一旦ログアウトして切断しておきます。
次にRemminaのメインウィンドウからセッションを右クリックして「編集」を選択し、基本設定タブを開きます。 「 共有フォルダー」という項目があるはずですのでそこにチェックを入れて、選択メニューから「その他」を選択してください。
ホームディレクトリなどの適当な場所で、右上の「フォルダーを作成します」のボタンから「Share」といった英数字の名前のディレクトリを作成 してください。日本語フォルダー名はバージョンによってはきちんと表示できないため、英数字にすることをおすすめします。
作成したら「開く」ボタンを押して、そのフォルダーを選択し、保存ボタンを押して完了です。ちなみに今回は新規にフォルダーを作成しましたが、別に英数字の名前であれば既存のフォルダーでもかまいません。
あとは再度Windowsに接続します。ファイルエクスプローラーを起動して「PC」を選択すると「<Ubuntuのホスト名>の<共有フォルダー名>」といった形で表示されるはずです。
図7 Remminaの機能で共有されたフォルダー
しかし残念ながらこのフォルダーをWSLから直接見る方法は存在しません。DrvFsでマウントできるものの、アクセスはできません。おそらくWSL側での対応が必要です 。当面は前述の「WSLとWindowsの間のファイルの送受信」を駆使すると良いでしょう。特にWindows Terminalからなら「cd \\tsclient\<共有フォルダー名>
」で共有ディレクトリに移動できるため、タブを駆使すればキーボードだけでファイルのやりとりが可能です[5] 。
[5] ここまでやるなら普通にWindowsのファイル共有使ったほうがいいかもしれません。さらに言うと、どうもRemminaの共有フォルダーは安定度が悪いような感じです。何度かアクセスできなくなることがあり、そのたびに再接続していました。
WSLは非常にユーザーの多いツールであり、さまざまなところでいろいろな知見が公開されています。ぜひ導入して夢のCLI生活を堪能してください。
図8 Ubuntuだけで生活できるタイプの人なら、直接Ubuntu使ったほうが楽だとは思う