Windowsでもコンテナを使いたい! WSLで「Docker」に入門しよう

はじめに
今どきのアプリケーション開発において、避けては通れないトレンドとなっているのが「コンテナ」です。そして、その中でも世界で最も利用されているコンテナ実行環境が「Docker」ではないでしょうか。
Dockerは、自身を「アプリケーションを開発、転送、実行するためのプラットフォーム」と位置づけています。Dockerはアプリケーションの実行環境一式をカプセル化し、ポータビリティを持たせる技術です。これにより、環境に左右されず同じ条件でアプリケーションを動かすことができ、効率の良い開発やデリバリーを実現できるというわけです。
第4回で少し触れた通り、Dockerとユニバーサルパッケージは非常によく似た設計思想を持っています。コンテナと言えば軽量な仮想環境というイメージを持っている方も多いかもしれませんが、Dockerはむしろパッケージシステムに近い存在だと言えるでしょう。
DockerはLinuxカーネルの機能を利用しているため、Linuxでなければ動かすことはできません。そのためWindows上でDockerを使うには仮想マシンを併用するのが定石でしたが、現在ではより高速に動作するWSL(WSL2)が存在するため、これを利用しない手はないでしょう。
今回はWSLを使って、Windows上でDockerを動かす方法を解説します。
Docker Desktopとは
WindowsやmacOSでDockerを動かそうと思った際、最初に候補に上がるのがDocker Desktopではないでしょうか。Docker DesktopはDocker Engine、クライアントとなるdockerコマンド、GUIフロントエンド等々のDocker実行環境をオールインワンで提供するプロダクトです。その特徴として内部的に仮想マシンを起動し、Dockerを動かしているという点が挙げられます。
Docker Engineを仮想マシンで提供することより、Windows/macOS/Linuxが混在する環境でも同じバージョンのDocker Desktopをインストールすれば開発環境を同一に揃えることができるのです。これは大規模なチームによる開発プロジェクトにおいて、非常に大きなアドバンテージとなります。
従来のWindows版のDocker DesktopはバックエンドとしてHyper-Vの仮想マシンを利用していましたが、WSLがインストールされている環境であれば、代わりにより軽量で高速なWSLを利用できます。
Docker Desktopのインストールと起動
それでは、実際にDocker Desktopをインストールしてみましょう。なお、まだWSLをインストールしていない場合は、第1回を参考に、事前にWSLのインストールを済ませておいてください。
Docker Desktopのインストールドキュメントを参考にWindows用のインストーラーをダウンロードして実行してください。以下の構成オプション画面が表示されます。バックエンドにWSL2を利用するので「Use WSL2 instead of Hyper-V」にチェックが入っていることを確認してください(現在ではWSLの利用が推奨されているため、デフォルトでチェックが入っているはずです)。
なお、Hyper-Vが使えない環境(具体的にはWindows 11 Home)ではバックエンドを選択できないため、この選択肢は表示されず自動的にWSLが使用されます。
そのまま画面の指示に従ってインストールを進め、完了するまで待ちましょう。以下の画面が表示されたら「Close and restart」をクリックします。Windowsが即座に再起動されるので気をつけてください。
再起動が完了したら、Docker Desktopを起動しましょう。初回起動時は以下のダイアログが表示され、Docker Subscription Service Agreementへの同意を促されます。内容を確認した後、問題がなければ「Accept」をクリックします。Docker Desktopは一定以上の規模の企業では有償サブスクリプションプランの契約が必要となります。業務で利用する場合はくれぐれも気をつけてください。
この段階でWSL内に「docker-desktop」という名前のディストリビューションがインストールされており、ここでDockerが起動しています。PowerShellを起動して以下のコマンドを実行すると、その存在を確認できます。
$ wsl --list
後述しますが、CLIで実行するdockerコマンドもWindows上のPowerShellから直接実行可能です。そのため、本連載で使ってきたUbuntuなどとは異なり、ユーザーが直接このディストリビューション内にログインして操作することはありません。あくまで、Docker DesktopのバックエンドとしてDocker Engineを動かすためのものとなります。通常の利用の範疇においては、その存在を意識する必要もないでしょう。
Dockerコンテナを動かす
ここまでの操作だけで、WSLをバックエンドとしてDockerコンテナを動かせます。試しにnginx Webサーバーをコンテナで動かしてみましょう。
Docker Desktopを起動したら、ウィンドウ上部にある検索ボックスに「nginx」と入力してください。複数のイメージがヒットしますが(おそらく)、一番上に表示されているであろう公式のイメージを選択します。「Run」をクリックしてください。
コンテナを起動しようとすると、以下のウィンドウが表示されます。nginxのコンテナは、ホストが待ち受けるポート番号やコンテナ内にマウントするボリュームを起動時に指定できます。これはその設定を行うためのウィンドウです。ここではコンテナに「nginx」という名前を付け、ホストのポートに「8080」を指定しました。設定値を入力したら「Run」をクリックしてください。
これだけでコンテナが起動します。WindowsでWebブラウザーを起動して「http://localhost:8080」*1にアクセスしてみましょう。nginxのサンプルページが表示されたら成功です。
*1: コンテナの起動時に異なるポートを指定した場合は、ポート番号を適宜変更してください。たったこれだけで、Windows上でも簡単にDockerを動かせることが理解いただけたのではないでしょうか。Docker Desktop自体のより詳しい使い方はドキュメントを参照してください。
コマンドラインからDockerを使う
Docker Desktopのメリットの1つはGUIから操作できる点ですが、「普段からコマンドラインを使っているためCLIでも操作したい」「自動化したいのでマウス操作は困る」といった方もいるでしょう。Docker DesktopにはCLIツールであるdockerコマンドも同梱されているため、コマンドラインからの操作も可能です。
PowerShellを起動して、以下のコマンドを実行してみましょう。先ほどpullしたnginxのコンテナイメージや、(コンテナを終了していなければ)起動中のnginxのコンテナが表示されます。
$ docker images $ docker ps
少し内部の仕組みを見てみましょう。以下のコマンドを実行してください。
$ docker context inspect
dockerコマンドは、Docker Engineとの通信に必要になるエンドポイント情報やセキュリティ情報などを「コンテキスト」という単位で管理しています。dockerコマンドは使用するコンテキストを切り替えることで複数のDocker Engineと通信できるのです。
Docker Desktopをインストールすると「desktop-linux」という名前のコンテキストが作成され、デフォルトでこれを利用するよう設定されていることが分かります。また、そのエンドポイントとしてWindowsの名前つきパイプである「\\.\pipe\dockerDesktopLinuxEngine」が指定されています。この名前つきパイプを経由して、WSL内のDocker Engineと通信を行っているというわけです。
WSL内のLinux空間から
Docker Desktopを使う
コマンドラインからもDockerを使えることは先に述べた通りですが、普段からLinuxサーバーに慣れている方からすると「PowerShellはちょっと不慣れで…」「やっぱりコマンドはLinuxのBashから操作したい」という方も多いのではないでしょうか(筆者もそうです)。せっかくWSLディストリビューションとしてUbuntuがインストールされているのですから、UbuntuのシェルからDocker Desktopを利用できたら便利ですよね。実はできるのです。
Docker Desktopのウィンドウを開いたら、右上にある歯車のアイコンをクリックして設定を開きます。左ペインから「Resources」→「WSL integration」を選択すると以下の画面が表示されるので、「Enable integration with my default WSL distro」にチェックを入れてください。これでデフォルトのWSLディストリビューション(本連載の通りにインストールしているのであればUbuntu 24.04)において、Docker Desktopとの連携設定が行われます。
もし複数のディストリビューションをインストールしており、個別に連携設定を行いたい場合は「Enable integration with additional distros」を個別にオンにしてください。
「Apply & restart」をクリックして設定を適用したら、連携を設定したWSLのLinuxディストリビューションを起動してください。インストール作業を行っていないにもかかわらず、dockerコマンドが使えるようになっていることに気づくでしょう。
/usr/bin/dockerコマンドの実体を調べてみると、/mnt/wsl以下にマウントされたファイルへのシンボリックリンクとなっていることが分かります。このファイルの実体はWindows上にある「C:\Program Files\Docker\Docker\resources\wsl\docker-wsl-cli.iso」というISOイメージ内に含まれています。Windows上にインストールされたISOイメージをループバックマウントすることで、WSLのLinux内から利用可能にしているというわけです。
また、Linux内からdocker contextを確認するとエンドポイントが「/var/run/docker.sock」というUnixドメインソケットに向いていることが分かりますが、Docker Desktopがこのソケットをプロキシしているため、docker-desktopディストリビューションのDocker Engineと通信できるようになっています。

