03[1]
米マイクロソフト(Microsoft)純正のLinux環境「Windows Subsystem for Linux(WSL)」。Windows 10 1803版(Redstone 4、以下RS4)では、Windows版Liunxと言えるこの機能がいよいよ完成形に近づく。従来はWSL実行中のウィンドウを閉じるとLinux環境ごと消える作りだったが、RS4では常駐が可能になる。

 従来のWindows 10 1709版(Redstone 3、以下RS3)までのWSLでは、WSLを起動したコマンドウィンドウ(bash.exeなど)の終了はWSL環境全体の終了と同義だった。ウィンドウを表示させずにバックグラウンドで動作するような、サーバー系のプログラム(デーモン)の実行には向かない。RS4では、プロセスなどを継続して実行できるようになった...

米マイクロソフト(Microsoft)純正のLinux環境「Windows Subsystem for Linux(WSL)」。Windows 10 1803版(Redstone 4、以下RS4)では、Windows版Liunxと言えるこの機能がいよいよ完成形に近づく。従来はWSL実行中のウィンドウを閉じるとLinux環境ごと消える作りだったが、RS4では常駐が可能になる。

 従来のWindows 10 1709版(Redstone 3、以下RS3)までのWSLでは、WSLを起動したコマンドウィンドウ(bash.exeなど)の終了はWSL環境全体の終了と同義だった。ウィンドウを表示させずにバックグラウンドで動作するような、サーバー系のプログラム(デーモン)の実行には向かない。RS4では、プロセスなどを継続して実行できるようになった*1

*1 ただしWSLでは、Linuxのrcスクリプト(システム起動時に実行される初期設定プロセス。デーモンなどはここで起動する)などをサポートしていないため、一般的なLinuxディストリビューションのようにシステム起動時に自動でデーモンを起動させる使い方はできない。

 使い勝手を大きく変えそうなバックグラウンド動作に代表される、RS4の主な変更点は以下になる。

  • (1)バックグラウンドプロセスが常駐可能に
  • (2)ファイルシステムとネットワーク設定の事前指定
  • (3)Windowsドライブのパーミッション設定が可能に
  • (4)WindowsプログラムとLinuxプログラムの連携強化
  • (5)Windows-Linux環境間でのプロセス間通信

 以上の機能強化を実現するRS4の登場と前後して、新たにDebian GNU/LinuxやKali LinuxといったLinuxディストリビューションがWindowsストアから入手可能になった。開発者が実務に使える環境が着実に整ってきた。

Microsoftストアで入手できるLinuxディストリビューションも増えてきた
[画像のクリックで拡大表示]

(1)Linux環境がバックグラウンドでも動作

 WSLは、実際にはスタートメニューなどから「bash.exe」や「debian.exe」といった実行ファイルを起動して利用する。RS3までのWSLでは、例えばbashを起動するとWSL環境が作られ、このbashを終了するとWSL環境自体が終了していた。WSL環境内でデーモンプログラムを動作させていても、bash終了とともにバックグラウンドタスクごとメモリーから消えていた。開発者にとってはLinux互換環境とは言いがたい状況が続いていた。

 これに対しRS4では、bashなどから起動したバックグラウンドタスクがある限りWSL環境はWindows上に残り続ける。

WSLでsshdを起動し、bashを終了したところ。wslhost.exeでWSL環境が残り、sshdは動き続ける
[画像のクリックで拡大表示]

 内部の動きを細かく見ていこう。

 もともとWSLでは、bash.exeなどからLinux側シェルである「bash」を起動する際に、WSLを動かすプロセスが起動してLinux環境の初期化を担う「init」プロセスをエミュレーションしている。親子関係にあるこれらのプロセスは、bash.exeなどの終了によって同時に消える。RS4からは、「wslhost.exe」という新プログラムが導入され、これがWSL環境を維持する。このwslhost.exe配下にあるLinuxプログラムは、Linux内のbashプロセスが終了しても、WSL環境を継続して実行し続ける。

 ただし、Windowsの「サービス」とは性格が異なる。WSL環境は、ユーザーのサインアウトなどでセッションが終了した時点で、他のWindowsプロセスと同様に終了する。このため、WSL内でSSHサーバーの「sshd」のようなネットワーク関連のデーモンを動作させても、ユーザーがサインアウトすればそれまで。Linuxの起動時にデーモンを自動起動するrcスクリプトはWSLではサポートされない。開発者向けのLinuxテスト環境が主目的という位置付けはこれまでと同じだ。

