Pythonの話。wheelを使ってC拡張モジュールをデプロイする仕組みが上手く稼動したのでメモ。
依存パッケージの本番デプロイ
アプリケーションが依存しているPythonパッケージをどうやって本番サーバーにデプロイするか。大抵はrequirements.txtにpip freezeで吐いた内容を保存しているだろう。とすると、本番サーバーでpip install -r requirements.txtすれば良いんだが、githubが落ちてたりPyPIが落ちてたりすると、外部要因でデプロイスクリプトが途中でコケる、というダサい事態になる。それを避けるために事前にパッケージを固めて各サーバーに配布する仕組みが必要になる。C拡張モジュールを使いたいけど本番サーバーでCコンパイラが自由に使えない、という時も同様で、事前にコンパイル済みの物を配布する必要がある。pip bundleを使う場合 (deprecated)
Pure Pythonなパッケージだけを使っている場合はこれで十分だろう。$ pip bundle -r requirements.txt myproduct.bundleで、myproduct.bundleを作成しておいて、デプロイ先で
$ pip install myproduct.bundleとする。しかし、C拡張モジュールがあると、デプロイ先でもりもりコンパイルが始まってしまって非効率なのと、そもそもpip 1.5でpip bundle自体が削除予定なので今後は忘れても良い機能だ。
pip wheel でコンパイル済みC拡張モジュールをデプロイする
これが本命、wheelというフォーマットでパッケージを配布する方式。
Wheel — wheel 0.22.0 documentation
http://wheel.readthedocs.org/en/latest/
私はCIサーバーでwheelを作って本番サーバーに転送して使っている。手順は、まず事前に各サーバーでwheelを導入しておく。
http://wheel.readthedocs.org/en/latest/
$ pip install --upgrade pip # 1.4以上が必要 $ pip install --upgrade setuptools # 0.8以上が必要 $ pip install wheelwheelの作成は次の通り。慣例的にwheelhouseというディレクトリ名が使われる様だ。
# requirements.txtがこんな内容だとする
$ cat requirements.txt
MySQL-python==1.2.4
python-memcached==1.53
boto==2.14.0
simplejson==3.3.1
# wheelの作成
$ pip wheel --wheel-dir=./wheelhouse -r requirments.txt
Downloading/unpacking MySQL-python==1.2.4 (from -r requirements_prod.txt (line 1))
Downloading MySQL-python-1.2.4.zip (113kB): 113kB downloaded
Running setup.py egg_info for package MySQL-python
Downloading http://pypi.python.org/packages/source/d/distribute/distribute-0.6.28.tar.gz
Extracting in /tmp/tmpKuwtk2
Now working in /tmp/tmpKuwtk2/distribute-0.6.28
Building a Distribute egg in /web/httpd_spc/chatparty_api/python/build/MySQL-python
/web/httpd_spc/chatparty_api/python/build/MySQL-python/distribute-0.6.28-py2.6.egg
Downloading/unpacking python-memcached==1.53 (from -r requirements_prod.txt (line 2))
Downloading python-memcached-1.53.tar.gz
Running setup.py egg_info for package python-memcached
warning: no files found matching '*.rst'
warning: no files found matching '*.txt'
warning: no files found matching 'MakeFile'
warning: no previously-included files matching '*.pyc' found anywhere in distribution
warning: no previously-included files matching '.gitignore' found anywhere in distribution
warning: no previously-included files matching '.DS_Store' found anywhere in distribution
Downloading/unpacking boto==2.14.0 (from -r requirements_prod.txt (line 3))
Downloading boto-2.14.0.tar.gz (1.1MB): 1.1MB downloaded
Running setup.py egg_info for package boto
warning: no files found matching 'boto/mturk/test/*.doctest'
warning: no files found matching 'boto/mturk/test/.gitignore'
Downloading/unpacking simplejson==3.3.1 (from -r requirements_prod.txt (line 4))
Downloading simplejson-3.3.1.tar.gz (67kB): 67kB downloaded
Running setup.py egg_info for package simplejson
Building wheels for collected packages: MySQL-python, python-memcached, boto, simplejson
Running setup.py bdist_wheel for MySQL-python
Destination directory: /web/httpd_spc/chatparty_api/wheelhouse
Running setup.py bdist_wheel for python-memcached
Destination directory: /web/httpd_spc/chatparty_api/wheelhouse
Running setup.py bdist_wheel for boto
Destination directory: /web/httpd_spc/chatparty_api/wheelhouse
Running setup.py bdist_wheel for simplejson
Destination directory: /web/httpd_spc/chatparty_api/wheelhouse
Successfully built MySQL-python python-memcached boto simplejson
Cleaning up...
生成されたファイル名を見ればわかる様に、wheelはPythonバージョンとアーキテクチャ毎に作られる。
$ ls -l wheelhouse/ boto-2.14.0-py26-none-any.whl MySQL_python-1.2.4-cp26-none-linux_x86_64.whl python_memcached-1.53-py26-none-any.whl simplejson-3.3.1-cp26-none-linux_x86_64.whlwheelを使ったインストールはpip installでwheelの場所を指定するだけ。一瞬で終って気持ちがいい。依存関係は既に解決済みなので --no-deps オプションを使う。
$ pip install --no-deps wheelhouse/* Unpacking ./wheelhouse/MySQL_python-1.2.4-cp26-none-linux_x86_64.whl Unpacking ./wheelhouse/boto-2.14.0-py26-none-any.whl Unpacking ./wheelhouse/python_memcached-1.53-py26-none-any.whl Unpacking ./wheelhouse/simplejson-3.3.1-cp26-none-linux_x86_64.whl Cleaning up...