この記事では、既存のツールを使用して、最小限の手動介入でFunction Computeプロジェクトに依存ライブラリをインストールする方法を説明します。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
#パッケージマネージャのインストールディレクトリ
現在、Function ComputeはJava、Python、Node.js環境をサポートしています。これら3つの言語のパッケージマネージャは、それぞれMaven、pip、NPMです。以下では、これらのパッケージマネージャのそれぞれのインストールディレクトリを説明します。
Maven
MavenはJavaのパッケージマネージャです。Mavenは、プロジェクトファイルpom.xmlで宣言された依存関係を、中央リポジトリまたはプライベートリポジトリから$M2_HOME/repository
ディレクトリにダウンロードします。M2_HOME
のデフォルト値は$HOME/.m2
です。開発マシン上のすべてのJavaプロジェクトは、このローカルリポジトリディレクトリの下にあるJARパッケージを共有します。mvn package
の段階で、依存するすべてのJARパッケージは最終的な成果物にパッケージ化されます。したがって、Javaプロジェクトは$M2_HOME/repository
ディレクトリ内のファイルに依存することなく実行されます。
pip
現在、Pythonのパッケージマネージャーとして最も人気があり、推奨されているのはpipです。インストールパッケージをローカルディレクトリにインストールする方法を理解する前に、Python パッケージマネージャについての理解を深める必要があります。理解を深めるために、以下ではまずPythonパッケージマネージャの開発履歴を説明します。
2004年以前は、Pythonのインストールにはsetup.pyが推奨されていました。これを使用するには、任意のモジュールをダウンロードし、そのモジュールに付属のsetup.pyファイルを使用します。
python setup.py install
setup.pyはDistutilsから開発されています。2000年にPython標準リポジトリの一部としてリリースされたDistutilsは、Pythonモジュールのビルドやインストールに利用されています。
そのため、setup.pyを使ってPythonモジュールや
python setup.py sdist
モジュールをRPMやEXEファイルにパッケージ化することもできます。
python setup.py bdist_rpm
python setup.py bdist_wininst
MakeFileと同様に、setup.pyもビルドとインストールに利用できます。しかし、ビルドとインストールのプロセスが統合されているため、モジュールをインストールする際には必ずモジュールをビルドしなければならず、リソースを無駄にしてしまいます。2004年にPythonコミュニティは、easy_installツールを含むsetuptoolsをリリースしました。その後、PythonはEGG形式のサポートを開始し、オンラインリポジトリPyPiを導入しました。
オンラインモジュールリポジトリPyPiには、2つの重要な利点があります。
1、コンパイル済みのEGGパッケージをインストールするだけで済むので、効率が向上します。
2、依存パッケージを自動的にPyPiからダウンロードしてインストールします。
2008年にリリースされて以来、pipは徐々にeasy_installに取って代わり、事実上の標準的なPythonパッケージマネージャとなりました。EGG形式と互換性があるため、pipはWheel形式を好み、コードバージョンリポジトリ(例えばGitHub)からのモジュールのインストールをサポートしています。
以下では、Pythonモジュールのディレクトリ構造を説明します。EGG形式とWheel形式の両方のインストールファイルのディレクトリは、purelib、platlib、ヘッダ、スクリプト、データの5種類に分類されます。
Directory | Installation location | Purpose |
---|---|---|
purelib | $prefix/lib/pythonX.Y/site-packages | Pure Python implementation library |
platlib | $exec-prefix/lib/pythonX.Y/site-packages | Platform-related DLL |
headers | $prefix/include/pythonX.Yabiflags/distname | C header files |
script | $prefix/bin | Executable files |
data | $prefix | Data files, such as .conf configuration files and SQL initialization files |
prefix
と $exec-prefix
は Python コンパイラのパラメータで、 sys.prefix
と sys.exec_prefix
から取得できます。Linuxでのデフォルトはどちらも/usr/local
です。
npm
npmはNode.jsのパッケージマネージャーです。npm installコマンドを実行すると、依存パッケージがカレントディレクトリ以下のnode_modulesサブディレクトリにダウンロードされます。Node.jsのランタイム依存パッケージはすべてカレントディレクトリに含まれています。ただし、Node.jsのライブラリの中には、モジュールをインストールしたときに構築されたローカル環境に依存するものがあります。ビルド環境(Windowsなど)とランタイム環境(Linuxなど)が異なる場合、ローカルに依存するライブラリは実行できません。また、ビルド時に開発ライブラリやランタイムライブラリがインストールされている場合、オペレーティングシステムのパッケージマネージャでローカルにインストールされていたDDL(apt-getなど)がランタイム環境下のコンテナに存在しない場合があります。
#トラブルシューティングの問題点
次に、Function Computeの依存ライブラリがインストールされている場合に発生する問題を解決する方法を見ていきます。
####グローバルシステムディレクトリにインストールされた依存ライブラリ####
Mavenとpipは、依存パッケージをプロジェクトディレクトリ以外のシステムディレクトリにインストールします。プロジェクトがビルドされると、Mavenは外部の依存パッケージをすべて最終的な成果物にパッケージ化します。そのため、Mavenで管理されているプロジェクトは、実行時に依存関係の問題から解放されます。Mavenで管理されていないJAVAプロジェクトでは、依存性のあるJARパッケージをカレントディレクトリまたはそのサブディレクトリに配置し、最終的な成果物にパッケージ化することも一般的です。このようにして、Java実行時に依存関係の問題が発生するのを防ぐことができます。しかし、このような問題は pip で管理された Python 環境で発生します。 pip は依存関係をシステムディレクトリにインストールしますが、Function Compute の本番環境(/tmp
ディレクトリを除く)は読み込み専用で、プレハブ環境を構築することができません。
####ネイティブの依存関係####
一般的なPythonやNode.jsのライブラリファイルは、システムのネイティブ環境に依存しています。コンパイル環境とランタイム環境のDDLをインストールしなければならず、結果としてどちらの場合も移植性が悪くなります。
Function ComputeがDebianやUbuntu上で実行される場合、システムのインストールプログラムやライブラリを管理するためにAPTパッケージが使用されます。デフォルトでは,これらのプログラムやライブラリは,システムディレクトリ(例えば,/usr/bin
,/usr/lib
,/usr/local/bin
,/usr/local/lib
)にインストールされます.したがって、ネイティブの依存関係もローカルディレクトリにインストールする必要があります。
#推奨ソリューション
以下にいくつかの直感的な解決策を説明します。
1、依存関係をインストールするための開発システムが本番の実行システムと一致していることを確認します。fcli sboxを使用して依存関係をインストールします。
2、すべての依存関係ファイルをローカルディレクトリに配置します。モジュール、実行ファイル、.dlまたは.soファイルをpipからカレントディレクトリにコピーします。
しかし、実際には依存関係ファイルをカレントディレクトリに配置するのは難しいです。
1、pipやapt-getでインストールしたライブラリファイルは、異なるディレクトリに散らばっています。これは、これらのファイルを見つけるためには、異なるパッケージマネージャに精通していなければならないことを意味します。
2、ライブラリファイルには遷移的な依存関係があります。ライブラリがインストールされると、そのライブラリが依存する他のライブラリもインストールされます。このため、これらの依存関係を手動で取得するのは非常に面倒です。
この場合、手動による介入を最小限に抑えて、カレントディレクトリに依存関係を手動でインストールするにはどうすればよいのでしょうか。以下では、pip と APT パッケージマネージャが使用するいくつかの方法を説明し、長所と短所を比較します。
#現在のディレクトリへの依存関係のインストール
####Python
#####方法 1: --install-option パラメータを使用します。
pip install --install-option="--install-lib=$(pwd)" PyMySQL
--install-option
を使用すると、setup.pyにパラメータが渡されます。しかし、.eggファイルや.whlファイルにはsetup.pyファイルは含まれていません。そのため、--install-option
を使用するとソースコードパッケージに基づいてインストール手順が起動し、setup.py はモジュールの構築プロセスを起動します。
--install-option
は以下のオプションをサポートしています。
File type | Option |
---|---|
Python modules | --install-purelib |
extension modules | --install-platlib |
all modules | --install-lib |
scripts | --install-scripts |
data | --install-data |
C headers | --install-headers |
--install-lib
を使用した場合、--install-purelib
と--install-platlib
の値は上書きされます。
また、--install-option="--prefix=$(pwd) "
はカレントディレクトリへのインストールをサポートしていますが、カレントディレクトリの下にlib/python2.7/site-packages
というサブディレクトリが作成されます。
利点。
1、モジュールをpurelibなどのローカルディレクトリにインストールできます。
デメリット: モジュールを purelib のようなローカルディレクトリにインストールすることができます。
1、ソースコードパッケージを含まないモジュールには適用できません。
2、Wheelパッケージをフル活用せずにシステムを構築してしまう。
3、モジュールを完全にインストールするためには、より多くのパラメータを設定する必要があり、面倒です。
方法 2: --target
または -t
パラメータを使用する
pip install --target=$(pwd) PyMySQL
--target
はpipによって新たに提供されたパラメータです。このパラメータを使うと、lib/python2.7/site-packages
というサブディレクトリを作らずに、モジュールをカレントディレクトリに直接インストールします。この方法は使いやすく、いくつかの依存関係を持つモジュールに適用できます。
方法3: PYTHONUSERBASE
を--user
と一緒に使う
PYTHONUSERBASE=$(pwd) pip install --user PyMySQL
user
を使用すると、モジュールはsite.USER_BASE
ディレクトリにインストールされます。このディレクトリのデフォルト値は、Linuxでは~/.local、MacOS
では~/Library/Python/X.Y
、Windowsでは%APPDATA%Python
です。環境変数 PYTHONUSERBASE
を使用して site.USER_BASE
の値を変更することができます。
prefix=
と同様に、--user
を使用すると、lib/python2.7/site-packages
というサブディレクトリが作成されます。
方法4: virtualenvを使用する
pip install virtualenv
virtualenv path/to/my/virtual-env
source path/to/my/virtual-env/bin/activate
pip install PyMySQL
virutalenv
は、グローバル環境を汚染しないという点で Python コミュニティから推奨されている方法です。virtualenv を使用すると、目的のモジュール (PyMySQL など) とパッケージマネージャ (setuptools, pip, wheel など) の両方がローカルディレクトリに保存されます。これらのモジュールはパッケージのサイズを大きくしますが、実行時には使用されません。
apt-get
apt-getでインストールしたDDLや実行ファイルもローカルディレクトリにインストールする必要があります。インターネット上で推奨されている chroot
や apt-get -o RootDir=$(pwd)
の方法を試してみましたが、欠陥があるので破棄しました。これまでの方法をベースに改良を加え、apt-get
を使って DEB パッケージをダウンロードし、 dpkg
を使ってインストールする方法を設計しました。
apt-get install -d -o=dir::cache=$(pwd) libx11-6 libx11-xcb1 libxcb1
for f in $(ls ./archives/*.deb)
do
dpkg -x $pwd/archives/$f $pwd
done
#ランニング方法
Javaはクラスパスを設定することでjarファイルやクラスファイルをロードしますが、nodejsはカレントディレクトリのnode_modules以下のパッケージを自動的にロードします。ここでは、これらの一般的な操作は省略します。
Python
Pythonはsys.pathが指すディレクトリリストからモジュールファイルをロードします。
> import sys
> print '\n'.join(sys.path)
/usr/lib/python2.7
/usr/lib/python2.7/plat-x86_64-linux-gnu
/usr/lib/python2.7/lib-tk
/usr/lib/python2.7/lib-old
/usr/lib/python2.7/lib-dynload
/usr/local/lib/python2.7/dist-packages
/usr/lib/python2.7/dist-packages
デフォルトでは、sys.pathにはカレントディレクトリが含まれています。そのため、2番目のメソッドでは -- target
や -t
パラメータを使用した場合、モジュールはカレントディレクトリにインストールされているので、sys.path の設定を無視することができます。
sys.pathは編集可能な配列なので、プログラム起動時にsys.path.append(dir)を使用することができます。プログラムの移植性を向上させるために、環境変数 PYTHONPATH を使用することもできます。
export PYTHONPATH=$PYTHONPATH:$(pwd)/lib/python2.7/site-packages
apt-get
apt-get を使ってインストールされた実行ファイルや DDL が、環境変数 PATH と LD_LIBRARY_PATH で設定されたディレクトリリストで利用可能であることを確認してください。
PATH
PATH 変数は、システムが実行可能なプログラムを検索するために使用するディレクトリのリストを示します。bin, usr/bin, usr/local/bin などの bin や sbin ディレクトリを PATH 変数に追加します。
export PATH=$(pwd)/bin:$(pwd)/usr/bin:$(pwd)/usr/local/bin:$PATH
なお、上記の内容はBashにも適用されます。Java、Python、node.jsの場合は、現在のプロセスの環境変数PATHを変更する際に適宜調整してください。
LD_LIBRARY_PATH
PATHと同様に、LD_LIBRARY_PATHはDDLを検索できるディレクトリリストです。通常、システムは /lib
, /usr/lib
, /usr/local/lib
ディレクトリにダイナミックリンクを配置します。いくつかのモジュールは、/usr/lib/x86_64-linux-gnu
のように、これらのディレクトリのサブディレクトリに置かれます。通常、これらのサブディレクトリは /etc/ld.so.conf.d/
以下のファイルに記録されます。
cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
したがって、$(pwd)/etc/ld.so.conf.d/
以下のファイルで宣言されたディレクトリ内のsoファイルも、LD_LIBRARY_PATH環境変数で設定されたディレクトリリストから取得する必要があります。
実行時に環境変数 LD_LIBRARY_PATH
を変更しても、その変更は反映されない可能性があることに注意してください。LD_LIBRARY_PATH
環境変数では、/code/lib
ディレクトリがあらかじめ設定されています。そのため、依存するsoファイルをすべて/code/lib
ディレクトリにソフトリンクすることができます。
#結論
このドキュメントでは、プログラムがインストールされたローカルライブラリファイルを見つけることができるように、pipやapt-getコマンドを実行してローカルディレクトリにライブラリをインストールしたり、実行時に環境変数を設定したりする方法を説明しています。
Pythonが提供する4つの方法は、どのような一般的なシナリオにも適用可能です。上記で説明したわずかな違いにもかかわらず、ニーズに応じて適切な方法を選択することができます。
apt-getはもう一つの方法です。他の方法と比較して、この方法はすでにシステムにインストールされているdebパッケージをインストールする必要がないため、パッケージサイズを小さくすることができます。さらにサイズを小さくするには、ユーザーマニュアルなどのインストール済みの不要なファイルを削除することができます。
本書は、より良いツールをカスタマイズするための技術蓄積の一環です。これをベースに、将来的にはより良いツールを提供し、開発を簡素化していきたいと考えています。
#参考文献
1、python はどのようにしてパッケージを見つけるのですか?
2、Pip ユーザーガイド
3、python-lambda-local
4、python-lambda
5、Pythonのパッケージ管理ツールガイド
6、別のパーティション/ディレクトリのために apt-get を実行していますか?
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