オフライン環境でPythonパッケージをpipインストール

はじめに

世の中のシステムには、セキュリティ等の理由から外部ネットワークとの接続が遮断されているケースがあります。その場合、インターネット上から直接ソフトウェアのパッケージを取得してインストールを行うことができません。
上記のようなオフライン環境でPythonのパッケージをインストールする方法を調べてみました。

前提条件

Python 3.9.6で検証しています。
OSは、CentOS Stream 8インストールDVDのISOファイルから「最小限のインストール」を選択しインストールを行いました。
バージョン情報は以下の通りです。

# cat /etc/redhat-release 
CentOS Stream release 8
# uname -r
4.18.0-301.1.el8.x86_64

必要パッケージのインストール

「最小限のインストール」でOSをインストールした場合、ユーザプログラム向けのPythonがインストールされていないのでインストールを行います。また、サーバ間でファイルを転送する際の圧縮・展開のためにtarも併せてインストールします。オフライン環境の場合、OSのISOイメージなどからインストールしてください。

$ sudo dnf install -y python39 tar

パッケージファイルの取得

まずは、インターネット接続環境のサーバを使用して、インストール対象のパッケージファイルをインターネット上から取得します。

仮想環境へ切り替え

パッケージファイル取得の前に、既存環境を汚さないように仮想環境を作成し、環境を切り替えます。

$ python3 -m venv .venv
$ source .venv/bin/activate

pipのアップデート

pipモジュールが古いとパッケージファイルの取得に失敗することがあるので、最新バージョンに更新します。

$ pip install -U pip
(略)
Successfully installed pip-21.2.4

パッケージファイルの取得(個別取得)

パッケージを個別に取得する場合は、引数にパッケージ名を指定してpip downloadを実行します。-dオプションで、ダウンロード先のディレクトリを指定できます。ディレクトリの指定がない場合は、カレントディレクトリにパッケージファイルが保存されます。

以下の例では、ansibleおよび依存関係にあるパッケージをカレントディレクトリ直下のpackagesディレクトリに保存します。

$ pip download -d ./packages ansible
(略)
Saved ./packages/ansible-4.5.0.tar.gz
Saved ./packages/ansible-core-2.11.4.tar.gz
Saved ./packages/resolvelib-0.5.4-py2.py3-none-any.whl
Saved ./packages/cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl
Saved ./packages/cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl
Saved ./packages/Jinja2-3.0.1-py3-none-any.whl
Saved ./packages/MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Saved ./packages/packaging-21.0-py3-none-any.whl
Saved ./packages/pyparsing-2.4.7-py2.py3-none-any.whl
Saved ./packages/pycparser-2.20-py2.py3-none-any.whl
Saved ./packages/PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl
Successfully downloaded ansible ansible-core resolvelib cryptography cffi jinja2 MarkupSafe packaging pyparsing pycparser PyYAML

なお、引数として渡すパッケージ名はバージョン指定することも可能です。
例:pip download -d ./packages ansible==4.5.0

パッケージファイルの取得(一括取得)

複数のパッケージファイルを一括で取得する場合、requirements.txtに一覧を記載すると一括指定できて便利です。
テキストエディタを使用して、事前にrequirements.txtファイルを作成しておきます。

$ cat requirements.txt
ansible
ansible-core
resolvelib
cryptography
cffi
jinja2
MarkupSafe
packaging
pyparsing
pycparser
PyYAML

pip downloadコマンドに-rオプションを付けると、requirements.txtに記載のパッケージファイルを取得できます。

$ pip download -d ./packages -r requirements.txt
(略)
Saved ./packages/ansible-4.5.0.tar.gz
Saved ./packages/ansible-core-2.11.4.tar.gz
Saved ./packages/resolvelib-0.5.4-py2.py3-none-any.whl
Saved ./packages/cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl
Saved ./packages/cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl
Saved ./packages/Jinja2-3.0.1-py3-none-any.whl
Saved ./packages/MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Saved ./packages/packaging-21.0-py3-none-any.whl
Saved ./packages/pyparsing-2.4.7-py2.py3-none-any.whl
Saved ./packages/pycparser-2.20-py2.py3-none-any.whl
Saved ./packages/PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl
Successfully downloaded ansible ansible-core resolvelib cryptography cffi jinja2 MarkupSafe packaging pyparsing pycparser PyYAML

