NHN Cloud NHN Cloud Meetup!

本番!Pythonの実行環境を設定する

背景

Linux環境においてPythonで安定したサービスアプリケーションを提供するための環境づくりについて紹介します。

Pythonランタイムは、各OSで使用されているパッケージマネージャやインストーラーを利用して正常にインストールされていると仮定しましょう。しかし、実際にPythonを利用したサービス環境を構築するには、より精密な設定が必要です。

まず、Pythonランタイムのバージョンに敏感なアプリケーションがなければ、基本インストールされたPython3ランタイムをPATH環境変数に追加して使用すればよいです。しかし、サービス環境では、外部ライブラリの依存性管理や、同一ホストから別バージョンへのランタイムが必要なケースなど、様々な問題があるでしょう。

Pythonの生態系では、venv、virtualenv、pyenv、pyenv-virtualenv、virtualenvwrapper、pipenvなど、人気のあるツールがいくつかあります。インターネット上に様々なツールの説明がありますが、ここでは最近の新しいツール(pyenv、pipenv)の活用法を重点的に紹介します。

アプリケーションによって要件が少し異なる場合がありますので、段階的に説明します。

  1. 独自開発したPythonモジュールを任意のパスに設置して使用する
  2. 外部Pythonライブラリの依存性を分離して管理する
  3. Python環境を分離して管理する
  4. 分離された仮想環境に名前をつける

1.独自開発したPythonモジュールを任意のパスに設置して使用する

この場合は特別なツールは必要ありません。シェルの環境変数PYTHONPATHを利用できます。

  1. export PYTHONPATH = Pythonライブラリが設置されているパス
export PYTHONPATH = Pythonライブラリが設置されているパス

コロン(:)記号を区切り文字にして複数パスを指定すると、Pythonランタイムがインポートするときに、この環境変数に指定した順にモジュールをナビゲートします。

2.外部Pythonライブラリの依存性を分離して管理する

pip

外部Pythonライブラリは、バージョンを適切に管理する必要があるため、Pythonランタイムパッケージに含まれるpipを利用します。3.xバージョンでは、pip3という名前で提供されているので、明示的にpip3で実行してもよいし、PATH環境変数で実行時のパスが指定されている場合は、pipから実行してよいでしょう。

初期に外部Pythonライブラリを設置するときは、まず検索して見ることができます。次のコマンドを利用することもありますが、通常はあまりにも多くの検索結果が出力されるため、grepでフィルタリングする必要があります。

  1. pip3 search ライブラリ名
pip3 search ライブラリ名

PyPIウェブサイトで参照できます。

次のコマンドでインストールできます。(ただし、実際にインストールしないでください。理由は下で説明します。)

  1. pip3 install ライブラリ名
pip3 install ライブラリ名

このように設置されたライブラリでは、バージョンを適切に管理した方がよいでしょう。特にサービスを安定的に持続しようとするなら、バージョンは特定バージョンに固定することをお勧めします。次の2つのコマンドラインは、記憶しておく必要があります。

  1. pip3 freeze > requirements.txt
pip3 freeze > requirements.txt

上記のfreezeではコマンド発行時点のパッケージ情報を確認しつつ、管理設定ファイルの「requirements.txt」を書き出しています。requirements.txtはgitなどでバージョン管理しておくとよいです。以下のコマンドではこの設定ファイルを使用して、新しい環境でも同じようにライブラリを再インストールしています。

  1. pip3 install -r requirements.txt
pip3 install -r requirements.txt

ここまでがpipの基本的な使い方です。Pythonの開発経験があれば、誰もが知っている内容でしょう。しかし、pipで外部ライブラリをインストールする場合、/usrの下位にインストールする必要があるため、root権限も必要となり、システム共通環境に影響を及ぼすため、サービス用として使用するサーバーならリスクが大きくなります。(pip3 installはなるべく避けた方がよいでしょう。)

 

virtualenv

