はじめに (対象読者・この記事でわかること)

この記事は、AWS Elastic Beanstalk(以下、EB)を使ってPythonアプリケーションをデプロイしている開発者の方、特にPython 3.4のような少し古い環境でNumPyなどの科学計算ライブラリを利用しようとしてコンパイルエラーに遭遇した方を対象にしています。

この記事を読むことで、Elastic BeanstalkのPython 3.4環境でNumPyインストール時に発生する具体的なコンパイルエラーの原因と、その一般的な解決策として「事前にビルドしたNumPyパッケージをアプリケーションに含めてデプロイする方法」がわかります。古い環境でのライブラリデプロイに関するトラブルシューティングの知識も深まるでしょう。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 * AWS Elastic Beanstalkの基本的な操作知識 * Pythonの基本的な知識とpipを用いたパッケージ管理の経験 * Linuxコマンドの基本的な知識 (特にSSH接続とログ確認) * 仮想環境 (virtualenv/venv) の利用経験

Elastic Beanstalk Python 3.4とNumPyインストールの課題

Elastic Beanstalkは、requirements.txtファイルに記載されたPythonパッケージをデプロイ時に自動的にインストールしてくれます。しかし、Python 3.4のような少し古い環境でNumPyのような数値計算ライブラリをインストールしようとすると、しばしばコンパイルエラーに直面することがあります。

NumPyは、高速な数値計算を実現するためにCやFortranなどのネイティブコードに依存しています。そのため、pip install numpyを実行する際には、これらのネイティブコードをコンパイルするためのコンパイラ(特にFortranコンパイラのgfortran)がシステムにインストールされている必要があります。

Python 3.4時代のElastic Beanstalk環境では、デフォルトでこれらのコンパイラが提供されていないか、バージョンが古いためにNumPyのコンパイルに失敗するケースが多発します。また、Python 3.4に対応するNumPyのバイナリホイール(事前にビルドされたパッケージ)がPyPI(Python Package Index)に存在しない、または最新のpipが古いPythonバージョン用の適切なホイールを解決できないといった問題も発生しやすくなります。これが、デプロイが失敗する主な原因となります。

Python 3.4環境でNumPyをデプロイするための具体的な手順

このセクションでは、Elastic BeanstalkのPython 3.4環境でNumPyのインストールエラーを回避し、アプリケーションにNumPyを組み込む具体的な手順を解説します。主要な解決策は、ローカル環境でNumPyをビルドまたは取得し、それをアプリケーションと一緒にバンドルしてデプロイする方法です。

ステップ1: ローカル環境の準備

まず、Elastic Beanstalk環境と可能な限り近い環境をローカルに用意します。これにより、EB上での問題を再現し、解決策を検証しやすくなります。

  1. Python 3.4のインストール: Python 3.4がインストールされていない場合は、pyenvなどのバージョン管理ツールを使ってインストールします。 bash pyenv install 3.4.10 # または使用したいPython 3.4の特定のバージョン pyenv local 3.4.10
  2. 仮想環境の作成: プロジェクトディレクトリ内でPython 3.4の仮想環境を作成し、アクティベートします。 bash python3.4 -m venv .venv_py34 source .venv_py34/bin/activate
  3. 開発ツールのインストール: NumPyのコンパイルに必要なシステムライブラリ(gcc, gfortran, python-develなど)をローカル環境にインストールします。これは、あなたの開発環境のOSによって異なります。 例えば、Ubuntuであれば: bash sudo apt update sudo apt install build-essential gfortran python3.4-dev CentOS/Amazon Linuxであれば: bash sudo yum update sudo yum install gcc gcc-gfortran python34-devel

ステップ2: ローカルでNumPyをインストールし、バンドルする

Elastic Beanstalk環境でコンパイルできないNumPyを、ローカルで事前にインストールし、デプロイパッケージに含めます。

  1. NumPyのインストール: アクティベートした仮想環境内で、必要なバージョンのNumPyをインストールします。このとき、システムにコンパイラが適切にインストールされていれば、コンパイルが成功するはずです。 bash pip install numpy==1.11.3 # Python 3.4で安定動作するNumPyのバージョン例 ※ここで、もしgfortranが見つからないなどのエラーが出たら、ステップ1で開発ツールが正しくインストールされているか確認してください。

  2. バンドル用のディレクトリ作成: アプリケーションのルートディレクトリに、NumPyやその他の外部ライブラリを格納するためのディレクトリ(例: vendor)を作成します。 bash mkdir vendor

  3. NumPyパッケージのコピー: 仮想環境のsite-packagesディレクトリから、インストールしたNumPyパッケージをvendorディレクトリにコピーします。 仮想環境のsite-packagesのパスは、通常./.venv_py34/lib/python3.4/site-packages/のような場所になります。 bash cp -r ./.venv_py34/lib/python3.4/site-packages/numpy vendor/ # もし依存関係もコピーするなら、まとめてコピーする cp -r ./.venv_py34/lib/python3.4/site-packages/*.whl vendor/ # バイナリホイールもあれば cp -r ./.venv_py34/lib/python3.4/site-packages/numpy-*.egg-info vendor/ これで、アプリケーションのデプロイパッケージ(ZIPファイル)にvendor/numpyが含まれることになります。

ハマった点やエラー解決

Elastic Beanstalkでpip install numpyを実行すると、以下のようなエラーメッセージに遭遇することが一般的です。

