開発・実行環境をDockerで整える

概要

開発環境構築はだいたい辛い作業ですが、Dockerを使うことで構築がとても楽になります。もちろん銀の弾丸ではないので別のつらさは存在します。 しかし一歩も進まずに時間だけが過ぎることはなくなるため精神衛生上良く、開発を始める段階においてはとても効果的です。

開発環境構築が辛い

開発環境構築はプログラミングをする上で必須の作業ですが、依存関係など非常に多くの落とし穴があることが多いです。 また、環境構築そのものが目的ということは少なく、その先に別にやりたい事が控えていることが多いと思います。 そのため、とりあえずやってみようと思った際に、その試してみるべき部分にたどり着けずに時間を浪費していくのはかなり辛いです…

設定自動化スクリプトでは足りない

環境構築の手順が煩雑な問題に対しては、chefやAnsible等、自動で環境を構築する方法はいくつかあります。 これらは一度作れば同じ環境を何度でも作ることが出来ますが、2回目以降を楽にするものであるため初回はそれほど楽になりません。 また、すでに入っているものとの依存関係の問題などはこれらのツールでは解決しないため、 複雑な環境になればなるほど環境構築の難易度は上がります。

開発環境にDockerを使う

このような問題に対応するために、Dockerを開発環境として使うことを考えます。 Dockerでは毎回クリーンな環境から必要な分だけインストールするため、 依存関係地獄にはまりにくいです。 さらに、Dockerfileで構築手順を保存できるため、 複数のマシンで同じ環境を揃えるのが簡単で、かつ不要になったらコンテナを消すことで容量の削減にもなります。

また、Dockerfileを本番環境に持って行き、そのままデプロイすることも可能です。 そのため、本番でだけバグが起きる…といったことも回避出来ます。

Dockerで開発環境を整える

細かい部分はDocker入門を読むのが早いと思います。 そのため、割とさくっとしか説明しません。

Dockerコンテナの作成

Dockerコンテナを構築するのに便利なDockerfileは、 ベースとなるコンテナをもとに、指定されたコマンドを実行してコンテナを作ってくれます。 例えば、以下のDockerfileはffmpegがインストール済みのコンテナに対して、 ニコニコ静画を使ったChainer用の学習済みモデルファイルを利用出来る環境を整えています。 ffmpeg自体はベースのコンテナに入っているため、その後にpythonの実行環境を入れ、様々なライブラリを入れているだけです。 コンテナの作成はこのDockerfileが置いてあるディレクトリまで移動し、 docker build -t ffmpeg_test . で作れます。

FROM cellofellow/ffmpeg:latest

RUN apt-get -y update && apt-get -y upgrade
RUN apt-get install -y ccache curl g++ gfortran git libhdf5-dev
RUN apt-get install -y python-pip python-dev

RUN pip install numpy==1.10.2

# scipy
RUN apt-get install -y libblas-dev liblapack-dev libatlas-base-dev gfortran
RUN pip install scipy
RUN pip install Pillow
RUN pip install scikit-image
RUN pip install chainer==1.3

# niconico dataset
RUN pip install git+http://github.com/nico-opendata/niconico_chainer_models.git#egg=niconico_chainer_models

CMD ["/bin/bash -c"]

データの永続化

Dockerfileに変更を加えるとコンテナが新たに作成されるため、データを入れても気がつくと消えてしまいます。 もちろんそれでは使い物にならないので、永続化の手法はいくつか考えられているようです。 開発環境として使う分には、手元のマシンの特定フォルダをDockerマシン上にマウントできるData Volumeを利用するのが良いと思います。

以下のようにコンテナを実行することで、手元のマシンの~/docker_volume/ffmpeg/を、Dockerマシン上の/tmp/hostにマウントすることが出来ます。
docker run -v ~/docker_volume/ffmpeg/:/tmp/host --name ffmpeg -i -t ffmpeg_test /bin/bash

マウントしているだけなので変更もリアルタイムに反映されるため、作業用フォルダをマウントするとスムーズに開発出来ると思います。

Dockerを開発環境にする上での問題点

環境構築は物凄く楽になりましたが、すべてが良いわけではなく、 いくつか問題点があります。

環境の使い分けの煩雑さ

Dockerは実行にだけ利用し、開発は手元のホストマシンで行う場合、 ホストとコンテナとの違いを意識しないといけないため、煩雑さがだいぶ上がります。 ファイルに保存する場合に保存場所を意識しないといけなかったり、gitにコミットしようとしたらコンテナ上だったりと、コンソール作業のたびに今いる環境を確認するのは結構面倒です。

もちろん、自動実行が整っててコンテナ側をいじる必要が無かったり、 開発もコンテナ内でやるような場合は当てはまりません

実行速度の問題

MacだとVirtualBoxのVM上でコンテナが動いているため、実質的に専用のVMを立ち上げているのと変わりません。 そのため、実行速度が遅くなるという問題があります。 実際、私のMacBook Pro上記の環境で画像分類を行うと、ホストのMacで実行すると1秒以内に終わる処理が、コンテナ上だと100秒ぐらいかかってしまいます。 おそらくWindowsも同じ仕組みのはずなので、同じような結果になりそうです。 画像処理など特に重い処理等の場合はとても時間がかかってしまうため、環境構築とは別方面のつらさが出てきます。

これにたいしては、とりあえず動かしたい初期段階ではDockerを使い、環境が固定化してきた段階で手元のマシンで開発するようにすると、 開発初期のとりあえず使ってみたい状態は楽に環境を整えられ、確定した段階でローカルでの開発に移行することで、速度的な部分も問題にならなくなります。

もしかしたら、サーバ上のコンテナにローカルのファイルをマウントするといったことが可能かもしれないので、 この辺はもう少し調査が必要です…

なお、何故遅いのかの原因まではつかめていません。 VMのオーバーヘッドなのかもしれませんし、VirtualBoxボリュームによるせいの可能性もあります。 ここをもう少し調べれば回避策はあるかもしれません。

まとめ

  • 開発環境構築は毎回辛い
    • 依存関係
    • 複数台で開発すると何回もセットアップする羽目に
  • 環境構築自動化
    • 構築用スクリプトでは解決しない
      • スタート地点がそれぞれ違う
  • Dockerで環境ごと作る
    • 毎回クリーンな環境から構築
      • 依存関係に悩まされにくい
        • 一度成功すれば後は固定
    • 別ベクトルで辛いところはある
      • 作業してるところを意識しないといけない
      • 環境によっては遅い
    • 一歩も進まずに四苦八苦するよりも精神衛生上良い
      • 心が折れない
      • 問題点がはっきりとして解決しやすい
      • 開発初期はDocker、本格的に行けそうなら直接入れるように使い分け