Dockerでデータ分析環境を作ってみる
MacBookのキーボード問題とかで躊躇していたら、この前いきなり電源が落ちてそろそろ新しいの買うべきかと追い詰められてます。
以前から、統計やニューラルネットの勉強のために自宅マシンでJupyterを使っていましたが、歴史的経緯でAnaconda、pyenv、virtualenv、pipenvと色々ごちゃごちゃしてきました。
このような状態は気持ち悪いので、勉強ついでにデータ分析環境をDockerで構築してみます。

Dockerエンジン/クライアントのインストール
Docker docs
https://docs.docker.com/install/
Linux:
Linux系の各ディストリビューションは公式の通りで問題なくインストールできると思います。日本語の記事も多いので、詳細は省きます。
Dockerはその仕組み上、ホストOSはLinuxであることが望ましいのですが、まあそうは言ってられない事情はあると思います。私も普段はMacを使っていますし…
公式からMac向けとWindows向けのDocker構築環境をダウンロードできます。
macOS:
Macは「Docker Desktop for Mac」をインストールします。こちらも上記リンク先の公式の手順通りでインストールできると思いますし、日本語のインストールしてみた記事もいくつかあるようです。
ただ、ダウンロードにDockerのアカウントを取る必要があると思います。
Windows:
WindowsはMacと同様「Docker Desktop on Windows」というのがあります。こちらも公式ドキュメントに手順がありますが、システム要件がWindows10のProかエンタープライズで、Hyper-V対応している必要があるなど、個人ではちょっと敷居が高いかもしれません。
Windows 10 64-bit: Pro, Enterprise, or Education (Build 15063 or later).
Docker Desktop on Windows
Hyper-V and Containers Windows features must be enabled.
https://docs.docker.com/docker-for-windows/install/
Windows10は必要ですが、HomeエディションでもWSL(Windows Subsystem for Linux)を使ってUbuntuを入れてから、Dockerというのも試している途中なので、上手くいったらまた記事にしてみます。
構築方針
要件
- データ分析環境を作る
- Dockerを使い、環境の構築は一元化しつつも、複数の人が手元のPCで分析タスクを行える
- 言語はPythonとRを使えるようにする
- Jupyterを使用
- とりあえず動くことを優先して、細かな調整は後から行う
ベースイメージ
まずベースとなるイメージを決めますが、今回は「Ubuntu 18.04」にします。
LTSがついてるバージョンなので比較的安定して長期運用できるというのと、それ故に情報が比較的多いのがメリットかなって思います。
Docker Hubには「16.04」や「19.01」というタグも見えます(2019/09/02時点)
Docker Hub – Ubuntu
https://hub.docker.com/_/ubuntu
Pythonのバージョン
3.7.xが最新ですが、今回は動かすことを優先して3.6.xで構築します。
pyenv経由でバージョンを指定して、インストールします。
pipでインストールするパッケージを「requirements.txt」にまとめてインストールします。
追々pipenvにするかもしれません。
Pythonのライブラリ
主要なものはとりあえず入れておきます。
- autopep8
- h5py
- jupyter
- jupyter_contrib_nbextensions
- matplotlib
- mysql-connector-python
- numpy
- pandas
- Pillow
- plotly
- psycopg2
- scikit-learn
- scipy
- seaborn
- sympy
まずは手動で構築
コンテナの元となるイメージは「Docker Hub」という場所に登録されています。
Docker HubはDocker社が運営しているDockerイメージのリポジトリで、アカウントを作成したら誰でもイメージを登録できます。
Docker Hub
https://hub.docker.com
誰でも登録/公開できるので、誰が公開しているイメージか確認してから利用するようにした方が良いでしょう。
pipのrequirements.txtを作成するため、一度手動で環境を作って、Dockerfileにまとめる形をとります。
ベースイメージを取得
docker pullはDocker Hubからイメージを取得するコマンドです。
イメージ名「ubuntu」のあとにコロンをはさんで、タグとして「18.04」を指定することでバーションの指定ができます。
$ docker pull ubuntu:18.04
取得したイメージを確認
docker imagesコマンドで、取得したイメージを確認します。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 a2a15febcdf3 2 weeks ago 64.2MB
イメージからコンテナを作成
ダウンロードした、イメージからコンテナを作成して起動します。
$ docker run -it --name=analysis_try ubuntu:18.04 /bin/bash
コマンドの意味
「ubuntu:18.04」のイメージを使って、analysis_tryという名前のコンテナを作成。
「-it」オプションでコンテナとホストのコンソールを繋げる。
最後の「/bin/bash」でシェルを起動して、ホストからコンテナにシェルコマンドを打てるようにする。
上記コマンドでコンテナが作成後起動して、以下のような表示になり、シェルコマンドが打ている状態になります。
root@8120a0d82344:/#
最新の状態にする
# apt-get update -y && apt-get upgrade -y
必要なパッケージをインストール
# apt-get install -y tzdata build-essential curl git libbz2-dev libffi-dev liblzma-dev libncurses5-dev libncursesw5-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev llvm make tk-dev unzip vim wget xz-utils zlib1g-dev
pyenvでpythonをインストール
# cd /root
# mkdir -p .pyenv
# mkdir -p local/bin/python-3.6.9
# git clone https://github.com/pyenv/pyenv.git .pyenv/
# ./.pyenv/plugins/python-build/install.sh
# /usr/local/bin/python-build -v 3.6.9 ./local/bin/python-3.6.9
# echo 'export PATH="$HOME/local/bin/python-3.6.9/bin:$PATH"' >> ~/.bashrc
# source .bashrc
# python -V
Python 3.6.9
pipでパッケージをインストール
# pip install -U pip
# pip install autopep8 h5py jupyter jupyter_contrib_nbextensions matplotlib mysql-connector-python numpy pandas Pillow plotly psycopg2 scikit-learn scipy seaborn sympy
# pip freeze > requirements.txt
ホストにrequirements.txtをコピー
ホストに戻って、
# exit
requirements.txtをホストにコピーして、
$ docker cp analysis_try:/root/requirements.txt ./
とりあえず作ったコンテナを削除します。
$ docker rm analysis_try
ホストのディレクトリ構造
今回はホストのディレクトリ構造は以下のように作りました。
- libs:各種パッケージの.lock系のファイルを置くディレクト
- notebooks:JupyterのHOMEディレクトリ。notebook等を置くディレクトリ
- data:分析に必要なデータを置くディレクトリ
- example:各種分析のサンプルノートを置くディレクトリ
analysis/
├── Dockerfile
├── libs/
│ └── requirements.txt
└── notebooks/
├── Pandas.ipynb
├── README.md
├── data/
└── example/
Dockerfileを作る
上記、analysisの下にDockerfileを作ります。
こんな感じにしてみました。
tzdataを入れる時に、タイムゾーンの選択を求められます。これを回避するためちょっとしたトリックを使ってます。
別のもっとシンプルな回避方法があるという情報もあったので、後から試してみる予定です。
あとはjupyterへのアクセスでポートを8000にしましたが、お好きなポートに変えて良いと思います。
FROM ubuntu:18.04
ENV PYTHON_VERSION 3.6.9
ENV HOME /root
# PYTHON
ENV PYTHON_ROOT $HOME/local/bin/python-$PYTHON_VERSION
ENV PATH $PYTHON_ROOT/bin:$PATH
ENV PYENV_ROOT $HOME/.pyenv
# Jupyter Notebook config
ENV JUPYTER_CONFIG /root/.jupyter/jupyter_notebook_config.py
ENV WORK_DIR /notebooks
RUN apt-get update && apt-get upgrade -y \
&& apt-get install -y tzdata
# timezone setting
ENV TZ=Asia/Tokyo
RUN apt-get install -y tzdata \
build-essential \
curl \
git \
libbz2-dev \
libcurl4-openssl-dev \
libffi-dev \
liblzma-dev \
libncurses5-dev \
libncursesw5-dev \
libpq-dev \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
libxml2-dev \
llvm \
make \
r-base \
tk-dev \
unzip \
vim \
wget \
xz-utils \
zlib1g-dev \
&& apt-get autoremove -y && apt-get clean \
&& git clone https://github.com/pyenv/pyenv.git $PYENV_ROOT \
&& $PYENV_ROOT/plugins/python-build/install.sh \
&& /usr/local/bin/python-build -v $PYTHON_VERSION $PYTHON_ROOT \
&& rm -rf $PYENV_ROOT
# install additional packages
COPY libs/requirements.txt requirements.txt
RUN pip install -U pip && pip install -r requirements.txt \
&& jupyter contrib nbextension install --user \
&& jupyter nbextensions_configurator enable --user \
&& jupyter notebook --generate-config --allow-root \
&& echo "c.NotebookApp.ip = '0.0.0.0'" >> ${JUPYTER_CONFIG} \
&& echo "c.NotebookApp.port = 8000" >> ${JUPYTER_CONFIG} \
&& echo "c.NotebookApp.open_browser = False" >> ${JUPYTER_CONFIG} \
&& echo "c.NotebookApp.allow_root = True" >> ${JUPYTER_CONFIG} \
&& echo "c.NotebookApp.token = ''" >> ${JUPYTER_CONFIG} \
&& echo "c.NotebookApp.iopub_data_rate_limit=10000000000" >> ${JUPYTER_CONFIG} \
&& echo "c.MultiKernelManager.default_kernel_name = 'python3.6'" >> ${JUPYTER_CONFIG} \
&& echo "c.IPKernelApp.pylab = 'inline'" >> ${JUPYTER_CONFIG} \
&& echo "c.InlineBackend.figure_formats = {'png', 'retina'}" >> ${JUPYTER_CONFIG} \
&& Rscript -e "install.packages(c('repr', 'IRdisplay', 'evaluate', 'crayon', 'pbdZMQ', 'devtools', 'uuid', 'digest'))" \
&& Rscript -e "devtools::install_github('IRkernel/IRkernel')" \
&& Rscript -e "IRkernel::installspec()"
EXPOSE 8000
VOLUME $WORK_DIR
WORKDIR $WORK_DIR
CMD [ "jupyter", "notebook"]
コンテナ作成
Dockerfileからイメージを作成
カレントディレクトリをDockerfileがあるディレクトリにして「ubuntu-analysis」としてイメージを作成します。
$ docker build -t ubuntu-analysis .
「ubuntu-analysis」イメージから「analysis」としてコンテナを作成します。
$ docker run -t --name=analysis -v $PWD/notebooks:/notebooks -p 8000:8000 ubuntu-analysis
こんな感じの出力がされるとJupyterが起動できてます。
[I 10:28:45.394 NotebookApp] The Jupyter Notebook is running at:
[I 10:28:45.394 NotebookApp] http://a19df1ce6079:8000/
[I 10:28:45.395 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
ブラウザで「http://localhost:8000」にアクセスして、Jupyterが表示され、notebooksディレクトリ以下のファイルやディレクトリが見えていれば成功です。

今後について
今回は一通り動かすことを目標に作ったので、色々足りない部分があると思います。
Dockerfileの最適化やライブラリの追加、データ分析には必要になるDBとの連携等含め、今後は使っていきながら、少しずつ調整していきたいと思います。
参考
サイト:
DockerでサクッとUbuntu+任意のPython環境を用意する
https://qiita.com/shngt/items/51102aeb81834d0d3d7a
asashiho/ml-jupyter-python3
https://github.com/asashiho/ml-jupyter-python3/blob/master/Dockerfile
[Docker] build tzdata タイムゾーン選択回避方法(ubuntu)
https://sleepless-se.net/2018/07/31/docker-build-tzdata-ubuntu/
jupyter notebook で R
https://www.kimoton.com/entry/20180902/1535819542
書籍:
自宅ではじめるDocker入門―人気のコンテナ型「仮想化ソフト」を使ってみる!
https://www.amazon.co.jp/dp/4777520722/