技術メモ 読む時間 約11分

Windows では実行できない Linux 前提の処理を実行するために:WSL に Ubuntu を入れて Docker を使えるようにした

Windows では実行できない Linux 前提の処理を実行するために:WSL に Ubuntu を入れて Docker を使えるようにした

仕事で使っているリポジトリでは、GitHub の CI(自動のチェック)で、テスト・コードの書き方・静的解析をまとめて流しています。その同じチェックを、自分の PC でも流せるスクリプトが用意されています。

ただ、このスクリプトは中で Docker と Linux の bash を使うので、Windows の Git Bash や PowerShell からは流せません。そこで、Windows の中に Linux(WSL の Ubuntu)を入れて、そこから Docker でチェックを流せるようにしました。この記事では、その手順と、途中でつまずいた 3 つの所をまとめます。

この記事のポイント

  • WSL に Ubuntu を入れて、ふだん使うユーザーを作る
  • Ubuntu から Docker Desktop の Docker を使えるようにする(WSL の連携と、Windows の .exe を動かす設定)
  • リポジトリは Ubuntu の中に clone して、チェックのスクリプトを流す(1 回目 10 分・2 回目から 1 分ほど)

使ったのは Windows 11・WSL 2.7.3・Docker Desktop(Docker 29.9.2)・Ubuntu 26.04.1 LTS です。Docker Desktop は前から入っていて、古い PHP のサイトの確認に使っていました。

ワンポイント:WSL とは

WSL は「Windows Subsystem for Linux」の略で、Windows の中で Linux を動かすための仕組みです。Microsoft が Windows に用意している機能で、別の PC や仮想マシンを用意しなくても、Windows の上で Ubuntu などの Linux を動かして、Linux のコマンドをそのまま使えます。今の WSL 2 は、Windows の中で本物の Linux のカーネル(Linux の中心の部分)を動かしているので、Linux 前提のスクリプトや Docker も、ほぼそのまま動きます。

1. 今の WSL を確認する

まず、WSL に何が入っているかを見ます。

wsl -l -v

入っていたのは、Docker Desktop が使う docker-desktop だけでした。Linux のシェルを使える Ubuntu がないので、足します。

2. Ubuntu を入れる

wsl --install -d Ubuntu --no-launch

--no-launch を付けると、入れたあとに Ubuntu の画面が開かず、ユーザーの作成も聞かれません。ユーザーは次の手順で作ります。

3. ふだん使うユーザーを作る

root で入って、ユーザーを作ります(ここではユーザー名を <ユーザー名> と書きます)。

useradd -m -s /bin/bash -G sudo <ユーザー名>
passwd <ユーザー名>

次に、WSL で開いたときに最初からそのユーザーになるよう、/etc/wsl.conf に書きます。上書きせず、元の内容を見てから足します。Ubuntu の WSL のイメージは、このファイルに systemd を使う設定を書いて配っていて、上書きすると systemd が切れます。

cat /etc/wsl.conf

元が [boot] と systemd=true だけなら、ユーザーの段を足して、次の形にします。

[boot]
systemd=true
[user]
default=<ユーザー名>

つまずいた所:wsl.conf を上書きして systemd を切っていた

わたしは最初、ユーザーの段だけを書いて、このファイルを上書きしていました。そのため systemd の行が消え、systemd が動いていない状態になっていました(記事を見直していて気づきました)。チェックを流すだけなら困りませんでしたが、systemd が要るサービスを使うときは困ります。元の内容を見てから足すのが安全です。

スクリプトから自動で流すので、わたしはパスワードを聞かれずに sudo できるようにしました。自分で打つだけなら、ふつうの sudo のままにしてください。パスワードなしの sudo は、その PC の Ubuntu をだれでも root で使えるので、自分だけが使う PC に限ります。

echo '<ユーザー名> ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/<ユーザー名>
chmod 440 /etc/sudoers.d/<ユーザー名>

設定を読み直させるために、一度 WSL を止めて入り直します(Docker の連携を設定する前なので、ここで止めても構いません)。

wsl --terminate Ubuntu
wsl -d Ubuntu

4. Ubuntu から Docker を使えるようにする

Docker Desktop を入れてあれば、Ubuntu からもそのまま docker が使えると思っていました。ところが、打つと次のエラーになりました。