同一サーバー内に独立した複数の開発環境を構築しようと思った際、かつてはvirtualenvが標準的な方法でした。ただし、現在はpyenvとpipenvで代替可能なため、virtualenvの説明は簡単にしてスルーします。

原理は簡単です。現在使用可能なPythonランタイムをディレクトリのまま個人ディレクトリにコピーしておき、それをグローバルのランタイムのように使用する方法です。

virtualenvは、Pythonの外部ライブラリの依存性を分離して使用できるようにした初の試みでもありました。古い方法ですが、環境分離という概念はすべてここから出発したと言えます。

pipenv

ここではvirtualenvは忘れて、pipenvを使いましょう。pipenvはvirtualenvの公式的な継承者と言えます。

まず、次のように設置します。

  1. pip3 install pipenv
pip3 install pipenv

pipenvはrequirements.txtの代わりに、PipfileとPipfile.lockに依存性を管理します。

初期化します。このコマンドは、復元する際にも同様に使用します。

  1. pipenv install
pipenv install

仮想環境を有効にします。

  1. pipenv shell
pipenv shell

外部ライブラリを設置しましょう。

  1. pipenv install beautifulsoup4
  2. pip list
pipenv install beautifulsoup4
pip list

削除します。

  1. pipenv uninstall beautifulsoup4
  2. pip list
pipenv uninstall beautifulsoup4
pip list

pip freezeと同じコマンドです。Pipfile.lockファイルを作成し、ランタイムと下位の依存性を含むすべての依存性に対する情報を記録するため、完全な同一環境を再構築します。

  1. pipenv lock
pipenv lock

このコマンドを実行した後、PipfileとPipfile.lockをgitにコミットするとよいでしょう。

PipfileとPipfile.lockを保持し、同じ依存性を持つ環境を復元するには、初期化で使用したinstallを実行します。

  1. pipenv install
pipenv install

3. Python環境を分離して管理する

様々な理由で、ランタイムの分離が必要になる場合があります。例えば、同じホストのアプリケーションにおいて、一方はPython 3.5のバージョンを必要とし、他のアプリケーションではPython 3.7を必要とする場合、2つのランタイムをインストールしなければなりません。システムパスにPythonをバージョン別にインストールするのは現実的に厳しく、また望ましくありません。

また、ランタイムに名前をつけて管理したい場合もあるでしょう。このような場合には、pyenvとpyenv-virtualenvを活用すると便利です。

pyenvインストール

次のコマンドを実行して、ホームディレクトリの下位に.pyenvを設置します。

  1. git clone https://github.com/pyenv/pyenv.git ~/.pyenv
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

pyenvを実行できるように、環境変数として追加する設定を.bashrcに作成します。

  1. export PYENV_ROOT=$HOME/.pyenv
  2. export PATH=$PYENV_ROOT/bin:$PATH
  3. if command -v pyenv 1>/dev/null 2>&1; then
  4. eval "$(pyenv init -)"
  5. fi
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
if command -v pyenv 1>/dev/null 2>&1; then
    eval "$(pyenv init -)"
fi

これでpyenvを使用するための準備は終わりました。

ランタイムのインストール

pyenvに必要なPythonランタイムを選んで自分だけのPython実行環境を作ってみましょう。
まず、設置できるランタイムのバージョンリストを選択します。

  1. pyenv install -l
pyenv install -l

2019年4月時点の最新バージョンに3.7.3が存在しました。これを設置してみましょう。ソースコードをダウンロードしてビルドするので、gccパッケージとmakeパッケージがインストールされていなければなりません。必須ライブラリであるlibffi-devel、zlib-develとopenssl-develパッケージもあらかじめインストールされていると仮定します。上述したようにソースビルドが非常に複雑なため推奨していませんが、pyenvでインストールする場合は必須パッケージで、うまく設置されていれば大きな問題もなく、自動でソースビルドが成功します。

  1. pyenv install 3.7.3
pyenv install 3.7.3

