はじめに
サーバーのPythonのアップグレードに挑戦しました。かなり時間を取られたので、備忘録としてここにまとめます。
環境
- CentOS 7
- python3.6とpython2.7が予め入っている
1. pyenvのインストール
$ pyenv versions
以下のように出力されれば、インストールされていないことになります。バージョンが表示される場合は、インストールされているので読み飛ばしてください。
bash: pyenv: command not found...
pyenvのインストールは以下の記事を参考にしました。手順をまとめておきます。
1-1. pyenvの使用に必要となるパッケージのインストール
$ sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel git libffi-devel
1-2.ホームディレクトリ下にpyenvのリポジトリをクローンする
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
1-3. .bash_profileにpyenvのパスを追加
$ echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
1-4. pyenvのバージョンを確認
$ pyenv --version
pyenv 1.2.2-6-g694b551
2. pythonのインストール (失敗)
入手できる最新のpythonのバージョンを確認。
$ pyenv install --list
3.11.3を選びました。
$ pyenv install 3.11.3
とすれば問題なくpython3.11.3がインストールできるはずですが
ModuleNotFoundError: No module named '_ssl'
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?Please consult to the Wiki page to fix the problem.
https://github.com/pyenv/pyenv/wiki/Common-build-problems
とエラーが出てきてしまいました。どうやら、_sslというモジュールが無いというエラーのようです。
実際、以下のように打ち込み、インストールされているpythonのバージョンを確認してみても、3.11.3
は出てきません。
$ pyenv versions
調べてみると、たくさん記事が出てきました。
なるほど。python3.10.x以降はopen-sslのバージョンが1.1.1以上でないとダメらしいです。open-sslとはchatGPTによると以下のようなものだそうです。
OpenSSLは、オープンソースの暗号ライブラリとツールキットです。データの暗号化、復号化、署名、証明書の作成、プロトコルの実装など、さまざまな暗号化関連の機能を提供します。
では、今入っているopen-sslのバージョンを確認してみます。
$ openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
確かにバージョンは1.0.2です。ではアップグレードを試みましょう。
3. opensslのアップグレード
まず試したのは以下のスクリプトです。
sudo yum install openssl11-devel --allowerasing
Command line error: no such option: --allowerasing
怒られました。
次に試したのは以下のコマンドです。
sudo yum install openssl11-devel
0 packages excluded due to repository protections
No package openssl11-devel available.
また怒られました。
よく見ると、以下のように書いてあります。
This system is not registered with an entitlement server. You can use subscription-manager to register.
なるほど、エンタイトルメントサーバーじゃないからダメ。みたいな話でしょうか。調べてみたら以下のような記事が出てきました。
/etc/yum/pluginconf.d/subscription-manager.conf
の中身にある、enabled
の値を1から0に書き換えたらいいんですね。こちらの方が、もし万が一のことがあったときに書き直せばいいのでsudo subscription-manager register
とするよりも心理的にやりやすいです。
ということで、
$ vi /etc/yum/pluginconf.d/subscription-manager.conf
としてenabled=0
に書き換えました。
登録を済ませた?ところで再び実行です。
openssl11
もその開発用パッケージopenssl11-devel
もまとめてインストールします。
sudo yum install openssl11 openssl11-devel
No package openssl11 available.
No package openssl11-devel available.
ダメでした。
仕方ないのでソースコードから直接インストールする方法がないか調べてみたところ、以下の記事が見つかりました。
良さそうなので早速試してみることに。
3-1. 必要なパッケージのインストール
最初にインストールしたパッケージと一部被ってますが、気にせずインストールしました。
$ sudo yum install -y zlib-devel perl-core make gcc
3-2. opensslのダウンロード
次に、ソースコードをおいてあるサイトから、tar.gzファイルをダウンロード。
$ sudo curl https://www.openssl.org/source/openssl-1.1.1.tar.gz -o /usr/local/src/openssl-1.1.1.tar.gz
3-3. opensslのインストール
そしてOpenSSLのインストールです。
$ cd /usr/local/src
$ sudo tar xvzf openssl-1.1.1.tar.gz
$ cd openssl-1.1.1/
$ sudo ./config --prefix=/usr/local/openssl-1.1.1 shared zlib
$ sudo make depend
$ sudo make
$ sudo make test
$ sudo make install
インストールされたかを確認しましょう。以下のようになればOKです。
$ sudo ls -l /usr/local/openssl-1.1.1
total 0
drwxr-xr-x 2 root root 37 Jul 11 13:57 bin
drwxr-xr-x 3 root root 21 Jul 11 13:57 include
drwxr-xr-x 4 root root 159 Jul 11 13:57 lib
drwxr-xr-x 4 root root 28 Jul 11 13:58 share
drwxr-xr-x 5 root root 140 Jul 11 13:57 ssl
3-4. opensslのライブラリ群を追加する
どうやら、ライブラリの追加という操作が必要なようです。
以下のサイトを参考にしました。
$ vi /etc/ld.so.conf.d/openssl-1.1.1.conf
として、
/usr/local/openssl-1.1.1/lib
と書き込みました。
3-5. キャッシュファイルの更新
$ sudo ldconfig
3-6. ライブラリが追加されたことを確認
$ sudo ldconfig -p | grep libssl
これで、
libssl.so.1.1 (libc6,x86-64) => /usr/local/openssl-1.1.1/lib/libssl.so.1.1
libssl.so (libc6,x86-64) => /usr/local/openssl-1.1.1/lib/libssl.so
が追加されていれば(あれば)OKです。
3-7. 動作確認
以下のコマンドで問題なくインストールされていることがわかります。
$ sudo /usr/local/openssl-1.1.1/bin/openssl ciphers -v TLSv1.3
TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
さて、これで最新のOpenSSLがインストールできたので、自信をもってpyenv install
ができますね。
pyenvの実行再び
$ pyenv install 3.11.3
ModuleNotFoundError: No module named '_ssl'
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?
ダメでした。
OpenSSLは問題なくインストールできたはず。インストールできてるよね?ってことで調べてみる。
$ openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
できてない。いやでも間違いなくサーバーの何処かにちゃんとしたOpenSSLはおいてあるはず。ということは従来のバージョンと競合してるかもしれない。ログアウトして再度ログインしても問題は解決しない。さっきインストールしたOpenSSLは/usr/local/openssl-1.1.1/bin/openssl
にある。
ということで絶対パスで確認してみる。
$ /usr/local/openssl-1.1.1/bin/openssl version
OpenSSL 1.1.1 11 Sep 2018
ビンゴ。絶対パスで指定してあげればちゃんと機能するってことは、正しくインストールはできたけど、opensslとコマンドを打つときに従来のopensslがまず読み込まれるようになっているということでしょう。これは従来のopensslがおいてあるPATHよりも前に、/usr/local/openssl-1.1.1/bin/openssl
をPATHとして指定すれば解決しそう。
ということで、
$ vi .bashrc
として、
export PATH="/usr/local/openssl-1.1.1/bin/:$PATH"
とすれば良いんじゃないだろうか。
source ~/.bashrc
として変更を反映させて、
$ openssl version
OpenSSL 1.1.1 11 Sep 2018
うまくいきました。これでようやくpyenvが使えそうです。
$ pyenv install 3.11.3
ModuleNotFoundError: No module named '_ssl'
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?
ダメでした。
調べてみたところ、opensslが標準の場所とは違うところにインストールされたせいで、pythonのビルドがうまく行かないそう(以下の記事参考)。そこで、OpenSSLのヘッダ・ライブラリを見つけられるように、PYTHON_CONFIGURE_OPTS
という環境変数にOpenSSLの場所を代入する必要があるみたいです。
上記の記事とはインストール場所が違うので、そこだけ書き換えた以下のコマンドを実行します。
$ echo 'export PYTHON_CONFIGURE_OPTS="--with-openssl=/usr/local/openssl-1.1.1"' >> ~/.bashrc
達成
流石に次はうまくいくだろうと思い、再度pyenv
を実行します。
$ pyenv install 3.11.3
Downloading Python-3.11.3.tar.xz...
-> https://www.python.org/ftp/python/3.11.3/Python-3.11.3.tar.xz
Installing Python-3.11.3...
Installed Python-3.11.3 to /root/.pyenv/versions/3.11.3
できました。
ようやくpython3.11.3がインストールできました。
以下のコマンドで、インストールができているか念のため確認します。アスタリスクの付いているものが現在の環境です。
$ pyenv versions
デフォルトで使用されるpythonを3.11.3にするために、
$ pyenv global 3.11.3
と実行して、
$ python -V
Python 3.11.3
と表示されればインストール終了です。
おまけ(一般ユーザーにも変化を適用する)
以下のように普段Pythonが使われているディレクトリに、新しくインストールしたPythonのシンボリックリンクを作成しました。
sudo ln -s $(pyenv which python) /usr/bin/python3.11
これで、
python3.11
というコマンドによって、誰でもpython3.11.3
を使うことが可能になりました。
結論
従来のPythonも残しつつ、新しいPythonも使えるようになりました。
追記:rootでやる必要はなかった
パッケージの保管場所など色々と面倒だったので、よく確認してみたら、上記のpyenvのインストールやpyenvの実行は別に一般ユーザーでもできることでした。なので、それぞれがpyenvをインストールしてopen-sslの問題をクリアして、好きなバージョンのpythonをインストールし管理する方がいい気がしました。
ですので、rootにインストールした新しいpyenvは
pyenb uninstall 3.11.3
として消しました。