(2)ファイルシステムとネットワーク設定の事前指定

 RS4のWSLでは「/etc/wsl.conf」ファイルによるDrvFsやネットワークの設定が可能になった。DrvFsは、WSL側からWindows側ドライブを利用するために組み込まれたファイルシステム。RS3までは、Windows側の固定ドライブ(リムーバブルではないドライブ)は起動時に/mnt以下に「/mnt/c/」のように既定の場所に自動マウントされていた。

 wsl.confファイルは、かつてWindowsで多用されていた.ini形式のテキストファイル。大きく「[automount]」と「[network]」の2つのセクションがある。セクション中の設定項目は「キーワード=値」の書式になっており、先頭が「#」の行は注釈となる。

 まず、automountセクションでは、自動マウント機能、DrvFsのマウントポイント、マウントオプション、/etc/fstabによるマウント指定などを設定できる。

wsl.confファイルのautomountセクションの主な設定項目
設定行 設定可能値 省略値 意味
enabled true/false true Windows管理のドライブをDrvFsでマウント
root 文字列 /mnt/ Drvfsのマウントポイント
options カンマ区切りのオプション値 なし DrvFsのマウントオプション値
mountFsTab true/false true /etc/fstabによる自動マウントを実行

 無設定の場合の挙動は従来と同じ。後述するRS4で追加されたDrvFsのオプション設定を付けてマウントしたい場合は、wsl.confで明示的に指定する必要がある。

 次のnetworkセクションでは、「/etc/hosts」ファイルと「/etc/resolv.conf」ファイルの自動生成を制御できる。

wsl.confファイルのnetworkセクションの主な設定項目
設定行 設定可能値 省略値 意味
generateHosts true/false true ホスト名とIPアドレスを対応付ける/etc/hostsを自動生成
generateResolvConf true/false true DNSサーバーを設定する/etc/resolv.confを自動生成

 前者はIPアドレスとホスト名の対応表で、後者はDNSによる名前解決を設定するファイルだ。どちらも無指定の場合はWSLがWindows側の設定などからファイルを自動生成する。networkセクションで自動生成を停止すると、任意の設定が可能になる。

(3)Windowsドライブのパーミッション設定が可能に

 RS4では、DrvFsのマウント時にオプションを指定できるようになった。このオプションにより、WSL側から見たWindowsドライブに対するアクセス制御(パーミッション)の設定などが可能になる。これにより、特定のパーミッションが動作の前提になるプログラムの互換性が向上した*2。Linux系のアプリでは、セキュリティ上の理由で特定のパーミッション状態を要求するものがある。例えばsshは、秘密鍵ファイルが所有者以外は読み書きできないパーミッション(表記は600)でなければ動作しない。

*2 このほか、RS4ではDrvFs上にFIFOやUNIXソケットを作成でき、Linuxファイルシステムとの互換性を高めている。

 RS3までは、DrvFs上のファイルに対してWSL側パーミッションを設定する方法は用意されていなかった。DrvFs側のパーミッションは、Windowsのアクセス制御リストにより決定されたもので、所有者とグループは「root」に固定されていた。パーミッションを指定する「chmod」や「chown」というLinuxコマンドでWindowsドライブを操作しても、エラーにこそならないが何も変更できない。

 RS4では、パーミッションを指定するマウントオプションを指定できる。「metadata」オプションを指定してWSL側からのパーミッション設定を有効にし、ユーザーIDやグループID、パーミッションのマスク値などのデフォルト設定を指定できる。

WSLの主なマウントオプション
複数オプションを指定する場合はカンマで区切って順不同で並べる
オプション 意味 指定例
metadata メタデータの利用を可能にする metadata
uid ユーザーIDのデフォルト値 uid=10000
gid グループIDのデフォルト値 gid=10000
umask ファイル、ディレクトリのパーミッションマスク値 umask=022
fmask ファイルのパーミッションマスク値 fmask=111
dmask ディレクトリのパーミッションマスク値 dmask=0

 metadataオプションは、WSL用の属性データ(メタデータ)を用意し、以後のパーミッション制御はWindows側、WSL側ともメタデータを参照する指定だ。このため、WSL側とWindows側でパーミッションを変更しても矛盾した状態に陥ることはない。

 ただし複数ユーザー、複数WSL環境を同一マシンで利用する場合には注意が必要だ。WSLのインストール時に作成される最初のユーザーはすべて1000というユーザーIDを持つ。このため、1つのマシンの中に複数のWSL環境があれば、同じユーザーIDを持つユーザーが複数存在する。さらに起動したWindowsユーザーが違うと、その対応関係も違ってくる。

 なお、Linuxではファイルやディレクトリの大文字と小文字を区別するが、Windowsでは区別しない。WindowsのNTFSは仕様上、大文字と小文字を区別するが、APIレベルでは同一視しているためだ。そこでDrvFsでは、WSL側で作ったディレクトリの大文字と小文字を区別する属性が指定され、Windows側でも両者が区別できるようにしている。

WSL側からDrvFsを介してディレクトリを作ると、大文字と小文字を区別したフォルダが作られる
[画像のクリックで拡大表示]