圧縮アーカイブファイル化

後ほどオフライン環境のサーバへファイルを転送しやすいように、packagesディレクトリを圧縮アーカイブファイルにまとめます。

$ tar zcvf packages.tar.gz ./packages
$ ls -l packages.tar.gz
-rw-rw-r--. 1 hoshino hoshino 46412021  9月  4 01:04 packages.tar.gz

パッケージのローカルインストール

ここからは、パッケージのインストールを行いたいオフライン環境のサーバで作業を行います。同サーバにパッケージをローカルインストールします。

パッケージファイルの転送

パッケージファイルの取得で作成した圧縮アーカイブファイルを、オフライン環境のサーバに転送します。同ファイルの内容を任意の場所に展開します。

$ ls -l packages.tar.gz 
-rw-rw-r--. 1 hoshino hoshino 46412021  9月  4 01:04 packages.tar.gz
$ tar zxvf packages.tar.gz
./packages/
./packages/ansible-4.5.0.tar.gz
./packages/ansible-core-2.11.4.tar.gz
./packages/resolvelib-0.5.4-py2.py3-none-any.whl
./packages/cryptography-3.4.8-cp36-abi3-manylinux_2_24_x86_64.whl
./packages/cffi-1.14.6-cp39-cp39-manylinux1_x86_64.whl
./packages/Jinja2-3.0.1-py3-none-any.whl
./packages/MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
./packages/packaging-21.0-py3-none-any.whl
./packages/pyparsing-2.4.7-py2.py3-none-any.whl
./packages/pycparser-2.20-py2.py3-none-any.whl
./packages/PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl

仮想環境へ切り替え

パッケージインストール対象のサーバでも、既存環境を汚さないように仮想環境を作成し、環境を切り替えます。

$ python3 -m venv .venv
$ source .venv/bin/activate

パッケージのローカルインストール(個別インストール)

パッケージを個別にインストールする場合は、引数にパッケージ名を指定してpip installを実行します。--no-indexオプションでインデックスサーバ(PyPI)への参照を無効化し、代わりに--find-linksオプションで指定したディレクトリ内からパッケージを検索します。

以下の例では、ansibleおよび依存関係にあるパッケージをカレントディレクトリ直下のpackagesディレクトリから検索しインストールします。

$ pip install --no-index --find-links=./packages ansible
(略)
Successfully installed MarkupSafe-2.0.1 PyYAML-5.4.1 ansible-4.5.0 ansible-core-2.11.4 cffi-1.14.6 cryptography-3.4.8 jinja2-3.0.1 packaging-21.0 pycparser-2.20 pyparsing-2.4.7 resolvelib-0.5.4

なお、pipのバージョンが古いとパッケージのインストールに失敗する場合があります。その場合は、pip自体を先にアップデートします。pipのパッケージファイルを事前に取得しておき、他パッケージをインストールする前に以下の要領でアップデートします。

$ pip install -U --no-index --find-links=./packages pip

パッケージのローカルインストール(一括インストール)

複数のパッケージファイルを一括でインストールする場合、requirements.txtを使用します。requirements.txtは、パッケージファイルの取得(一括取得)で使用したものをオフライン環境のサーバへ転送します。

pip installコマンドに-rオプションを付けると、requirements.txtに記載のパッケージファイルを一括インストールできます。

$ pip install --no-index --find-links=./packages -r requirements.txt
(略)
Successfully installed MarkupSafe-2.0.1 PyYAML-5.4.1 ansible-4.5.0 ansible-core-2.11.4 cffi-1.14.6 cryptography-3.4.8 jinja2-3.0.1 packaging-21.0 pycparser-2.20 pyparsing-2.4.7 resolvelib-0.5.4

インストール済みパッケージの確認

ローカルインストールが完了したら、pip listで対象パッケージがインストールされていることを確認します。

$ pip list
Package      Version
------------ -------
ansible      4.5.0
ansible-core 2.11.4
cffi         1.14.6
cryptography 3.4.8
Jinja2       3.0.1
MarkupSafe   2.0.1
packaging    21.0
pip          21.2.4
pycparser    2.20
pyparsing    2.4.7
PyYAML       5.4.1
resolvelib   0.5.4
setuptools   50.3.2

参考資料

User Guide – pip documentation v21.2.4

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です