インストールが完了したら、設置状況を確認できます。

  1. pyenv versions
  2. * system (set by /home/test/.pyenv/version) 3.7.3
pyenv versions
* system (set by /home/test/.pyenv/version)   3.7.3

systemと3.7.3がリストに表示されるでしょう。

ランタイムの有効化と使用

このように設置されたランタイムは~/.pyenv下位にインストールされているだけで、すぐに使用できるわけではなく、特定のランタイムを選択して有効にする過程が必要です。(次のコマンドは昔ながらの方法で従う必要はありません。)

  1. pyenv shell 3.7.3
  2. pyenv activate
  3. pyenv activateを実行するには項目4でインストールされているpyenv-virtualenvが必要。
pyenv shell 3.7.3
pyenv activate

pyenv activateを実行するには項目4でインストールされているpyenv-virtualenvが必要。

このようなコマンドを覚えて毎回入力して使用するのは煩わしいですね。次の方法で面倒なプロセスをすべて省略して使用することができます。

pyenv local

重要:特定ディレクトリの下位から、特定ランタイムと外部ライブラリの依存性を別途分離して、自動的に適用されるようにできます。

  1. pyenv local 3.7.3
pyenv local 3.7.3

このコマンドが実行されると、当該ディレクトリに.python-versionファイルが作成され、ここにバージョンを記録します。以降も、当該ディレクトリと下位に進入する度に、バージョン3.7.3のランタイムが自動で有効になります。当該ディレクトリを抜けると自動で無効になり、グローバルに使用するランタイムが選択されます。これはpyenvの最大の利点だと言えます。

自分が使用しているランタイムのバージョンを確認したい場合は、次のコマンドで確認できます。

  1. pyenv version
pyenv version

pyenv global

グローバルに使用するランタイムは、基本的にバージョン2.7.5で、systemという名前で通用されます。もしグローバルに使用するランタイムをバージョン3.7.3に変更するなら、次のコマンドで実行できます。

  1. pyenv global 3.7.3
pyenv global 3.7.3

2.7.5に戻したい場合は…

  1. pyenv global system
pyenv global system

pyenvの使用方法が複雑に見えるので整理します。次の3つのコマンドだけ覚えましょう。その中で最も重要なのはlocalコマンドです。
インストール:pyenv install 3.7.3
特定ディレクトリのバージョンを指定:pyenv local 3.7.3
バージョン確認:pyenv version

4.分離された仮想環境に名前をつける

pyenvを拡張してvirtualenv機能を使用することができます。pyenv-virtualenvという素晴らしいツールがあります。

次のようにインストールします。

  1. git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv

.bashrcファイルにpyenv設定を追加したように、pyenv-virtualenvの初期化設定を追加します。

  1. if command -v pyenv 1>/dev/null 2>&1; then
  2. eval "$(pyenv init -)"
  3. eval "$(pyenv virtualenv-init -)"
  4. fi
if command -v pyenv 1>/dev/null 2>&1; then
    eval "$(pyenv init -)"
    eval "$(pyenv virtualenv-init -)"
fi

先ほどインストールした3.7.3環境に別の名前をつけて使用します。v3という分離された仮想環境が得られました。

  1. pyenv virtualenv 3.7.3 v3
pyenv virtualenv 3.7.3 v3

インストールして使用可能なバージョンを確認します。

  1. pyenv versions
  2. * system (set by /home/test/.pyenv/version)
  3. 3.7.3
  4. 3.7.3/envs/v3
  5. v3
pyenv versions
* system (set by /home/test/.pyenv/version)
   3.7.3
   3.7.3/envs/v3
   v3

v3という名前の仮想環境が生じたことを確認できます。1つだけ作って使用するなら、あえて仮想環境を使う必要はありません。実際の環境である3.7.3は、1つだけインストールしておき、仮想環境を複数作っておけば分離された環境で使用することができます。

  1. pyenv virtualenv 3.7.3 v3_test_env
  2. pyenv versions
  3. * system (set by /home/test/.pyenv/version)
  4. 3.7.3
  5. 3.7.3/envs/v3
  6. 3.7.3/envs/v3_test_env
  7. v3
  8. v3_test_env