(4)WindowsプログラムとLinuxプログラムの連携強化

 WSLの特徴の1つが、WSL側からWindowsのコマンドを起動できる「相互運用性」だ。例えばWSL内のLinux環境で「notepad.exe」を実行するとメモ帳が起動する。WSLを起動するWindowsコマンド(bash.exe、wsl.exeおよびディストリビューション名のubuntu.exeなど)では、引数としてWSL側で実行するLinuxコマンドを指定できる。両者の間は処理結果をやり取り可能な「標準入出力」で接続できるため、パイプ記号(|)を使った連続処理も可能だ。

 RS4では、WSLで起動したWindowsプログラムからさらにWSLを呼び出すといった多重起動にも対応した。さらに、こうした利用シーンで必要になる、プログラムの実行時などに参照する「環境変数」を共有する機能も実装された。Windows側で定義した環境変数をWSL側で読み込め、その逆も可能だ。RS3では、WSLを起動するときに「PATH」変数だけが渡されていた。RS4の環境変数の共有では、引き渡す環境変数を指定できる。

 このとき気になるのが、WindowsとLinuxとでパスの表記が異なる点だろう。Windows側では「C:\~」だが、WSL側ではDrvFsを使うため「/mnt/c/~」という形式になる。このため環境変数の共有時に、環境に合わせてパスの文字列を変換するかどうかを指示できるようになっている*3

*3 パスの変換に関しては、WSL側に「wslpath」というパスの変換用コマンドが用意されている。

 Windows側とWSL側それぞれの環境変数は、WSLENVという環境変数を通じて共有する。ここに共有したい環境変数名とオプションを“:”で区切って記述する。

WSLとWindowsで環境変数を共有する際のオプション
WSLを起動する前のWin32側で指定した場合、WSLからWin32を起動する場合には該当の環境変数を渡さないという意味になる。pとlはuとwの指定と併用可能(:/wpなど)
オプション 意味
/p 値は単独パスで変換して共有
/l 値はパスのリストで、変換して共有
/u Win32からWSLを起動するときのみ指定の環境変数を含める(値のパス変換なし)
/w WSLからWin32を起動するときのみ指定の環境変数を含める(値のパス変換なし)

 実使用時に注意すべきなのは「/w」オプションだ。これは、WSL側からWindows側を呼び出した場合に指定した環境変数を渡すが、その逆は継承させないというものだ。例えば、Windowsの環境変数「COMPUTERNAME」には標準でホスト名が入る。Windows側で「set WSLENV=COMPUTERNAME/w」としてWSLを起動し、さらにcmd.exeを起動すると環境変数COMPUTERNAMEは未定義になる。これによりWSLから起動したWindows環境に元々のWindowsの環境変数を伝搬させない処理が可能になる。

(5)Windows-Linux環境間でのプロセス間通信

 RS4では、プログラム同士がデータをやり取りするためのOSの基本機能である「プロセス間通信」の互換性も向上した。RS4のWSLは、Windows側のプログラムがLinuxのプロセス間通信の仕様に沿って動作できるようになった。

 Windowsのネットワーク通信のAPIは「WinSock」という。基はUNIXのソケットAPI(バークレーソケット)で、TCP/IPの通信には「AF_INET」というアドレス空間でIPアドレスを指定する。ところがWinSockは、Linuxやその基になったUNIXでローカルのプロセス間通信に使う「AF_UNIX」というアドレス空間を使うことができなかった*4。Windowsでは「名前付きパイプ」という別の技術がプロセス間通信に使われている。

*4 AF_UNIXは「Address Family UNIX」を意味し、ファイルパスをアドレスとして利用する。ツリー上のディレクトリ構造を使うUNIX/Linuxでは、ファイルパスはシステム内でユニークな存在になるからだ。同じファイルパスをアドレスとして指定したプロセス間で通信が可能になる。

 そこでRS4では、WinSockにAF_UNIXを実装。WSL内のLinuxアプリケーションとAF_UNIXによるプロセス間通信が可能になった。WSLの目的の一つが、Linuxバイナリをそのまま動作させること。AF_UNIXをWinSockがサポートすることで、Linux側のプログラムは改変せずWindows側のアプリケーションと連携できる。

 AF_UNIXのサポートと直接の関係はないが、RS4ではWindows側にtar(FreeBSDに搭載されたbsdtarがベース)とcurl(cURL)も組み込まれている

WindowsのコマンドプロンプトからLinux/UNIX由来のtarやcurlの2つのコマンドを実行できるようになった
[画像のクリックで拡大表示]

 WSLは当初、標準的なアプリしか動作せず、日本語表示なども怪しいものだったが、バージョンアップのたびに「リアル」なLinuxに近づきつつある。