Dockerfile が書けない人のための環境構築方法
もう環境構築で悩まされたくない!そう願ってデータ分析においても Docker を使って環境構築する人が多くなってきたのではないでしょうか。
ただ、
Kaggle のイメージは重すぎ
必要最低限のパッケージが入った自分の研究用の環境を構築したい
こう思う人も多いはず。
一方で Docker 初心者にとっては
Dockerfile の書き方がわからん。
という問題があります。(私だけ?)
どうするか色々悩んで調べて、「Poetry
と Docker を組み合わせる」という方法に行き着きました。
環境構築にあたり、以下の記事を大いに参考にさせていただきました。
イメージはこんな感じで、Poetry で自分の好きなパッケージをインストールし、作ったオリジナル環境 (virtualenv)を、Docker上に構築する。
環境は github にアップロードしています。
Poetry とは
日本語訳もあります
Poetry とは、Python のパッケージ管理ツールのことで、Python で何か新しいパッケージをインストールする際、既にある環境に合わせて最適なバージョンのものを勝手にインストールしてくれる*1大変ありがたいやつです。
Python のパッケージ管理ツールとしてはこれまで Pipenv
が有力でしたが、lock ファイルの構築が遅かったりするらしく新鋭の Poetry を雄す記事も見かけるようになりました。
ここでは Poetry を使っていますが、Pipfile を使ってもほぼ同様に環境構築ができるはず。
簡単な使い方
コマンドリストはシンプルでわかりやすいので、見てみることをお勧めします。
基本
pip install
の代わりにpoetry add
pip uninstall
の代わりにpoetry remove
最初このようにいくつかパッケージのバージョンを指定するとする
$ poetry add sklearn=="0.23.1"
後はバージョンを指定しなくても勝手に依存関係を踏まえた最適なバージョンを入れてくれる
$ poetry add pandas
パッケージをインストールする際の依存関係は lock ファイル(poetry.lock
)に記録される。
gitなどで pyprojeck.toml
と poetry.lock
が共有されていれば、そのディレクトリをそのまま自分の手元へクローン(コピー)し、以下のコマンドを実行すれば、その環境がそのままインストールされる。
$ poetry install
この環境を Docker 上で行うというわけだ。
Docker を用いた環境構築方法
- Poetry が入ったまっさらなコンテナを構築する
- コンテナ内のターミナルに入り、好きなパッケージをインストールする
- 保存し、コンテナ環境をアップデートする
Dockerfile はこのように、最もシンプルな python:3.7-slim
のイメージを元に作成されています。
FROM python:3.7-slim ENV PYTHONUNBUFFERED=1 WORKDIR /workspace COPY poetry.lock pyproject.toml ./ # Git のインストール RUN apt-get update && apt-get -y install git # poetry のインストール RUN pip install poetry # Poetry で導入したパッケージ(pyproject.toml)を全てインストール RUN poetry config virtualenvs.create false \ && poetry install RUN pip install jupyter_contrib_nbextensions && \ jupyter contrib nbextension install --user && \ jupyter nbextension enable highlight_selected_word/main &&\ jupyter nbextension enable hinterland/hinterland && \ jupyter nbextension enable toc2/main
コメントアウトにて書いてあるまんまですが、
COPY poetry.lock pyproject.toml ./
にて環境構築に必要な2つのファイルを Docker 環境にマウントし、
RUN pip install poetry
にて poetry を Docker にインストールします。
RUN poetry config virtualenvs.create false \
&& poetry install
Poetry は自動で virtualenv を作成し、そこに環境を構築してくれますが Docker内に仮想環境を作ってもしょうがないので virtualenv 作成を false
とします。
そして、RUN poetry install
により pyproject.toml
に既に記載のパッケージをインストールするよう、Docker に命令させます。
というわけで、実際に環境構築。
1. Poetry が入ったまっさらなコンテナを構築する
ディレクトリ内にて、以下コマンドより イメージのビルド → コンテナの起動
$ docker-compose up build
一番最初の段階では、 poetry に何も書かれていないので何もインストールされないです。
と言いたいところですが、poetry には先に Scikit-learn (バージョン管理の説明の便宜上)と、JupyterNotebook 使用を想定して Jupyter 環境と、必須な拡張機能をいくつかインストールしています。
[tool.poetry.dependencies] python = "^3.7" scikit-learn = "0.23.1" [tool.poetry.dev-dependencies] autopep8 = "^1.5.2" jupyter = "^1.0.0" jupyter-nbextensions-configurator = "^0.4.1" jupyter-contrib-nbextensions = "^0.5.1" jupyterthemes = "^0.20.0"
Dockerfile の以下の部分で、拡張機能を有効化
RUN pip install jupyter_contrib_nbextensions && \ jupyter contrib nbextension install --user && \ jupyter nbextension enable highlight_selected_word/main &&\ jupyter nbextension enable hinterland/hinterland && \ jupyter nbextension enable toc2/main
入れている拡張機能
- 入力補完
- 変数のハイライト機能
- 目次
拡張機能について詳しくはこちらの記事
Jupyter 知っておくと少し便利なTIPS集 - Qiita
コンテナが立ち上がると同時に、Jupyter Notebook ブラウザが起動するので https://
から始まる部分を丸ごとコピーしてブラウザに貼り付ければ JupyterNotebook にアクセスできます。
2. コンテナ内のターミナルに入り、好きなパッケージをインストールする
コンテナ内のシェル(bash)に入るためのコマンドは
docker exec -it [CONTAINER ID または CONTAINER NAME] /bin/bash
docker-compose.yaml
にて コンテナ名を指定しています
services: app: container_name: "poetry-example"
JupyterNotebook が起動しているターミナルとは別に、新しいターミナル(タブ)を開いて、以下を打つ
$ docker exec -it poetry-example /bin/bash root@2c8334962160:/workspace#
念のため、CONTAINER NAME または CONTAINER ID を確認するには以下のコマンド
# CONTAINER ID を確認 $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aac318175543 poetry_example_app "jupyter notebook --…" 3 minutes ago Up 3 minutes 0.0.0.0:8881->8881/tcp poetry-example
今 Poetry にインストールされているパッケージを以下のコマンドで確認できます
$ poetry show
新しいパッケージをインストール
$ poetry add numpy pandas
ここで pyproject.toml
を見てみると、最初はなかった pandas と numpy がバージョン指定された状態で上書きされていることがわかります。
[tool.poetry.dependencies] python = "^3.7" scikit-learn = "0.23.1" numpy = "^1.19.2" pandas = "^1.1.3"
あとは自分の好きなパッケージを入れていけば、好きな環境ができあがります。
3. 保存し、コンテナ環境をアップデートする
poetry.toml を保存し、ターミナルを Control + C で一旦コンテナを停止させます。
そして再び
$docker-compose up --build
を実行しましょう。そうすることで、Dockerfile の poetry install
が実行され、先ほど追加したパッケージが反映された新しいPoetry 環境ができあがることになります。
インストールに失敗した場合
ここで、たまにパッケージインストールに失敗することがあります。
そんな時は、インストールに必要な linux のソフトウェアが足りないと言われていることが多いです。
ここでは、
error: command 'gcc' failed with exit status 1
つまり gcc というコマンドが足りないと言われているので、ネットで 「error: command 'gcc' failed with exit status 1」と検索しましょう。そしたら必ず、誰かがコマンドを教えてくれています。
今回の場合だと例えば Dockerfile に
RUN apt-get -y install gcc python3-dev python3-pip libxml2-dev libxslt1-dev zlib1g-dev g++
と書いて保存 → もう一度イメージのビルドからコンテナを起動し直す → poetry add
というステップを踏みましょう
(つぶやき)
このようなインストールエラーに遭遇して検索した回答のほとんどが linux ベースの記法(apt-get install
)で、pip install
とは互換性がない。
Docker を使っていて個人的にありがたいと思うのは、Docker 環境そのものは Linux ベースなのでこのコマンドをそのまま Dockerfile にコピペできること。
最後に
ここまで読んでくださりありがとうございました!
Docker でデータ分析を行う方々の参考になれれば嬉しいです。
*1:カッコよく言えば、依存関係を解決してくれる