pyenv virtualenv 3.7.3 v3_test_env
pyenv versions
* system (set by /home/test/.pyenv/version)
   3.7.3
   3.7.3/envs/v3
   3.7.3/envs/v3_test_env
   v3
   v3_test_env

v3環境とv3_test_env環境がすべて3.7.3ランタイム基盤に、別途分離された環境で準備できました。

pyenv localを使って、特定ディレクトリで使用する仮想環境を設定します。

  1. cd ~/my_work_dir
  2. pyenv local v3
  3. pip list
  4. cd ~/my_test_dir
  5. pyenv local v3_test_env
  6. pip list
cd ~/my_work_dir
pyenv local v3
pip list
cd ~/my_test_dir
pyenv local v3_test_env
pip list

同じく以降、当該ディレクトリに入る度、定められた仮想環境が自動で有効になります。

アップグレード

Python仮想環境のバージョンを変更する場合は、新規ランタイムをpyenv installにインストールした上で、仮想環境を消去して、新しいランタイムに基づいて設定することも可能です。

  1. pyenv install 3.7.4
  2. pyenv versions
  3. pyenv uninstall v3
  4. pyenv virtualenv 3.7.4 v3
pyenv install 3.7.4
pyenv versions
pyenv uninstall v3
pyenv virtualenv 3.7.4 v3

もちろん、このようなアップグレード作業の前に、pipenv lockを用いて依存性情報を固定しておく必要があります。

この仮想環境でサービス形態でPythonアプリケーションが実行されている場合、上記のようにアンインストールするのは難しいです。このような場合には、別途ディレクトリに新規の仮想環境を構築し、既存のサービスを停止して、新規の仮想環境で新たにサービスを開始することを推奨します。

結論

pyenvとpyenv-virtualenvの組み合わせにpipenvを加えて使用すると便利です。
gitでpyenvをインストールし、pip3でpyenv-virtualenvとpipenvだけをインストールしておけば、以降は、/usrの下位に外部ライブラリやツールをインストールする必要がありません。

pipenv vs pyenv

pipenvも非常に便利なツールですが、個人的にはpyenvがさらに便利だと感じるので、これを推奨します。環境を分離したり、自動設定を適用したり、より便利に使いたい場合は、pyenvを選択しましょう。また、ランタイムは分離する必要がなく、依存性のみを分離したい場合は、pipenvを選択するとよいでしょう。pyenvは、ランタイムの最初に1回ソースビルドしなければならないという負担がありますが、pipenvは実行する度にshellコマンドでアクティベートさせる過程がやや面倒です。

Anaconda

フルパッケージとして一度にすべてのパッケージを含めてインストールしたい場合は、Anacodaをお勧めします。yumやaptのようなシステムのパッケージマネージャを利用することもでき、ダウンロードしてインストールすることもできます。

Anacondaは、ランタイムと依存性を事前によくパッケージしておくことによって、簡単かつ迅速にインストールして使うことができますが、主にWindowsの環境やデータ分析用として使用します。

condaという名前のCLIツールを提供しますが、これを利用して仮想環境を作成し、追加的なパッケージをインストールできます。

  1. conda create -n my_ana_env
  2. conda activate my_ana_env
  3. conda install lxml
  4. conda deactivate
conda create -n my_ana_env
conda activate my_ana_env
conda install lxml
conda deactivate

pyenvまたはpipとほぼ同様の文法をサポートするため、詳細な説明は省略します。

Miniconda

Anacondaは、パッケージ構成がよくなっていますが、かなり大きいため、軽い環境では小さいサイズで構成されているminicondaを使用することもあります。同様にcondaを利用して、追加的なパッケージをインストールすることもできます。

NHN Cloud Meetup 編集部

NHN Cloudの技術ナレッジやお得なイベント情報を発信していきます