WSLのUbuntu内からdockerコマンドを実行した例。先ほどWindows上でpullしたイメージや実行中のコンテナが表示される。つまり同一のDocker Engineと通信できていることが分かる
Docker DesktopのWSL連携を使うことで、クライアント環境としては好みのディストリビューションを使いつつ、Windows/WSL間で共通のDocker Engineを利用できるのです。
Docker Desktopを使わない方法
このように至れり尽くせりなDocker Desktopですが、企業での利用となると、そのライセンスが問題となることもあります。大規模な企業の業務では無償利用ができないため、現場レベルで気軽に試すといったことができません。
勘違いされる方も多いのですが、こうしたライセンスが課されているのは「Docker Desktop」です。コンテナの実行に必要なDocker Engine自体はApache License 2.0で公開されているオープンソースソフトウェアのため自由に利用できます。つまり、Docker Desktopを使わずにDocker Engineをインストールすれば良いということになります。そしてUbuntuにはDockerのパッケージが用意されており、WSLの中でも動かすことができます。
Ubuntuのシェルを起動したら、以下のコマンドを実行してください。なお、Ubuntu内に直接Dockerをインストールする際は意図しないトラブルを避けるため、Docker DesktopのWSL連携は無効にしておきましょう。あるいはDocker Desktop自体をアンインストールしてしまっても良いでしょう。
$ sudo apt install -U -y docker.io
これだけでDockerが動き出します。前述と同様に、nginxのコンテナを動かすには以下のようにコマンドを実行してください。なおUbuntuのパッケージからDockerをインストールした場合、dockerコマンドの実行にはroot権限(sudoコマンド)が必要になります。
$ sudo docker run -p 8080:80 -d nginx
先ほどと同様に、WindowsのWebブラウザーから「http://localhost:8080」にアクセスしてみましょう。WSLでは自分(Windows)宛ての通信をWSLが動作している仮想マシンへ転送する仕組みがあるため、これで問題なくコンテナ内と通信できます。
おわりに
現在のDocker DesktopはWSLとシームレスに連携できるようになっています。これにより、複雑なインストール手順や設定をせずともWindowsで高速なコンテナ実行環境を整えることができます。また、現在のWSLディストリビューションはsystemdが動作するようになっているため、Docker Desktopを使わず、一般的なLinuxディストリビューションと同様にDockerを動作させることも簡単です。
本連載の開始時にも述べましたが、本番環境はLinuxであるものの「開発用のデスクトップにはWindowsを使いたい」というニーズは多いでしょう。そしてWSLとDockerは、こうしたニーズを満たすために最適だと言えるのではないでしょうか。
次回は、WSL+Dockerの活用例として、Visual Studio Codeを利用したWindows上でのリモート開発について解説します。