dockerでアプリケーションテスト用の環境を作ろうとしたときにはまったので、誰得メモ。
python3.3のwebアプリケーションのテストをpostgresqlとかredisとかを簡単にリセットできる環境がほしいと思ったので、dockerで試していました。 で、なんかsaucyのイメージって公式っぽい base リポジトリにはなかったので、とりあえずppa:deadsnakesで各種バージョンのPythonが完備されているshimizukawa/python-allを使ってみました。
そして、dockerの中で環境作るためにpyvenvしてからのget-pip.pyをしたところ、pipが $VIRTUAL_ENV/bin じゃなくて、 $VIRTUAL_ENV/local/bin にインストールされてしまう問題に気づきました。 これだとPATHに含まれてないので、最初はpipのインストールに失敗したように見えます。 実際は違うところにインストールされていました。
で、なぜだろうと原因を探りつつ、発生する条件を特定してみると
- activateした場合は発生しない。pyvenvしたpythonをパス指定で実行すると発生する。
- ソースインストールしたPythonでは発生しない。
- deadsnakesでなくともubuntuのパッケージで入れたPython3.3でも発生する。
- pyvenvじゃなくて、virtualenvのときは発生しない。
まずactivateすると発生するってことで、その前後でsite-packagesを調べると、activateするとpyvenvした環境がsite.getsitepackages()の結果に含まれていることがわかりました。 pipは最終的に、 setup.py install を呼ぶようになってるので、このあたりの情報が狂ってしまうとどうしようもないのでしょう。 ソースインストールしたPythonではそういった動作はしてなかったので、パッケージの場合に当てられてるパッチかなと思い、パッケージソースを確認してみます。
なぜかdebianのほうのソースを確認していますが、多分ubuntuも同じでしょう。
http://bazaar.launchpad.net/~doko/python/pkg3.3-debian/view/head:/patches/site-locations.diff
ここで、dist-packagesとかなんかごちゃごちゃやってますが、 VIRTUAL_ENV環境変数が有効なときに、その環境のsite-packagesを追加するようになっています。 これで、activateすれば発生しない理由がわかりました。
しかし、ansibleとかそういうので環境作ろうとしたら、activateしないでそのままパス指定で実行することもあるので、別の方法はないのかと調べてみると、pipがやっていました。 pip はインストール先の環境を判定するのに sys.prefix, sys.base_prefix, sys.real_prefix をつかっています。 こちらの方法ならactivateに関係なく、パス指定の場合でも正確に判定できそうです。
ちなみに virtualenv の場合に発生しないのは、site.pyを仮想環境専用のsite.payを置いているのでパッチの影響を受けないのだろうと思われます。
とはいえ、この問題の発生条件は ubuntu(多分debianも)で、パッケージインストールされたPython3.3のpyvenvで作った環境以下のpythonをactivateせずにパス指定で実行するという以外に見つからなかったので、まあ virtualenv使うなり、VIRTUAL_ENV環境変数が使われるようにplaybookとかそういうのを書くってことで回避できるでしょう。 3.4だとensure-pipでpyvenv内に最初からpip入るようになるし....
多分まったく同じ問題ではまる人はあまりいないと思いますが、類似の問題のヒントにでもなればと思います。 役に立ったと思った人は、「午後の紅茶 おいしい無糖」でも送ってください。
Comments !