これは、なにをしたくて書いたもの?
Pythonのモジュールインストールにはpipを使うことが多いと思いますが、pipをオフライン環境で使う方法はないかな?と。
要するに、どこかでダウンロードしたパッケージを、オフラインの別の環境で使いたい、みたいな話です。
pipについて
そもそも、pipのドキュメントを見たことがありませんでした。こちらみたいですね。
Home - pip documentation v21.1.1
User Guideを見ていると、やりたいことがそのまま書いてありました…。
In some cases, you may want to install from local packages only, with no traffic to PyPI.
Installing from local packages
こちらを見ると、download
コマンドとinstall
コマンドのオプションで実現するようです。
が、ドキュメントに記載されているオプションが変な気が…(特にdownload
)。
download
コマンドのドキュメントは、こちらですね。
pip download does the same resolution and downloading as pip install, but instead of installing the dependencies, it collects the downloaded distributions into the directory provided (defaulting to the current directory). This directory can later be passed as the value to pip install --find-links to facilitate offline or locked down package installation.
pip download - pip documentation v21.1.1
オフライン環境で使えるようにするために、パッケージをディレクトリにダウンロードするコマンドです。
install
コマンドは、こちら。
pip install - pip documentation v21.1.1
User Guideによると、--no-index
、--find-links
の2つのオプションを使うようです。
意味は、それぞれこのようになっています。
- -f, --find-links
- --no-index
- パッケージインデックスを無視する(代わりに、
--find-links
で指定されたURLのみを参照する)
- パッケージインデックスを無視する(代わりに、
--find-links
でアーカイブの参照先を指定し、--no-index
で--find-links
で指定したディレクトリのみを参照させることで
実現するようです。
このあたりを実際に使っていってみようと思います。
環境
今回の環境は、こちらです。
$ python3 -V Python 3.8.5 $ pip3 -V pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)
お題
Flaskで簡単なWebアプリを作り、それをGunicornで動かす…という環境一式を、オフライン環境でも動かせるようにしたいと
思います。
確認は、仮想環境を2つ用意して行おうかな、と。
片方はパッケージのダウンロード用。もう片方は、オフラインインストール用ですね。
この2つのディレクトリを使いましょう。
$ mkdir source-project offline-project
プログラムを作成して、ライブラリをダウンロードする
まずは、確認用のプログラムを作成したいと思います。
$ cd source-project
仮想環境を有効にします。
$ python3 -m venv venv $ . venv/bin/activate
FlaskとGunicornをインストール。
$ pip3 install Flask==2.0.0 gunicorn==20.1.0
ダウンロードの様子。
Collecting Flask==2.0.0 Downloading Flask-2.0.0-py3-none-any.whl (93 kB) |████████████████████████████████| 93 kB 236 kB/s Collecting gunicorn==20.1.0 Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB) |████████████████████████████████| 79 kB 1.2 MB/s Collecting Werkzeug>=2.0 Downloading Werkzeug-2.0.0-py3-none-any.whl (288 kB) |████████████████████████████████| 288 kB 10.7 MB/s Collecting itsdangerous>=2.0 Downloading itsdangerous-2.0.0-py3-none-any.whl (18 kB) Collecting click>=7.1.2 Downloading click-8.0.0-py3-none-any.whl (96 kB) |████████████████████████████████| 96 kB 929 kB/s Collecting Jinja2>=3.0 Downloading Jinja2-3.0.0-py3-none-any.whl (133 kB) |████████████████████████████████| 133 kB 11.4 MB/s Requirement already satisfied: setuptools>=3.0 in ./venv/lib/python3.8/site-packages (from gunicorn==20.1.0) (44.0.0)
簡単なソースコードを作成。
index.py
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "Hello, World!!"
動作確認しましょう。Gunicornを起動。
$ gunicorn index:app
確認。
$ curl -i localhost:8000 HTTP/1.1 200 OK Server: gunicorn Date: Sun, 16 May 2021 15:09:50 GMT Connection: close Content-Type: text/html; charset=utf-8 Content-Length: 14 Hello, World!!
Content-Type
がデフォルトのtext/html
になっているのは、今は気にしないことにします。
動作確認ができたので、いったんGunicornを終了。
freeze
して、requirements.txt
を作成します。
$ pip3 freeze > requirements.txt
download
を実行します。ライブラリの保存先は、dependencies
というディレクトリにしました。
$ pip3 download -d dependencies -r requirements.txt
保存先のディレクトリの中身を見てみると、こうなっています。
$ ll dependencies 合計 1512 drwxrwxr-x 2 xxxxx xxxxx 4096 5月 17 00:12 ./ drwxrwxr-x 5 xxxxx xxxxx 4096 5月 17 00:12 ../ -rw-rw-r-- 1 xxxxx xxxxx 93174 5月 17 00:12 Flask-2.0.0-py3-none-any.whl -rw-rw-r-- 1 xxxxx xxxxx 133357 5月 17 00:12 Jinja2-3.0.0-py3-none-any.whl -rw-rw-r-- 1 xxxxx xxxxx 30551 5月 17 00:12 MarkupSafe-2.0.0-cp38-cp38-manylinux2010_x86_64.whl -rw-rw-r-- 1 xxxxx xxxxx 288104 5月 17 00:12 Werkzeug-2.0.0-py3-none-any.whl -rw-rw-r-- 1 xxxxx xxxxx 96881 5月 17 00:12 click-8.0.0-py3-none-any.whl -rw-rw-r-- 1 xxxxx xxxxx 79531 5月 17 00:12 gunicorn-20.1.0-py3-none-any.whl -rw-rw-r-- 1 xxxxx xxxxx 18240 5月 17 00:12 itsdangerous-2.0.0-py3-none-any.whl -rw-rw-r-- 1 xxxxx xxxxx 785278 5月 17 00:12 setuptools-56.2.0-py3-none-any.whl
ちょっとLinux依存と思われるものが含まれていますね。コマンドを実行しているプラットフォームの情報に依存している
みたいです。
これをなんとかしたかったら、もうちょっとオプションに踏み込む必要がありそうです。
pip download with the --platform, --python-version, --implementation, and --abi options provides the ability to fetch dependencies for an interpreter and system other than the ones that pip is running on.
--platform
や--python-version
あたりはポイントかもです。
--python-version <python_version>
今回は、このまま使うとしましょう。
ディレクトリをtar.gz
に固めて
$ tar czf dependencies.tar.gz dependencies
仮想環境を終了します。
$ deactivate
ダウンロードしたライブラリを使って、依存関係をインストールする
では、先ほどダウンロードしたライブラリとプログラムを使って、ライブラリのオフラインインストールと実行を試して
みましょう。
オフライン用のプロジェクト側に移動。
$ cd ../offline-project
仮想環境を作成して、有効化します。
$ python3 -m venv venv $ . venv/bin/activate
一応、pipのキャッシュも削除しておきましょう。
$ rm -rf ~/.cache/pip
先ほどのプロジェクトから、ライブラリとソースコード、そしてrequirements.txt
をコピー。
$ cp ../source-project/dependencies.tar.gz ../source-project/index.py ../source-project/requirements.txt ./.
tar.gz
ファイルを展開して
$ tar xf dependencies.tar.gz
--no-index
と--find-links
を指定して実行。
$ pip3 install --no-index --find-links=dependencies -r requirements.txt
実行時のログ。
Looking in links: dependencies Processing ./dependencies/click-8.0.0-py3-none-any.whl Processing ./dependencies/Flask-2.0.0-py3-none-any.whl Processing ./dependencies/gunicorn-20.1.0-py3-none-any.whl Processing ./dependencies/itsdangerous-2.0.0-py3-none-any.whl Processing ./dependencies/Jinja2-3.0.0-py3-none-any.whl Processing ./dependencies/MarkupSafe-2.0.0-cp38-cp38-manylinux2010_x86_64.whl Processing ./dependencies/Werkzeug-2.0.0-py3-none-any.whl Requirement already satisfied: setuptools>=3.0 in ./venv/lib/python3.8/site-packages (from gunicorn==20.1.0->-r requirements.txt (line 3)) (44.0.0) Installing collected packages: click, MarkupSafe, Jinja2, itsdangerous, Werkzeug, Flask, gunicorn Successfully installed Flask-2.0.0 Jinja2-3.0.0 MarkupSafe-2.0.0 Werkzeug-2.0.0 click-8.0.0 gunicorn-20.1.0 itsdangerous-2.0.0
インターネットからダウンロードしているような様子はなくなりました。
プログラムをGunicornで実行してみましょう。
$ gunicorn index:app [2021-05-17 00:25:02 +0900] [7586] [INFO] Starting gunicorn 20.1.0 [2021-05-17 00:25:02 +0900] [7586] [INFO] Listening at: http://127.0.0.1:8000 (7586) [2021-05-17 00:25:02 +0900] [7586] [INFO] Using worker: sync [2021-05-17 00:25:02 +0900] [7588] [INFO] Booting worker with pid: 7588
なにも問題なく起動します。
確認。
$ curl -i localhost:8000 HTTP/1.1 200 OK Server: gunicorn Date: Sun, 16 May 2021 15:25:32 GMT Connection: close Content-Type: text/html; charset=utf-8 Content-Length: 14 Hello, World!!
OKですね。
使用するライブラリによっては、オプションをもうちょっと調整しなくてはいけない気もしますが、だいたいやり方は
わかったのではないでしょうか。