[Python]pip で Numba をインストールする時にエラーになるという状況でしたので、結果的に Docker で Anaconda を使うまでを書いてみました。
Anaconda, pyenv の問題を理解する
Anaconda を使う方向で考え始めたのですが、
もともと、homebrewを用いてNode.js等の環境を構築し、hubotと戯れていた環境。 最近、話題のTensorFlowを使ってみるべくPythonの環境をAnacondaで作り、チュートリアルを少々動かし始めていました。
久々にnpmコマンドを打ったところ…
-bash: npm: command not found
Anaconda を公式サイトの Graphical Installer(.pkg file), Command Line Installer(Anaconda3-4.3.1-MacOSX-x86_64.sh) でインストールすると、環境変数の PATH を Anaconda のコマンドが優先されるように設定されるため、Homebrew でインストールしたコマンドが使えない状況になると解釈しました。
だから、
このままだとHomebrewとAnaconda環境がバッティングするのでコメントアウトしておく。
#export PATH="/Users/*ユーザーネーム*/anaconda/bin:$PATH"
そして、~/.bashrcに以下の関数を追加する。
#!/usr/local/bin/bash function enter_conda() { source /Users/*ユーザーネーム*/anaconda/bin/activate root } function quit_conda() { source /Users/*ユーザーネーム*/anaconda/bin/deactivate }
環境変数の設定をこねくり回したりしなければいけないのだと解釈しました。
そうしなくても良いように、
- 多くは2.xなので、3.xと共存したいなと思います。
- システムの方をうかつにさわるとはまります。
- 別途apt-get install python3などとして入れても、環境変数を自分で弄る必要があります。
- anaconda単独だと実は問題があります。
- curlやsqlite3,opensslなどを一緒にインストールして動作をのっとります。
- 推奨はpyenvを経由することです。
- 現在のpyenvはanacondaに対応しています。
環境構築方法
.1. pyenvをインストールします。
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc $ echo 'eval "$(pyenv init -)"' >> ~/.bashrc $ source ~/.bashrc
.2. anacondaをインストールします。 3系でも2系でもどっちでもいいですが、3で殆どの場合不都合が無いです。 pyenvで両方共存させることも可能ですが、condaで2/3の切り替えができるので片方でいいです。
$ pyenv install -l | grep ana # 最新版を確認。anaconda3-2.5.0 (2系はanaconda-2.5.0) # minicondaがいい人はminicondaを入れてください。 $ pyenv install anaconda3-2.5.0 $ pyenv rehash $ pyenv global anaconda3-2.5.0 # anacondaをメインのpythonに設定。 $ echo 'export PATH="$PYENV_ROOT/versions/anaconda3-2.5.0/bin/:$PATH"' >> ~/.bashrc $ source ~/.bashrc # activateがpyenvとanacondaでバッティングするので、pathに明示しておく。 $ conda update conda #念のためconda自体をアップデートしておく。
Anaconda をインストールするのに、pyenv を使った方が良さそうに解釈しました。
ただ、pyenv も Anaconda と衝突するところがあるようで、
pyenvとanacondaのactivate衝突問題とは? linuxやMacではpyenvを介してanacondaをインストールできます。 更に、anacondaで複数開発環境の切り替えをしたいケースがあると思います。 anacondaでの環境は、source activate <環境名>として切り替えを行えますが、pyenvの下では下記のようなエラーが出てシェルごと落ちます。
$ source activate #>>> pyenv: -bash: command not found
理由はよくわかりませんが、pyenvがshimスクリプトを使ってpathをのっとっているので、変な事が起こっているのかもしれません。
anacondaがconda activateを採用してくれていれば… orz
pyenv で Anaconda をインストールしても面倒そうです。
次の記事を見て、
- pyenvが必要かどうかフローチャート - Qiita
- Pythonの環境設定でむかついてる人はとりあえずこれをコピペで実行してください 2017.01 - YAMAGUCHI::weblog
- Pythonの仮想環境構築(2017年版) pyenvとpyenv-virtualenvとvirtualenvとvirtualenvwrapperとpyvenvとvenv - Qiita
pyenv, Anaconda を避けてきたのですが、Numba のインストールでわざわざ LLVM のバージョンを落としてインストールするのが面倒な状況になりました。
だから、Anaconda で一式使える状態にしようと考え始めたので、
ウェブサービスのガチ開発者
pyenvではなくて、今ならDockerとかvagrantとかを使って、コンテナ化/仮想化の方が良いと思います。Pythonのバージョンだけじゃなくて、データベースのバージョンとか、周りのミドルウェアとか、OSのバージョンとか、サービスごとに要件はいろいろあるはずですし。
Python と必要なパッケージを、設定の面倒さなく、影響を閉じ込めて使いたいので、Docker のコンテナーを使ってみようと思いました。
Docker が初めてなので、Docker Hub の Anaconda(continuumio/anaconda - Docker Hub) で Numba が使えるところまで進めたいと思います。
Docker のインストール
いくつか種類があるようでしたが、
Docker Community Edition for Mac
Docker Community Edition for Mac(Stable) を選びました。
Docker.dmg をダブルクリックして、ウィザードの通りに進めました。
Install it
Double-click Docker.dmg to start the install process.
When the installation completes and Docker starts, the whale in the top status bar shows that Docker is running, and accessible from a terminal.
特に悩む選択肢はなかったと思います。
次のコマンドでインストールされていることを確認しました。
$ docker --version
Docker version 17.03.1-ce, build c6d412e
$ docker-compose --version
docker-compose version 1.11.2, build dfed245
$ docker-machine --version
docker-machine version 0.10.0, build 76ed2a6
Docker で hello-world
最初なので、hello-world をしてみます。
Run it
Open a command-line terminal, and try out some Docker commands.
Run docker version to check that you have the latest release installed.
Run docker run hello-world to verify that Docker is pulling images and running as expected.
ターミナルから次のコマンドを実行すると、Docker Hub からイメージをダウンロードして、実行してくれるみたいです。
docker run - Docker Documentation
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
78445dd45222: Pull complete
Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
次のコマンドでローカルにあるイメージが確認できるようです。
docker images - Docker Documentation
$ docker images hello-world
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 48b5124b2768 2 months ago 1.84 kB
Docker Hub のこれ(library/hello-world - Docker Hub)がダウンロードされているようです。
Description
Run a command in a new container
docker run
は新しいコンテナーの中でイメージを実行するようです。
hello-world を実行した直後はコンテナーは停止しているだけで、プロセスは残っている状態のようです。
次のコマンドでコンテナーが確認できるようです。
-a
のオプションで停止しているコンテナーも含めてすべて表示できるようです。
docker ps - Docker Documentation
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f033a686f252 hello-world "/hello" 58 seconds ago Exited (0) 56 seconds ago flamboyant_yalow
次のコマンドでコンテナーを削除することができるようです。
docker rm - Docker Documentation
$ docker rm f033a686f252
f033a686f252
コンテナーが削除されているようです。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
コンテナーはイメージとは別なので、イメージから実行するたびに同じ環境のコンテナーが作成できるものだと認識しました。 オブジェクト指向プログラミングで言うとクラスとインスタンスの関係みたいなものでしょうか。
nginx
nginx イメージのダウンロード
次は HTTP サーバーである nginx(library/nginx - Docker Hub) のイメージを実行してみます。
コンテナーの実行(作成)はしないで、イメージだけをローカルにダウンロードする場合は docker pull
コマンドを実行するようです。
docker pull - Docker Documentation
$ docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
6d827a3ef358: Pull complete
b556b18c7952: Pull complete
03558b976e24: Pull complete
9abee7e1ef9d: Pull complete
Digest: sha256:52f84ace6ea43f2f58937e5f9fc562e99ad6876e82b99d171916c1ece587c188
Status: Downloaded newer image for nginx:latest
ダウンロードできました。 イメージを確認してみます。
$ docker images nginx
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 5e69fe4b3c31 11 days ago 183 MB
nginx の実行
nginx のイメージからコンテナーを実行(作成)します。
$ docker run --name some-nginx -d -p 8080:80 nginx
bba2da7144dc2649ce97219de5e8d73b68e9bbbc548f332ccde77ee41a06b417
オプションの --name
はコンテナーの名前をつけることができるようです。
-d
はコンテナーをバックグラウンドで「デタッチド」モード(detached mode)で実行することができるようです。
-p
はコンテナーのポートをホストのポートに公開することができるようです。
コンテナーを確認してみます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bba2da7144dc nginx "nginx -g 'daemon ..." 10 seconds ago Up 8 seconds 443/tcp, 0.0.0.0:8080->80/tcp some-nginx
STATUS が UP の状態でコンテナーが動いているようです。
PORTS は 0.0.0.0:8080->80/tcp
となっていて、コンテナーの 80
のポートがホストの 8080
で公開されているようです。
NAMES は --name
でつけた some-nginx
になっています。
http://localhost:8080 にアクセスしてみます。
nginx の標準のページが表示できました。
コンテナーを停止します。
docker stop
でコンテナーを停止することができるようです。
docker stop - Docker Documentation
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bba2da7144dc nginx "nginx -g 'daemon ..." 8 minutes ago Up 8 minutes 443/tcp, 0.0.0.0:8080->80/tcp some-nginx
$ docker stop bba2da7144dc
bba2da7144dc
コンテナーを削除します。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bba2da7144dc nginx "nginx -g 'daemon ..." 8 minutes ago Exited (0) 8 seconds ago some-nginx
$ docker rm bba2da7144dc
bba2da7144dc
nginx の実行(オリジナルコンテンツを公開)
nginx の標準のコンテンツを公開するのではなく、自分のコンテンツを公開するために、docker の-v
オプションを使うようです。
$ docker run --name some-nginx -v /Users/user/content:/usr/share/nginx/html:ro -d -p 8080:80 nginx
71cd51a3403584329421261d2d49a52a03314b6d1b034b23942042377a5cb21e
/Users/user/content
はホストのコンテンツのあるディレクトリーです。
/usr/share/nginx/html
はコンテナーの nginx の公開用ディレクトリーのようです。
/Users/user/content:/usr/share/nginx/html
のように記述することで、ホストのコンテンツのあるディレクトリーがコンテナーの nginx の公開用ディレクトリーにマウントされるようです。
ro
はホストのファイルを読み取り専用にできるようです。
公開用のファイルとして、次のファイルを作成して、/Users/user/content/index.html
として保存しました。
<!-- index.html -->
<html>
<head>
<title>sample nginx</title>
</head>
<body>
<h1>sample nginx</h1>
</body>
</html>
http://localhost:8080 にブラウザーでアクセスします。
作成したファイルが公開されているようです。
コンテナーを停止して、削除します。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
71cd51a34035 nginx "nginx -g 'daemon ..." 3 seconds ago Up 2 seconds 443/tcp, 0.0.0.0:8080->80/tcp some-nginx
$ docker stop 71cd51a34035
71cd51a34035
$ docker rm 71cd51a34035
71cd51a34035
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
nginx に限らず、コンテナーの中でドキュメントを永続化するのではなくて、ホストのディレクトリーをマウントすることで、データはホスト側で永続化するようです。
Anaconda
Anaconda のイメージのダウンロード
Docker の Anaconda(continuumio/anaconda - Docker Hub) のイメージをダウンロードします。
$ docker pull continuumio/anaconda
Using default tag: latest
latest: Pulling from continuumio/anaconda
8ad8b3f87b37: Pull complete
16deb7e607c1: Pull complete
8f70420d5249: Pull complete
542bf307a831: Pull complete
Digest: sha256:4c9abc36612cfcaebbacb399696184dba27b132ccdae9c2ccbb4fad81f96902d
Status: Downloaded newer image for continuumio/anaconda:latest
$ docker images anaconda
REPOSITORY TAG IMAGE ID CREATED SIZE
continuumio/anaconda latest 083a044e94ca 3 weeks ago 2.25 GB
2.25GB もありました。
Anaconda の実行
Anaconda のコンテナーを実行(作成)します。
$ docker run -i -t continuumio/anaconda /bin/bash
root@ea0b0fab39e2:/#
オプションの -i
と -t
は、
Assign name and allocate pseudo-TTY (–name, -it)
The -it instructs Docker to allocate a pseudo-TTY connected to the container’s stdin; creating an interactive bash shell in the container
コンテナーの中の bash
の標準入出力を使えるもののようです。
/bin/bash
はコンテナーの実行直後に /bin/bash
コマンドを実行した状態にしておくものと解釈しました。
Python のバージョンを確認してみます。
root@ea0b0fab39e2:/# python --version
Python 2.7.13 :: Anaconda 4.3.1 (64-bit)
root@ea0b0fab39e2:/#
Python のバージョンは 2.7.13, Anaconda のバージョンは 4.3.1 のようです。
exit
でコンテナーの中のシェルから抜けることができるようです。
root@ea0b0fab39e2:/# exit
exit
コンテナーを削除します。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea0b0fab39e2 continuumio/anaconda "/usr/bin/tini -- ..." 13 minutes ago Exited (130) 7 seconds ago eloquent_bose
$ docker rm ea0b0fab39e2
ea0b0fab39e2
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Anaconda の Jupyter
Alternatively, you can start a Jupyter Notebook server and interact with Anaconda via your browser:
docker run -i -t -p 8888:8888 continuumio/anaconda /bin/bash -c "/opt/conda/bin/conda install jupyter -y --quiet && mkdir /opt/notebooks && /opt/conda/bin/jupyter notebook --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser"
You can then view the Jupyter Notebook by opening
http://localhost:8888
in your browser, orhttp://<DOCKER-MACHINE-IP>:8888
if you are using a Docker Machine VM.
Docker Hub の Anaconda のページには、ホストのコマンドからコンテナーの Jupyter を実行するところまでしているようです。 ここでは 1 つずつコマンドを確認したいので、対話式にコマンドを入力してみます。
Jupyter をインストールするコマンドも含まれているようですが、Anaconda の中に Jupyter もインストールされているようですので、Jupyter のインストールはしないこととします。
次のようにコマンドを入力しました。
$ docker run -i -t -p 8888:8888 continuumio/anaconda /bin/bash
root@27ab9f9474ac:/# mkdir /opt/notebooks
root@27ab9f9474ac:/# /opt/conda/bin/jupyter notebook --notebook-dir=/opt/notebooks --ip='*' --port=8888 --no-browser
[I 08:42:05.890 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
[W 08:42:05.909 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 08:42:05.920 NotebookApp] Serving notebooks from local directory: /opt/notebooks
[I 08:42:05.920 NotebookApp] 0 active kernels
[I 08:42:05.921 NotebookApp] The Jupyter Notebook is running at: http://[all ip addresses on your system]:8888/?token=2c0e5f6c42d282d4d4bad1f00502f1366448ef21e8cba8b4
[I 08:42:05.921 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 08:42:05.923 NotebookApp]
Copy/paste this URL into your browser when you connect for the first time,
to login with a token:
http://localhost:8888/?token=2c0e5f6c42d282d4d4bad1f00502f1366448ef21e8cba8b4
Jupyter の実行に次の引数が指定されていますが、雰囲気で察することにしました。
--notebook-dir=/opt/notebooks
--ip='*'
--port=8888
--no-browser
一番下に表示されている token のついた URL にブラウザーからアクセスします。
Anaconda の Jupyter が表示されました。
Anaconda の Numba
Jupyter で Numba — Numba の Example にあるコードを実行してみます。
Numba のコードもエラーにならずに実行することができました。
コンテナーの /opt/notebooks
に作成したファイルが保存されるのですが、コンテナーの中のデータは、コンテナーを停止して削除するとなくなってしまいます。
データの永続化のために docker run
の -v
のオプションでホスト側のディレクトリーをコンテナーにマウントして、ホスト側でデータを永続化しようと思いました。
Anaconda3
後から気づいたのですが、Python 3.5 の Anaconda の Docker イメージがこちらにありました。
continuumio/anaconda3 - Docker Hub
$ docker pull continuumio/anaconda3
Using default tag: latest
latest: Pulling from continuumio/anaconda3
8ad8b3f87b37: Already exists
26e5bbd29116: Pull complete
26a23cde1ff7: Pull complete
0947a413f98b: Pull complete
Digest: sha256:d04148529d340097c08677061e7d08f42e13a51dbdbf7488d92af0a65fd82973
Status: Downloaded newer image for continuumio/anaconda3:latest
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
continuumio/anaconda3 latest 2f12b7e5bd80 3 weeks ago 2.23 GB
2.23 GB ありました。 Python 2.7 より少し小さいみたいです。
終わり
Numba のエラーから遠回りをしたような… Anaconda が使えるようになりましたので、しばらくこのコンテナーで使ってみたいと思います。