Amazon Linux 2上でpip install
しようとしたところ、以下の警告に遭遇したので、調べたことを書く。
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead
まとめ
- root(sudo)で
pip install
作業をすることに対するセキュリティ的な警告ではない。 - パッケージをグローバルインストールすることでパッケージがコンフリクトするリスクがあることを警告している。
pip install
にはグローバルインストール(デフォルト)と--user
をオプションに付けるローカルインストールが存在する。- 上記1〜3を理解した上でパッケージをグローバルインストールしたい場合は無視してよい(と私は理解した)。
事象
rootユーザーでpip install
しようとしたところ、以下のように前述の警告が出た。(インストール自体はできる。)
[root@ip-172-31-27-206 ~]# pip3 install django WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead. Collecting django Using cached https://files.pythonhosted.org/packages/9d/04/04abb097c84c770180eeebe7ed920ce42f9917ab5ad4de01ff8ed11bc25b/Django-3.0.6-py3-none-any.whl Requirement already satisfied: pytz in /usr/local/lib/python3.7/site-packages (from django) Requirement already satisfied: asgiref~=3.2 in /usr/local/lib/python3.7/site-packages (from django) Requirement already satisfied: sqlparse>=0.2.2 in /usr/local/lib/python3.7/site-packages (from django) Installing collected packages: django Successfully installed django-3.0.6 [root@ip-172-31-27-206 ~]#
rootユーザーで直接pip install
しようとしたことに対する警告なのかと思い、ec2-userからsudoで実行してみたが、同じ警告が出る。
[ec2-user@ip-172-31-27-206 ~]$ sudo pip3 install django WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead. Collecting django Using cached https://files.pythonhosted.org/packages/9d/04/04abb097c84c770180eeebe7ed920ce42f9917ab5ad4de01ff8ed11bc25b/Django-3.0.6-py3-none-any.whl Requirement already satisfied: asgiref~=3.2 in /usr/local/lib/python3.7/site-packages (from django) Requirement already satisfied: pytz in /usr/local/lib/python3.7/site-packages (from django) Requirement already satisfied: sqlparse>=0.2.2 in /usr/local/lib/python3.7/site-packages (from django) Installing collected packages: django Successfully installed django-3.0.6 [ec2-user@ip-172-31-27-206 ~]$
とりあえずインストールはできるので、検証用の環境であれば気にしなくてよいかもしれないが、ちゃんとしたサーバー構築の際にはこういうのは大事なので、調べてみることにした。
パッケージがインストールされるディレクトリ
そもそも、pip install
したパッケージはどこに保存されているのかというところから確認してみる。
以下のようにpip show
を実行すると、パッケージは/usr/local/lib64/python3.7/site-packages/〜
配下に保存されていることが分かる。
[root@ip-172-31-27-206 ~]# pip3 show django | grep "Location" Location: /usr/local/lib64/python3.7/site-packages [root@ip-172-31-27-206 ~]#
ls
で/usr/local/lib64/python3.7/site-packages/〜
配下を確認すると、確かにインストールしたパッケージが保存されていることを確認できる。
[root@ip-172-31-27-206 ~]# ls /usr/local/lib64/python3.7/site-packages 56fa58acf89604978a41__mypyc.cpython-37m-x86_64-linux-gnu.so django Django-3.0.6.dist-info mypy mypy-0.770.dist-info mypyc regex regex-2020.5.14.dist-info typed_ast typed_ast-1.4.1.dist-info [root@ip-172-31-27-206 ~]#
rootユーザー(sudo)以外ではインストールできない。
「Running pip install with root privileges is generally not a good idea.」と警告されるが、以下の通り、/usr/local/lib64/python3.7/site-packages
はrootユーザー以外には書き込み権限がないので、rootユーザー(sudo)以外ではpip install
で該当ディレクトリ配下にパッケージをインストールすることはできない。
[root@ip-172-31-27-206 ~]# ls -ld /usr/local/lib64/python3.7/site-packages drwxr-xr-x 11 root root 266 May 21 15:27 /usr/local/lib64/python3.7/site-packages [root@ip-172-31-27-206 ~]#
実際に、ec2-userでsudoなしでpip install
しようとすると、「Permission denied」が出て失敗する。
[ec2-user@ip-172-31-27-206 ~]$ pip3 install requests Collecting requests Downloading https://files.pythonhosted.org/packages/1a/70/1935c770cb3be6e3a8b78ced23d7e0f3b187f5cbfab4749523ed65d7c9b1/requests-2.23.0-py2.py3-none-any.whl (58kB) 100% |████████████████████████████████| 61kB 3.0MB/s Collecting chardet<4,>=3.0.2 (from requests) Downloading https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl (133kB) 100% |████████████████████████████████| 143kB 5.1MB/s Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests) Downloading https://files.pythonhosted.org/packages/e1/e5/df302e8017440f111c11cc41a6b432838672f5a70aa29227bf58149dc72f/urllib3-1.25.9-py2.py3-none-any.whl (126kB) 100% |████████████████████████████████| 133kB 7.6MB/s Collecting idna<3,>=2.5 (from requests) Downloading https://files.pythonhosted.org/packages/89/e3/afebe61c546d18fb1709a61bee788254b40e736cff7271c7de5de2dc4128/idna-2.9-py2.py3-none-any.whl (58kB) 100% |████████████████████████████████| 61kB 9.3MB/s Collecting certifi>=2017.4.17 (from requests) Downloading https://files.pythonhosted.org/packages/57/2b/26e37a4b034800c960a00c4e1b3d9ca5d7014e983e6e729e33ea2f36426c/certifi-2020.4.5.1-py2.py3-none-any.whl (157kB) 100% |████████████████████████████████| 163kB 6.6MB/s Installing collected packages: chardet, urllib3, idna, certifi, requests Exception: Traceback (most recent call last): File "/usr/lib/python3.7/site-packages/pip/basecommand.py", line 215, in main status = self.run(options, args) File "/usr/lib/python3.7/site-packages/pip/commands/install.py", line 365, in run strip_file_prefix=options.strip_file_prefix, File "/usr/lib/python3.7/site-packages/pip/req/req_set.py", line 784, in install **kwargs File "/usr/lib/python3.7/site-packages/pip/req/req_install.py", line 854, in install strip_file_prefix=strip_file_prefix File "/usr/lib/python3.7/site-packages/pip/req/req_install.py", line 1069, in move_wheel_files strip_file_prefix=strip_file_prefix, File "/usr/lib/python3.7/site-packages/pip/wheel.py", line 345, in move_wheel_files clobber(source, lib_dir, True) File "/usr/lib/python3.7/site-packages/pip/wheel.py", line 316, in clobber ensure_dir(destdir) File "/usr/lib/python3.7/site-packages/pip/utils/__init__.py", line 83, in ensure_dir os.makedirs(path) File "/usr/lib64/python3.7/os.py", line 221, in makedirs mkdir(name, mode) PermissionError: [Errno 13] Permission denied: '/usr/local/lib/python3.7/site-packages/chardet' [ec2-user@ip-172-31-27-206 ~]$
/usr/local/〜配下は何を配置する場所か?
脇道に逸れてしまうが、Linuxの/usr/local
というディレクトリの配下は、そもそも何を配置する場所なのか?というのも気になったので、ついでに調べてみた。
日本語の記事では以下の2つがとても分かりやすかった。
dqn.sakusakutto.jp
また、以下はLinux Foundationの公式ドキュメントである。
refspecs.linuxfoundation.org
The /usr/local hierarchy is for use by the system administrator when installing software locally. It needs to be safe from being overwritten when the system software is updated. It may be used for programs and data that are shareable amongst a group of hosts, but not found in /usr.
Locally installed software must be placed within /usr/local rather than /usr unless it is being installed to replace or upgrade software in /usr.
/usr/local階層は、ソフトウェアをローカルにインストールするときにシステム管理者が使用するためのものです。システムソフトウェアが更新されたときに上書きされないようにする必要があります。ホストのグループ間で共有可能であるが、/usrにはないプログラムおよびデータに使用できます。
ローカルにインストールされたソフトウェアは、/usrのソフトウェアを置換またはアップグレードするためにインストールされている場合を除き、/usrではなく/usr/local内に配置する必要があります。
(Google翻訳)
「local」という単語からローカルインストールをイメージしてしまうので、直観に反していて紛らわしいが、ユーザー間で共有したいソフトウェアを配置する際には、Linuxの世界では標準的に/usr/local
配下を使用するのだというくらいに理解しておくことにした。
pipの--userオプションについて
「`pip3 install --user` instead」の意味について調べていると、以下の記事を見つけた。
pyteyon.hatenablog.com
pip
には--user
というオプションがあり、これを付けるとユーザーのホームディレクトリ配下にパッケージがインストールされるとのことである。
実際にやってみた。
[ec2-user@ip-172-31-27-206 ~]$ pip3 install --user requests Collecting requests Using cached https://files.pythonhosted.org/packages/1a/70/1935c770cb3be6e3a8b78ced23d7e0f3b187f5cbfab4749523ed65d7c9b1/requests-2.23.0-py2.py3-none-any.whl Collecting idna<3,>=2.5 (from requests) Using cached https://files.pythonhosted.org/packages/89/e3/afebe61c546d18fb1709a61bee788254b40e736cff7271c7de5de2dc4128/idna-2.9-py2.py3-none-any.whl Collecting chardet<4,>=3.0.2 (from requests) Using cached https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests) Using cached https://files.pythonhosted.org/packages/e1/e5/df302e8017440f111c11cc41a6b432838672f5a70aa29227bf58149dc72f/urllib3-1.25.9-py2.py3-none-any.whl Collecting certifi>=2017.4.17 (from requests) Using cached https://files.pythonhosted.org/packages/57/2b/26e37a4b034800c960a00c4e1b3d9ca5d7014e983e6e729e33ea2f36426c/certifi-2020.4.5.1-py2.py3-none-any.whl Installing collected packages: idna, chardet, urllib3, certifi, requests Successfully installed certifi-2020.4.5.1 chardet-3.0.4 idna-2.9 requests-2.23.0 urllib3-1.25.9 [ec2-user@ip-172-31-27-206 ~]$
今回はインストールに成功した。
確かに、ホームディレクトリの.local
配下にパッケージがインストールされている。
[ec2-user@ip-172-31-27-206 ~]$ pwd /home/ec2-user [ec2-user@ip-172-31-27-206 ~]$ tree -L 4 .local .local ├── bin │ └── chardetect └── lib └── python3.7 └── site-packages ├── certifi ├── certifi-2020.4.5.1.dist-info ├── chardet ├── chardet-3.0.4.dist-info ├── idna ├── idna-2.9.dist-info ├── requests ├── requests-2.23.0.dist-info ├── urllib3 └── urllib3-1.25.9.dist-info 14 directories, 1 file [ec2-user@ip-172-31-27-206 ~]$
pip show
で確認すると、Locationも/home/ec2-user/.local
配下になっている。
[ec2-user@ip-172-31-27-206 ~]$ pip3 show requests | grep "Location" Location: /home/ec2-user/.local/lib/python3.7/site-packages [ec2-user@ip-172-31-27-206 ~]$
同じパッケージを「--user」を付けずにインストールしてみるとどうなるか?
今度は、同じパッケージを「--user」を付けずにインストールしてみるとどうなるか(インストールできるのか?コンフリクトしないのか?)というのが気になったので、再度rootユーザーになって実験してみた。
[root@ip-172-31-27-206 ~]# pip3 install requests WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead. Collecting requests Downloading https://files.pythonhosted.org/packages/1a/70/1935c770cb3be6e3a8b78ced23d7e0f3b187f5cbfab4749523ed65d7c9b1/requests-2.23.0-py2.py3-none-any.whl (58kB) 100% |████████████████████████████████| 61kB 2.6MB/s Collecting certifi>=2017.4.17 (from requests) Downloading https://files.pythonhosted.org/packages/57/2b/26e37a4b034800c960a00c4e1b3d9ca5d7014e983e6e729e33ea2f36426c/certifi-2020.4.5.1-py2.py3-none-any.whl (157kB) 100% |████████████████████████████████| 163kB 5.8MB/s Collecting idna<3,>=2.5 (from requests) Downloading https://files.pythonhosted.org/packages/89/e3/afebe61c546d18fb1709a61bee788254b40e736cff7271c7de5de2dc4128/idna-2.9-py2.py3-none-any.whl (58kB) 100% |████████████████████████████████| 61kB 9.3MB/s Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests) Downloading https://files.pythonhosted.org/packages/e1/e5/df302e8017440f111c11cc41a6b432838672f5a70aa29227bf58149dc72f/urllib3-1.25.9-py2.py3-none-any.whl (126kB) 100% |████████████████████████████████| 133kB 7.8MB/s Collecting chardet<4,>=3.0.2 (from requests) Downloading https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl (133kB) 100% |████████████████████████████████| 143kB 7.7MB/s Installing collected packages: certifi, idna, urllib3, chardet, requests Successfully installed certifi-2020.4.5.1 chardet-3.0.4 idna-2.9 requests-2.23.0 urllib3-1.25.9 [root@ip-172-31-27-206 ~]#
インストールには成功した。
pip show
で確認すると、rootユーザーの場合は向き先は/usr/local/lib/python3.7/site-packages
の方を向いている。
[root@ip-172-31-27-206 ~]# pip3 show requests | grep "Location" Location: /usr/local/lib/python3.7/site-packages [root@ip-172-31-27-206 ~]#
ec2-userでは/home/ec2-user/.local
の方を向いている。
[ec2-user@ip-172-31-27-206 ~]$ pip3 show requests | grep "Location" Location: /home/ec2-user/.local/lib/python3.7/site-packages [ec2-user@ip-172-31-27-206 ~]$
探索の優先順位に関するドキュメントの記述は見つけられなかったが、ローカルとグローバルで同じパッケージがインストールされている場合は、ローカルインストールしたuserでログインしている場合には、ローカルインストールした方が使われる仕様になっているようである。
なぜ警告が出力されるのか?
エラーメッセージで検索したところ、最初に以下のissueがヒットした。
github.com
このissueには、さらに以下のissueを読めとコメントがあるので、流し読みしたところ、警告が出力される経緯がなんとなく理解できた。
github.com
上記のissueは--user
オプションをデフォルトにしようという提案である。(2020/5/22時点では未実装)
以下のコメントにあるように、この提案に至った背景は、元々はセキュリティの問題ではなく、パッケージをグローバルに管理することによるコンフリクトを防ごうという意図である。
sudo and security is really a secondary issue IMO.
this is primarily about preventing the conflict between OS packaging and pip in the system python.
Currently, linux users are often placed in an impossible situation.
--user
をデフォルトにするまでの橋渡しとして、警告を出すようにしているのだろうか。
また、FedoraはデフォルトでPython3系がインストールされているらしいので、OSのシステム管理で使用されているパッケージとアプリケーションで使用するパッケージがコンフリクトしてしまうということがあるのかもしれない。(isuueを挙げている人もFedoraを使用していた。)
この辺は私はFedora使ったことがないので分からないが、機会があれば検証してみたい。
Amzon Linux2の場合、デフォルトでインストールされているPythonは2系(2020/5/22時点)なので、Python3はアプリケーション用途専用で使用できるので、この点は考慮しなくて良い。
まとめ
「WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead」の意味、及び結論については以下の通り。
- root(sudo)で
pip install
作業をすることに対するセキュリティ的な警告ではない。 - パッケージをグローバルインストールすることでパッケージがコンフリクトするリスクがあることを警告している。
pip install
にはグローバルインストール(デフォルト)と--user
をオプションに付けるローカルインストールが存在する。- 上記1〜3を理解した上でパッケージをグローバルインストールしたい場合は無視してよい(と私は理解した)。