【小ネタ】Lambda Layersのパッケージ作成に便利!!pipenvでsync対象ディレクトリを指定する方法

Pipfile.lockで定義されたライブラリを指定したディレクトリにインストールする方法をご紹介します。Lambda Layers用のパッケージ時に便利です!!
2019.10.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

CX事業本部@大阪の岩田です。

Lambda Layers用のパッケージを作成する際にpipenv syncでライブラリをインストールする対象のディレクトリを指定したかったのですが、それらしきオプションが見つからず色々と試行錯誤していました。最終的にpipの環境変数を使うことでうまく制御できたので手順をご紹介します。

注意!!

こちらの記事で紹介している手順ですが、pipenvのバージョンv2020.5.28からは意図通りに動作しなくなりました。以下のコミットで既にインストール済みのライブラリについてはインストール処理をスキップする最適化処理が追加されたのですが、この処理では常にデフォルトのディレクトリ(.venv/lib/python3.x/site-packages/ 等)をチェックしてライブラリがインストール済みかを判定しています。そのため、デフォルトのディレクトリにライブラリがインストールされた状態で、デフォルト以外のディレクトリに別途ライブラリをインストールしようとしても、インストールがスキップされてしまうのです。

Skip satisfied dependencies during installation

ライブラリがインストール済みかを判定する際に環境変数PIP_TARGETを考慮するよう修正するプルリクを上げているので、これがマージされれば以前のバージョンと同じ感覚で利用できるようになるはずです。 https://github.com/pypa/pipenv/pull/4776

pipenvでsync対象ディレクトリを指定する方法

まず結論から

PIP_TARGET="<targetdir>" pipenv sync

これで<targetdir>ディレクトリ配下にPipfile.lockで定義されたライブラリがインストールできます。 あとはZIPに固めてアップロードすれば必要なライブラリが導入されたLambda Layerの完成です!

ググるとpipenv lock -r | pip install -r /dev/stdin -t <targetdir>でイケるぜ!!みたいな記事がいくつかヒットしたのですが、これだと都度都度Pipfile.lockの更新が走ってしまうので、導入対象ライブラリが依存しているライブラリが開発環境とは異なるバージョンでインストールされるというリスクが残ります。 開発環境で仮想環境をアクティベートしてpipenv run pip freeze| pip install -r /dev/stdin -t <targetdir>を実行するのもアリですが、これだと余計なdevパッケージまでインストールされてしまいます。

pipの環境変数について

pipのUser Guideに記載があるのですが、pipのコマンドラインオプションは環境変数から指定することが可能です。設定すべき環境変数はpipのコマンドラインのロングオプションを

  1. 大文字に変換する
  2. -_に変換する
  3. 先頭にPIP_をつける

というルールで変換したものです。

pip’s command line options can be set with environment variables using the format `PIP_` . Dashes (`-`) have to be replaced with underscores (`_`).

pip 19.2.3 documentation

例えばPIP_TARGET=<targetdir> pip installというコマンドはpip install --target <targetdir>と同様の挙動となります。pipenv syncは内部的にpip installを実行するためPIP_TARGET=<targetdir> pipenv syncというコマンドはpipenv install --requirement <Pipfile.lockで定義されたライブラリ達> --target <targetdir>を実行することになり、Pipfile.lockで定義されたライブラリを指定したディレクトリにインストールすることが可能です。

まとめ

これで開発環境と同一バージョンのライブラリでLayerが作成可能です。 開発環境とLambda実行環境でライブラリのバージョンが違ってバグを踏んだ...なんてことがないように有効活用していきましょう