【Windows】DockerでPythonアプリケーションをビルドする方法
背景
年に一度しか更新されず、前置きが長いポエミーな本ブログで未だによく見られている記事にGUIアプリを作る話があったので、折角ならもうちょっとモダンに何とかできないかと。 思い至ったので、実際に作ってみました。
ところで、私は普段WindowsでAnacondaを使ってPythonを使っているのですが、Anaconda+PyInstallerという組み合わせは非常にまずい組み合わせであります。 何がまずいかと言えば、ファイルサイズです。 Anacondaは依存関係が異常に複雑で、特に依存ライブラリのないプログラムであっても、PyInstallerを使ってExeを作ると200MB近いファイルサイズになってしまいます。 それにPySideや何やら入ってしまうと、どんどんファイルサイズが大きくなってしまいます。
それは何とも残念な話ですので、通常のPythonにPyInstallerをインストールしてビルドすれば、ファイルサイズの増大を回避できますが、いくらvenvをインストールしてやったとしても、それは何かと面倒なことがあります。 まず、新規でアプリケーションを作る度にvenvで環境を作るというのも良いと思いますが、個人的にいつもrequirements.txtの書き忘れが問題になります。 Linuxならpipenvを使えばそれも回避できますが、Windowsでpipenvはまともな動きをしてくれないので、それもダメです。
はてさてどうしたものかとなりますが、いい感じにやる方法にDockerがあります。 Dockerの説明はもう良いでしょと思うので割愛しますが、Dockerを使えば使い捨てのビルド環境が作れるのでいい感じにやれるなと思って今回の記事のようなものを作りました。
Windows container on Windows
Windows環境でWindow Containerを動かすのってどうやんの?って思ったので調べたのですが、タスクトレイのDockerを右クリックして出てくるメニューから切り替えられるそうです。 非常に簡単でありますね。ちなみに、WindowsコンテナとLinuxコンテナは同時に使えない問題があるそうですが、まあそれはそれということでしょうか。
ちなみにですが、Windowsコンテナのライセンスってどうなってんの?ってなことも気になって調べましたが、開発用途なら特に使用に制約は無いようです(ないよね?) docs.microsoft.com
Dockerfile
適当なアプリケーションをビルドする用のDockerfileは下記のとおりです。 pythonのソースコードと同じディレクトリにファイルを保存している前提で、以下のようなDockerfileを書きました。
FROM winamd64/python:3.8.3-windowsservercore-1809 # /tmpにソースコードを展開して必要なファイルをインストール # 事前にrequirements.txtをコピーして必要なライブラリをインストールして # キャッシュしておく。 WORKDIR /tmp COPY requirements.txt /tmp RUN pip install -r requirements.txt RUN pip install pyinstaller # それ以外のソースコードをホストからコピーしてpyinstallerを実行する。 COPY . /tmp RUN pyinstaller Main.spec WORKDIR /app RUN cp -r /tmp/dist/* . RUN Remove-Item -Path /tmp -Recurse -Force RUN mkdir /mount ENTRYPOINT cp -r -Force * /mount
ちなみに使っているpyinstallerのspecファイルは以下の通りです。 依存ライブラリとしてeelを使うアプリケーションを考えているので、ライブラリのインストールディレクトリからdataファイルに追加するようにしています。
# -*- mode: python -*- import eel from pathlib import Path path_to_eel_js = Path(eel.__file__).parent / 'eel.js' block_cipher = None a = Analysis( ['./app/__main__.py'], pathex=[], binaries=None, datas=[ (str(path_to_eel_js), './eel/') ], hiddenimports=[ 'pkg_resources.py2_warn', 'eel', 'bottle_websocket' ], hookspath=None, runtime_hooks=None, excludes=None, cipher=block_cipher ) pyz = PYZ( a.pure, a.zipped_data, cipher=block_cipher ) exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name='ClipDraw', debug=False, strip=None, upx=True, console=True, #icon='mainIcon.ico' ) app = BUNDLE( exe, name='app.exe', #icon='mainIcon.ico' )
これだけで勝手にexeファイルができます。
コンテナの使い方
実際にはDockerファイル内でビルドしたパッケージをローカルにダウンロードする必要があるので、以下のコマンドでホストにコピーする必要があります。
docker run --rm -it -v ${pwd}\build:C:\mount python-build-env:latest
ちなみに上記はpowershellで実行するケースでたぶんcmdだと下記のようになります。
docker run --rm -it -v %cd%\build:C:\mount python-build-env:latest
これでWindows環境で動くPythonアプリケーションが出来上がるはずです。 LinuxやMacでも基となるOSをそろえてやれば(例えばLinuxならPython:3.8-busterとか)同様の手順でアプリケーションを浮くることができるはずです。