docker version
.../DockerDesktop/resources/bin/docker: 24: exec: .../DockerDesktop/resources/bin/docker.exe: Exec format error

つまずいた所 1:Windows の docker.exe を呼んで「Exec format error」

原因は 2 つ重なっていました。

  • Docker Desktop の WSL 連携が Ubuntu に向いていなかった:連携が入っていないので、Ubuntu の中に Linux の docker がなく、Windows 側の docker(中で docker.exe を呼ぶスクリプト)が使われていた
  • Ubuntu が Windows の .exe を動かせなかった:WSL では、ふつうは Linux の中から Windows の .exe をそのまま動かせます。わたしの Ubuntu 26.04 では、その仕組み(WSLInterop)の登録がなく、.exe を動かそうとして「Exec format error」になっていた(systemd が動いているときに、WSL の登録が消える形の見込み)

1 つ目は、Docker Desktop と Ubuntu の連携を設定します。わたしの場合は、WSL の既定を Ubuntu にしただけで連携が有効になりました。Docker Desktop の「既定のディストリビューションと連携する」が、もとからオンだったためです。

wsl --set-default Ubuntu
Docker Desktop の Settings で WSL を探した画面。WSL integration の Enable integration with my default WSL distro がオン
Docker Desktop の Settings で「WSL」と探した所。「Enable integration with my default WSL distro」がオンなので、既定を Ubuntu にすると Ubuntu と連携します

既定を変えたくないとき

Docker Desktop の Settings の WSL integration(上の画面のように、Settings で「WSL」と探すと出ます)で、「Ubuntu」を個別にオンにして、Apply を押します(英語の表示のまま書いています)。既定を Ubuntu にすると、wsl とだけ打ったときの入り先も変わるので、それを避けたいときはこちらにします。

連携が有効になると、Ubuntu の中に Linux の docker(/usr/bin/docker)ができます。少し時間がかかるので、出てくるまで待ちます。

ls /usr/bin/docker
/usr/bin/docker
docker version --format "server {{.Server.Version}}"
server 29.9.2

2 つ目は、Windows の .exe を動かす仕組みです。Docker の認証の手伝い(docker-credential-desktop.exe)など、Ubuntu から Windows の .exe を呼ぶ所があるので、こちらも要ります。まず cmd.exe /c ver を打って、Windows のバージョンが出るかを見ます。出なければ、登録します。systemd を使うときは、1 行のファイル(binfmt.d)を置いておくと、再起動のあとも登録が残ります。

echo ':WSLInterop:M::MZ::/init:PF' | sudo tee /usr/lib/binfmt.d/WSLInterop.conf
echo ':WSLInterop:M::MZ::/init:PF' | sudo tee /proc/sys/fs/binfmt_misc/register
cmd.exe /c ver
Microsoft Windows [Version 10.0.26100.9711]

最後の cmd.exe /c ver で Windows のバージョンが出れば、Ubuntu から Windows の .exe が動いています。わたしの場合は、どちらの直しが効いたのかを分けて確認してはいません。同じエラーになったときは、連携 → .exe の順に見てください。

最後に、ユーザーが docker のグループに入っているかを見ます。入っていないと、docker を打ったときに「permission denied」になります。

id
sudo usermod -aG docker <ユーザー名>   # docker が出てこないときだけ・そのあと入り直す

5. リポジトリを Ubuntu の中に clone する

リポジトリは、Windows のフォルダー(/mnt/c/…)ではなく、Ubuntu の中(ホームの下)に clone します。Windows のフォルダーのまま流すと、ファイルの読み書きが遅く、権限の違いでつまずくことがあるからです。

つまずいた所 2:Ubuntu の中から Git のサーバーの認証が通らない

Windows ではふつうに clone や fetch ができるのに、Ubuntu の中からは Git のサーバーの認証が通りませんでした。Windows 側の認証の情報を、Ubuntu からうまく使えなかったためです。そこで、Windows 側の作業フォルダーで fetch しておき、Ubuntu からはそのフォルダーを取り込み元にする形にしました。

mkdir -p ~/dev && cd ~/dev
git clone /mnt/c/<Windows の作業フォルダー>/<リポジトリ> <リポジトリ>