エラーメッセージ例:

Running setup.py install for numpy ... error
    Complete output from command /usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-0k1x8p6x/numpy/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-lkm2o6b2-record/install-record.txt --single-version-externally-managed --compile:
    ... (中略) ...
    error: a setuptools-conda-test configuration error occurred: Failed to find Fortran compiler.
    error: Command "gfortran -fno-strict-aliasing -fPIC -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fno-strict-aliasing -I/usr/include/python3.4m -c numpy/linalg/lapack_lite/python_xerbla.c -o build/temp.linux-x86_64-3.4/numpy/linalg/lapack_lite/python_xerbla.o" failed with exit status 1
    ----------------------------------------
Command "/usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-0k1x8p6x/numpy/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-lkm2o6b2-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-0k1x8p6x/numpy/

原因: このエラーは、NumPyのコンパイルに必要なFortranコンパイラ(gfortran)がElastic Beanstalk環境にインストールされていないために発生しています。特にPython 3.4の環境では、このような開発ツールがデフォルトで不足していることが頻繁にあります。また、Python 3.4に対応するNumPyのバイナリホイールがない場合、pipはソースコードからのビルドを試みるため、この問題が顕在化します。

解決策

ローカルでNumPyをバンドルし、Elastic Beanstalk環境がそのNumPyモジュールを正しく認識できるようにパスを設定します。

  1. requirements.txtからNumPyを削除: アプリケーションのrequirements.txtファイルからnumpyの行を削除します。これにより、EBがNumPyのインストールを試みなくなり、コンパイルエラーを回避できます。

  2. アプリケーションコードでのパス設定: アプリケーションのエントリポイントとなるPythonファイル(例: application.pywsgi.py)の冒頭で、バンドルしたNumPyのパスをPythonの検索パスに追加します。 ```python import sys import os

    アプリケーションルートからの相対パスでvendorディレクトリを追加

    EBのデフォルトでは/opt/python/current/appがアプリケーションのルート

    sys.path.insert(0, os.path.join(os.path.dirname(file), 'vendor'))

    または直接パスを指定

    sys.path.insert(0, '/opt/python/current/app/vendor')

    import numpy # これでnumpyがインポートできるようになる ``os.path.dirname(file)は現在のファイルのディレクトリを指します。アプリケーションのルートがカレントディレクトリになるようにデプロイされていれば、この方法で./vendor`を指定できます。

  3. .ebextensionsでの永続的なパス設定 (推奨): もしアプリケーションコードを修正したくない場合や、より恒久的な解決策を求める場合は、.ebextensionsを使ってElastic Beanstalk環境のPYTHONPATHを設定することができます。アプリケーションのルートに.ebextensionsディレクトリを作成し、その中に.configファイル(例: 01_add_pythonpath.config)を配置します。

    ```yaml

    .ebextensions/01_add_pythonpath.config

    files: "/etc/profile.d/pythonpath_vendor.sh": mode: "000755" owner: root group: root content: | #!/bin/bash # Elastic Beanstalkのアプリケーションルートは通常 /opt/python/current/app export PYTHONPATH=$PYTHONPATH:/opt/python/current/app/vendor echo "PYTHONPATH added: /opt/python/current/app/vendor" >> /var/log/cfn-init.log

    container_commands: 01_add_path: command: "sh /etc/profile.d/pythonpath_vendor.sh" leader_only: true `` この設定により、デプロイ時に/etc/profile.d/にスクリプトが配置され、以降のシェルセッションやアプリケーション実行時にPYTHONPATH/opt/python/current/app/vendorが追加されます。これにより、アプリケーションコード内でsys.pathを直接操作することなく、import numpy`が可能になります。

  4. アプリケーションのデプロイ: vendorディレクトリ、変更後のrequirements.txt.ebextensions(利用する場合)、およびアプリケーションコードをすべて含んだZIPファイルを作成し、Elastic Beanstalkにデプロイします。

この手順により、Elastic BeanstalkがNumPyをコンパイルする手間を省き、ローカルで事前に準備したNumPyモジュールを利用してアプリケーションを正常に動作させることができます。

まとめ

本記事では、Elastic BeanstalkのPython 3.4環境でNumPyのインストールがコンパイルエラーで失敗する問題に対する解決策として、ローカルでNumPyをインストール・バンドルし、デプロイパッケージに含める方法を解説しました。

  • 古い環境の課題: Python 3.4のような古いEB環境では、NumPyのコンパイルに必要なシステムライブラリ(特にgfortran)がデフォルトで不足しており、pip installが失敗する。
  • ローカルでの事前準備: requirements.txtに頼らず、ローカル環境でNumPyをインストールし、そのパッケージをvendorディレクトリなどに入れてアプリケーションにバンドルする。
  • 実行パスの設定: バンドルしたNumPyをPythonが認識できるように、アプリケーションコードでsys.pathを操作するか、.ebextensionsを用いてPYTHONPATHを設定する。

この記事を通して、古いElastic Beanstalk環境でもNumPyのような複雑なライブラリを安定してデプロイできるようになり、一般的なデプロイエラーのトラブルシューティングスキルが向上したことでしょう。 今後は、より新しいPython環境でのデプロイのベストプラクティスや、Dockerを用いたデプロイ方法についても記事にする予定です。

参考資料