Windows 10 Homeで特定バージョンのPython保持しなければならなくなったので、その際やったことを記事にまとめます。
オーソドックスにWSL2でDockerを動かし、コンテナ上にPython環境を構築してみようと思います。
対象読者
開発初心者の方。特にPython。
そもそもWSLって? Dockerって名前は聞いたことあるけど、実際どんなものなの? という方にも(なるべく)理解してもらえる(といいなぁ)よう、頑張ります。
対象マシン
Windows 10 Home
x64システムの場合、バージョン 1903 以降、ビルド 18362 以上が必要です。
そもそも
なぜ特定バージョンのPythonを保持しなければならなくなったのかといえば、そのバージョンでしか(まともに)動かない機械学習Modelを作ってしまったからです。
だからPythonのアップデートはしたくないんだけど、別のModelでは別のバージョンを使いたい……なんてことは、Pythonの開発をやっていると稀によくあります。
pyenvなどでも1つのマシンに異なるバージョンを保持することができますが、Dockerのコンテナにプロジェクトの開発環境をまるっと保持してしまえばよりシンプルに、かつ移植性も高い環境を構築できるため、こちらを採用しました。
(ぶっちゃけpyenvよくわかってない)
でもその前に
ただ、初心者は特にですが、必要性がなければこんなことをする必要もないです。
機械学習といえばGPUだ! Ubuntuだ! となりいきなり壮大な環境構築を頑張ろうとして躓いて嫌になって……。てなるのも悲しいので。
それでもPythonの開発ではライブラリの導入を含めたトライ&エラーが頻発します。
そのたびにインストール&アンインストールを繰り返しているとローカルの開発環境がぐっちゃぐちゃに汚れ、このライブラリどこにパス通ってるんだ……? なんてことにもしばしば。
そうなったら新規一転、開発環境を仮想化してしまうのも手です。
あとは自然言語処理でMeCab使いたいけど、Windowsだと文字コードでバグりまくる……という場合も、簡単にLinux系の環境を用意できるのも利点ですね。
開発初心者の方はこんな風に、必要に迫られた段階でステップアップとして取り組むと良いと思います。
用語
何となく仮想環境を構築したい理由はわかったよ。じゃあWSLって? Dockerって? という方に。
-
Dockerとは
仮想化技術の一つです。
非常に手軽にWEBサーバーやAPサーバー、DBサーバーをデプロイできることからWEB開発の現場では広く使われている(らしい)技術です。おれWEB畑じゃないからね。
Hyper-VやVirtualBoxと何が違うの? と思われる方がいるかもしれませんが、これらは物理マシンのネットワークスイッチなどをエミュレートできるのに対し、DockerではベースとなるOSと完全に分離せず、OSのカーネル上にコンテナを配置する形をとります。
(前者をホスト型仮想化、後者をコンテナ型仮想化といいます)
例えばHyper-Vではホストとは異なるOSを積んだり、個別にネットワークアダプタを割り当てることが可能ですが、それらの点でいうとDockerは劣ります。
なのになぜDockerを使うのかと言われれば、やはりその軽量さ、手軽さが大きな理由でしょうか。
DockerではOS上にほかのプロセスと切り離された環境にコンテナを作るので、仮想環境の動作をホスト型仮想化よりも少ないリソースで実現できるのです。 -
WSL(2)とは
Windows Subsystem for Linuxの略で、そのまんま、Windows上でLinuxを動かすための技術です。
じゃあやっぱHyper-Vでいいじゃん! って感じですが、Windows 10 HomeじゃHyper-V使えないし、さらにいうとHyper-Vより少ないリソースでLinuxを動かすことができて、んでもって動作も軽量軽快。
個人的に一番違いを感じるのは起動ですね。
また今回はDocker Desktop for Winodwsという製品を使いたいのですが、本来こちらはHyper-Vの仮想化とネットワークを利用します。
前述の通りHomeではHyper-Vが使えないのですが、WSL2にUbuntuをインストールすることで、Docker Desktop for Windowsのバックエンドとして機能させることができるのです。
要はWSL2でUbuntuを動かして、そこにDockerをインストールするってことですね。
環境のイメージ
以上を踏まえ、今回はこんなイメージの環境を構築してみたいと思います。
やっと図が出てきた。
ホストのWindowsでWSL2を起動し、そこでUbuntuを動かします。UbuntuやDockerの制御はPowerShell等からでもできるのですが、今回はWindows Terminalからコントロールします。
そのUbuntu上にDocker(Docker Desktop for Windows)を導入。
Docker上にコンテナを配置し、それらを開発環境として利用します。
今回はAnacondaのDockerイメージをDockerHubから引っ張ってきます。DockerHubってのはDockerのコンテナを公開できる、GitHubみたいなもんだね。
んでAnacondaのコンテナでJupyter Labを動かし、Windowsのブラウザから操作したりプロジェクトをVS Codeでいじくったりできるようになろうってのが今回の目標です。
ちょっと注意
ここまで言っておいて水差すつもりはないんですけど、製品版のWindowsではWSL2をバックエンドとしたDockerコンテナではGPUを使えません。
(2021年3月19日現在)
Insider Previewならできるのですが、そちらは自己責任となりますのでご注意を。
自分はGPUを使うプロジェクトに関してはローカルでやりくりしています。
WSL2のインストール
やぁ、前置きがウルトラ長くなってしまった。
まずはWSL2のインストールからはじめましょ。
公式ドキュメント:https://docs.microsoft.com/ja-jp/windows/wsl/install-win10
コマンドラインからのインストールは現在(2021/3/19)プレビュー版でしか利用できないようです。
PowerShellの起動
Windowsの検索機能で「PoweShell」と入力します。表示されたアイコンを右クリックし、「管理者として実行」を選んでください。
Linux用Windowsサブシステム、仮想マシンの機能の有効化
起動したPowerShellから下記のコマンドを入力し、必要な機能を有効化します。
Linux用Windowsサブシステム
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
仮想マシンの機能
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
どちらもすぐに処理は完了すると思います。
Linuxカーネル更新プログラムパッケージのダウンロード
以下のリンクからLinuxカーネル更新プログラムパッケージをダウンロードします。
https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi
ダウンロードしたパッケージをダブルクリックし、インストールします。
手順に従って進み、以下の画面となればOKです。
WSL2を既定のバージョンとして設定
再度管理者としてPowerShellを開いて、次のコマンドを実行します。
wsl --set-default-version 2
新たにLinux系OSをインストールする際に使用するWSLの規定バージョンを2に指定しています。
これでひとまずWSL2の準備は完了。
Ubuntuのインストール
続いてはWSL2に乗っけるOS(Linuxディストリビューション)をインストールします。
WSL2ではDebian GNU/Linuxなどのディストリビューションも利用可能とのことですが、今回は機械学習の開発環境を構築することが目的なのでよく使われるUbuntuを使うことにします。
バージョンは16.04 LTS / 18.04 LTS / 20.04 LTSから選びます。
自分は20.04 LTSをインストールしますが、それ以外のバージョンでも手順は同じ(はず)です。
Microsoft StoreからUbuntuをダウンロード
スタートメニューから「Microsoft Store」を開き、検索窓に「Ubuntsu」と入力します。
(MSのアカウントでサインインしていなくてもDLできました)
Ubuntuの起動
インストールが完了すると「インストール」のボタンが「起動」に変わっているので、クリックしてUbuntuを起動します。
Ubuntuを起動すると初期化が行われ、続いてユーザー名とパスワードの入力が求められます。
ご自身のものを入力してください。
あとちなみにスタートメニューに「Ubuntu 20.04 LTS」が追加されていると思います。
起動状況の確認
念のためPowerShellからUbuntuの起動状況を確認しましょう。
(別に管理者権限で開かなくてもいいです)
以下のコマンドを実行してください。
wsl --list --verbose
これはWSLにインストールされているLinuxディストリビューションの一覧と起動状況、使用するWSLのバージョンを表示するコマンドです。
Ubuntu-20.04がVERSION「2」としてインストールされていますね。
大丈夫そうです。
Windows Terminalのインストール(おまけ)
これはオプションなので別にやらなくてもいいんですけど、自分はUbuntuの操作はWindows Terminalから行っています(結構使いやすい)。
Windows TerminalもMicrosoft Storeからインストールできますできます。
(検索窓に「Windows Terminal」と入力してください)
用途としてはUbuntuの制御がメインなので、起動時にUbuntuのシェルが立ち上がるよう規定値を変更します。
タブの「▽」をクリックし、「設定」を選択してください。
「Setting.json」というjsonファイルが開かれます。
上のほうに「defaultProfile」という項目があります。
ここに起動時に立ち上げたいシェルのguidを入力することで規定値を変更することができます。
少しスクロールすると「profiles」→「list」というところに各シェルの情報が格納されているのがわかります。
Ubuntuがインストールされていれば「"name": "Ubuntu-20.04"」の項目があるはずなので、そのguidをコピーし、先ほどのdefaultProfileの値に貼り付けます。
これでWindows Terminalを起動するとデフォルトでUbuntuのシェルが立ち上がるようになりました。
Docker Desktop for Windowsのインストール
バックエンド環境が準備できたところで、Dockerをインストールしましょう。
公式ドキュメント:https://docs.docker.jp/docker-for-windows/install.html
インストーラーのダウンロード
インストーラーはDocker Hubからダウンロードできます。
https://hub.docker.com/editions/community/docker-ce-desktop-windows/
「Get Docker」をクリックするとダウンロードが始まります。
特にSign upしなくてもDLできます。
インストール
ダウンロードしたインストーラーをダブルクリックして起動します。
「Install required Windows Components for WSL 2」にチェックし、「OK」をクリックします。
試しにDockerを起動してみましょう。
もちろん空っぽです。
このあとコンテナ入れるので、チュートリアルはスキップして良いです。
Dockerディスク領域の変更(オプション)
Docker Desktopをインストールすると問答無用でシステムドライブに仮想環境が作られます。
↑の手順でもマウントするパスの指定とかなかったしね。
コンテナを立てていくとCドライブの容量を圧迫してしまうので、データドライブに領域を移します。
なおWSLのインストール一覧は下記のコマンドで確認することができます。
wsl --list
Windows Terminalでの実行結果です。このとき接続先のシェルはPowerShellにしてください。
(先の手順でデフォルトがUbuntuになっているので)
領域を移したいのはこの「docker-desktop-data」ってやつです。
ちなみに上記のイメージの実態は %LocalAppData%\Docker\wsl\distro\ext4.vhdx
というものです。
エクスプローラーで %LocalAppData%\Docker\wsl\distro
と入力すると、 ext4.vhdx
というファイルがあります。
(多分デフォルトだと C:\Users\(ユーザー名)\AppData\Local\Docker\wsl\distro
とかじゃないかな)
あ、ちなみに vhdx
は VirtualHardDisk
って意味ね。
Docker / WSLの停止
まずはDocker Desktopを停止します。
タスクバーの「△」を選択し、Dockerのクジラみたいなアイコンを右クリックすると操作一覧が表示されるので「Quit Docker Desktop」を選択します。
続いてPowerShellで下記のコマンドを実行します。
wsl --shutdown
念のため起動状況を確認します。
wsl --list --verbose
STATEがすべて「Stopped」になっていればOKです。
データのエクスポート
docker-desktop-data
の移動先のフォルダを作っておきます。
データドライブに D:\01_Docker
というフォルダを予めつくっておきました。フォルダ名は気にしないでください。
下記のコマンドで、上記フォルダの中に docker-desktop-data.tar
というファイルをエクスポートします。
wsl --export docker-desktop-data D:\01_Docker\docker-desktop-data.tar
コンテナは空っぽの状態なんで、すぐに終わります。
docker-desktop-dataの登録の解除
WSLにおけるdocker-desktop-dataの登録を解除します。
wsl --unregister docker-desktop-data
.tarファイルのインポート
上記でデータドライブにエクスポートしておいた.tarファイルをインポートします。
D:\01_Docker
フォルダの直下に data
フォルダを作成します。
下記のコマンドを実行し、 D:\01_Docker\docker-desktop-data.tar
ファイルを D:\01_Docker\data
フォルダにインポートします。
> wsl --import docker-desktop-data D:\01_Docker\data D:\01_Docker\docker-desktop-data.tar
D:\01_Docker\data
フォルダに ext4.vhdx
が作成されています。
WSL / Dockerの起動
WSLとDockerを起動しましょう。
WSLはPowerShellで wsl
と入力すれば起動します。
DockerはアイコンをクリックすればOK。
Dockerコンテナの作成
ちょっと話が脇道にズレてしまいましたが、いよいよ最終目的である仮想開発環境を構築しましょう!
冒頭のイメージ図でもふれたとおり、今回はDocker HubからAnacondaのコンテナをダウンロードします。
作業フォルダの準備~Dockerfileの作成
Dockerではコンテナを作るときに Dockerfile
というファイルを作成し、そこにどんな構成のコンテナとするか~といった情報をコードとして記述します。
コンテナを立ち上げる時にDockerがこのファイルを参考にセットアップしてくれるんですね。
まずはそのコンテナにおける作業フォルダを作成します。
本格的な運用をする場合には1プロジェクトにつき1コンテナとすることが多いので、コンテナ名=プロジェクト名するのが分かりやすいでしょう。
今回は D:\Project\202103_TestProject
というフォルダを作成しました。
ここでは半角英数にしておいたほうが賢明です。
特に スペースは全角半角問わずやめておいたほうが良いでしょう。
作成したフォルダの直下で右クリック→新規作成→テキストドキュメントを選択します。
作成したファイル名を「Dockerfile」に変更します。
このとき、 「.txt」の拡張子を削除します。
Dockerfileに拡張子はないのです。
Dockerfileの記述
作成したDockerfileに「どんなコンテナを作るのか」という情報を記述していきます。
DOckerfileを選択し右クリック→プログラムから開くを選び、好きなテキストエディタから編集してください。
今回は次のような命令を記述していきます。
FROM continuumio/anaconda3:2019.03
RUN pip install --upgrade pip && pip install Keras && pip install tensorflow
WORKDIR /workdir
EXPOSR 8888
ENTRYPOINT ["jupyter-lab", "--ip=0.0.0.0", "--port=8888", "--no-browzer", "--allow-root", "--NotebookApp.token=''"]
CMD ["--notebook-dir=/workdir"]
一つ一つ見ていきましょう。
FROM continuumio/anaconda3:2019.03
ここでDocker Hubから「2019.03時点のAnaconda3を引っ張って来いよ」と明示しています。
RUN pip install --upgrade pip && pip install Keras && pip install tensorflow
その後実行するコードです。
イメージとしてはcmdから実行すべきコマンドを記述している感じ。
WORKDIR /workdir
命令を実行するときのカレントディレクトリを指定します。
上記によりコンテナに/workdir
が作成され、各種命令はこの中で実行されることになります。
EXPOSE 8888
ネットワーク上のポートを指定します。
ENTRYPOINT ["jupyter-lab", "--ip=0.0.0.0", "--port=8888", "--no-browzer", "--allow-root", "--NotebookApp.token=''"]
実行対象に関する設定です。
今回はコンテナ上で起動するJupyter LabをホストのWindowsから利用したいのでそれに関する設定を行っています。
ローカルで完結する環境を想定しているためトークン認証は無効としていますが("--NotebookApp.token=''")、例えばクラウドで立ち上げる等であれば設定が必要でしょう。
CMD ["--notebook-dir=/workdir"]
最後にJupyter labの作業ディレクトリを先ほど作成した/workdirに紐づけます。
以上で命令の記述は完了です!
保存してエディタを閉じます。
docker-compose.ymlファイルの作成
次にアプリケーションを構成するサービスを「Docker-compose.yml」というファイルに記述します。
今回はDockerの起動にはDocker Composeというツールを使用します。
これは複数コンテナを定義し、実行するDockerアプリケーションを管理するためのツールです。
YAMLというファイルにアプリケーションの各サービスの設定を記述することによって、Docker起動時にYAMLファイルを呼び出すだけで簡単にコンテナの生成、起動を行うことができます。
先ほど作成したDockerfileと同じディレクトリに、docker-compose.yml
というファイルを作成してください。
そこに以下のように記述します。
services:
dev:
build:
context: .
dockerfile: Dockerfile
image:project01
ports:
- "8080:8888"
volumes:
- .:/workdir
imageにはご自身のプロジェクト名を入力してください。
また起動対象となるDockerfileもbuild内で指定します。そのためdocker-compose.ymlとDockerfileは同じディレクトリにないといけませんので、注意。
Dockerfileと同じくvolumesには作業ディレクトリとして/workdirを指定しましょう。
ちなみに今回は割愛しますが、docker-compose.ymlファイルを使用しなくとも、シェルからdocker run
というコマンドを実行しても起動できますよ。
コンテナの起動
これでコンテナを起動する準備ができました。
Powershellを起動し、カレントディレクトリをDockerfile、docker-icompose.ymlが置かれたフォルダに移動します。
cd D:\Project\202103_TestProject
続いて下記のコマンドを実行します。
docker-compose up
Jupyter Labの起動
WindowsからコンテナのJupyter Labに接続しましょう。
コンテナが起動した状態で任意のブラウザを起動し、localhost:8080
と入力してください。
Jupyter Labが起動すれば成功です!
Jupyterのナビゲーターを見ればわかる通り、JupyterのカレントディレクトリはそのままDockerfile、docker-compose.ymlが置かれたフォルダとなっています。
このフォルダの中身をコンテナは認識してくれますので、試しにこの直下に「01_Input」「02_Source」「03_Model」「04_Output」というフォルダを作成してみます。
今度は逆にJupyter LabからPythonのNotebookを作ってみましょう。
「02_Source」に入り、Python Notebookを作成します。
Windows側のエクスプローラーから「02_Source」の中を見ると、作成した.ipynbファイル(とチェックポイント)があることが分かります。
これで無事WindowsとDockerコンテナの同期が取れていることが確認できました!
お疲れ様です、全作業完了です!
あとはもう、イカしたModelを作りまくって世の中に貢献しちゃってください。