プッシュの前に、ほかの枝を確認するときは、先に Windows 側で git fetch してから、Ubuntu で次のように取り込みます。

cd ~/dev/<リポジトリ>
git fetch -q /mnt/c/<Windows の作業フォルダー>/<リポジトリ> +refs/remotes/origin/<枝>:refs/remotes/origin/<枝>
git checkout --detach origin/<枝>

6. チェックを流す

cd ~/dev/<リポジトリ>
<チェックのスクリプト>

このスクリプトは、流すたびに使い捨てのデータベースのコンテナを立てて、テスト・コードの書き方のチェック・静的解析・ビルドを流し、終わったらコンテナを消します。最後に「PASS」の 1 行が出れば、GitHub の CI と同じチェックが通ったことになります。

結果

  • 1 回目:10 分ほど(Docker のイメージ作りなどがあるため)
  • 2 回目から:1 分ほど(テスト 約 2,000 件を、同時に 8 本で流す)
  • 流しているあいだは、PC が少し重くなる

つまずいた所 3:WSL を止めると Docker の連携が切れる

wsl --terminate Ubuntu や wsl --shutdown で WSL を止めると、Docker Desktop に「WSL integration with distro ‘Ubuntu’ unexpectedly stopped」と出て、Ubuntu から docker が使えなくなります。その画面の「Restart the WSL integration」を押すと戻ります(「Skip」を押すと戻りません)。設定を変えたあとなどで WSL を止めたときは、Docker Desktop の画面を見ておくと安心です。

気をつけること

  • WSL の既定を Ubuntu にすると、wsl とだけ打ったときの入り先が変わります。docker-desktop に入る前提のスクリプトがあれば、wsl -d docker-desktop のように名前を付けます。
  • Docker Desktop の設定を変えると、Docker Desktop が再起動し、動いていたほかのコンテナも一度止まります。自動で戻る設定(restart: always など)になっているかを確認しておきます。

自分のシステムでも使ってみた

せっかく Linux の環境ができたので、わたしが作っている業務システム(CakePHP・PHP 8.3)の全体の試験も、この Ubuntu で流してみました。ふだんは Windows の XAMPP で作っていますが、本番のサーバーは Linux だからです。本番と同じ PHP のバージョン(8.3.36)の Docker の箱を作り、git のコミットだけを Ubuntu の中にコピーして流しました(約 6,300 件・35 秒)。

分かったこと

  • Linux だけでエラーになる試験が 6 件:Linux の PHP にある posix の拡張が入っていると、試験の中の出力の扱いで警告になる作りでした。Windows の XAMPP には posix がないので、今まで見えていませんでした(本番の動きではなく、試験の作りの問題)
  • Windows では飛ばされていた試験 9 件が、Linux では流れて通った:XAMPP に入っていない拡張(sodium)を使う、署名の試験です
  • まっさらな場所で組み立てると、手動で作業したファイルが見つかった:いつもの作業フォルダーには、前に手動で作業したライブラリのファイルが残っていて、git にも Composer にも入っていないことに気づいていませんでした。サーバーの引っ越しのときに初めて気づくと大変なものでした
  • 心配していたファイル名の大文字と小文字・改行コード・パスの区切りのちがいで、エラーや失敗になったものは 0 件でした

Linux のちがいそのものより、「本番と同じ形のまっさらな環境で流す」ことに意味がありました。それからは、本番に反映する前に、毎回この箱で全体の試験を流すようにしています。

やってみて

GitHub の CI と同じチェックを、Windows の PC で 1 分ほどで流せるようになりました。プッシュする前に、そのコミットで流した最後の 1 行を、レビューに貼っています。

手順書には「WSL の Ubuntu の中に clone して流す」としか書いていなかったので、Docker の連携・Windows の .exe・Git の認証の 3 つは、実際にやってみて初めて分かりました。同じように Windows で Linux 前提のスクリプトを流したい人の参考になればうれしいです。

この記事を書いた人

フリースタイル

Web の仕事 25 年以上。WordPress の保守・引っ越しと、PHP の業務の仕組みづくり。 プロフィール →

まずは、お気軽にご相談ください。

相談と見積りは無料です。急ぎのときは、フォームで「急ぎ」を選んでください。