Amazon Linux 2で気付いたら変更したPythonのバージョンが元に戻っていた話

2019.08.20

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

こんにちは。インテグレーション部の大高です。

最近、Amazon Linux 2を利用していて困ったことがあったのでご紹介したいと思います。

前提

あるAMIを作成しており、標準のpython2.7以外にpython3.5.6を個別にインストールした後にalternativesコマンドを利用してpythonコマンドをpython3.5.6に設定していました。

シンボリックリンクとしては以下のような状態です。

$ ll /usr/bin/python
(略) /usr/bin/python -> /etc/alternatives/python
$ ll /etc/alternatives/python
(略) /etc/alternatives/python -> /usr/bin/python3.5

この設定をしたものをAMI化しました。

Python3に設定したはずがPython2になっていた…!

上記のAMIをインスタンスタイプ t2.nano で起動すると、設定した通りPython3のままとなっています。

$ python --version
Python 3.5.6

一方で、インスタンスタイプ t2.small で起動したところ、Pythonのバージョンが2.7になっていました。

$ python --version
Python 2.7.16

これは一体…?

原因はどこに?

pythonのリンボリックリンクが以下のようになっていたので、どこかで書き変わっているはずです。

$ ll /usr/bin/python
(略) /usr/bin/python -> /usr/bin/python2

ということで、/var/log/messages を調べます。

(略) cloud-init: 7 package(s) needed (+0 related) for security, out of 12 available
(略) cloud-init: Resolving Dependencies
(略) cloud-init: --> Running transaction check
(略) cloud-init: ---> Package bind-libs.x86_64 32:9.9.4-73.amzn2.1.2 will be updated
(略) cloud-init: ---> Package bind-libs.x86_64 32:9.9.4-74.amzn2.1.2 will be an update
(略) cloud-init: ---> Package bind-libs-lite.x86_64 32:9.9.4-73.amzn2.1.2 will be updated
(略) cloud-init: ---> Package bind-libs-lite.x86_64 32:9.9.4-74.amzn2.1.2 will be an update
(略) cloud-init: ---> Package bind-license.noarch 32:9.9.4-73.amzn2.1.2 will be updated
(略) cloud-init: ---> Package bind-license.noarch 32:9.9.4-74.amzn2.1.2 will be an update
(略) cloud-init: ---> Package bind-utils.x86_64 32:9.9.4-73.amzn2.1.2 will be updated
(略) cloud-init: ---> Package bind-utils.x86_64 32:9.9.4-74.amzn2.1.2 will be an update
(略) cloud-init: ---> Package python.x86_64 0:2.7.14-58.amzn2.0.4 will be updated
(略) cloud-init: ---> Package python.x86_64 0:2.7.16-1.amzn2.0.1 will be an update
(略) cloud-init: ---> Package python-devel.x86_64 0:2.7.14-58.amzn2.0.4 will be updated
(略) cloud-init: ---> Package python-devel.x86_64 0:2.7.16-1.amzn2.0.1 will be an update
(略) cloud-init: ---> Package python-libs.x86_64 0:2.7.14-58.amzn2.0.4 will be updated
(略) cloud-init: ---> Package python-libs.x86_64 0:2.7.16-1.amzn2.0.1 will be an update
(略) cloud-init: --> Finished Dependency Resolution
(略) cloud-init: Dependencies Resolved
(略) cloud-init: ================================================================================
(略) cloud-init: Package            Arch       Version                     Repository      Size
(略) cloud-init: ================================================================================
(略) cloud-init: Updating:
(略) cloud-init: bind-libs          x86_64     32:9.9.4-74.amzn2.1.2       amzn2-core     1.0 M
(略) cloud-init: bind-libs-lite     x86_64     32:9.9.4-74.amzn2.1.2       amzn2-core     744 k
(略) cloud-init: bind-license       noarch     32:9.9.4-74.amzn2.1.2       amzn2-core      87 k
(略) cloud-init: bind-utils         x86_64     32:9.9.4-74.amzn2.1.2       amzn2-core     207 k
(略) cloud-init: python             x86_64     2.7.16-1.amzn2.0.1          amzn2-core      92 k
(略) cloud-init: python-devel       x86_64     2.7.16-1.amzn2.0.1          amzn2-core     402 k
(略) cloud-init: python-libs        x86_64     2.7.16-1.amzn2.0.1          amzn2-core     7.5 M
(略) cloud-init: Transaction Summary
(略) cloud-init: ================================================================================
(略) cloud-init: Upgrade  7 Packages

いました。cloud-initでのsecurity用のパッケージアップグレード処理でpythonが更新されていますね。この際にpythonのシンボリックリンクが上書きされていました。

なお、試しに /etc/cloud/cloud.cfg で以下のようにパッケージのアップグレードをしないように設定すると上記の更新は掛からなくなることを確認しました。

(抜粋)

datasource_list: [ Ec2, None ]
repo_upgrade: none  # security

ちなみに、t2.nano ではこの現象が起きなかった原因を調べたところyum update時にCannot allocate memoryエラーでアップデートが出来ていなかった、というオチでした。

対策

上記のようにcloud-init時にパッケージのアップグレードをさせないということもできますが、セキュリティを考慮してアップグレードはさせておきたいと思います。

ですので、systemdを利用してcloud-init後にシンボリックリンクを再度上書きしてしまいます。Unitファイルは以下のような感じです。

/etc/systemd/system/python_settings.service

[Unit]
Description=python_settings
After=cloud-final.service

[Service]
ExecStart=/opt/python_settings/start.sh
Restart=no
Type=simple
RemainAfterExit=yes
KillMode=none

[Install]
WantedBy=cloud-init.target

/opt/python_settings/start.sh

#!/bin/bash

unlink /usr/bin/python
ln -s /etc/alternatives/python /usr/bin/python

これで、cloud-initの後に再度pythonのシンボリックリンクが上書きされます。

まとめ

Pythonのシンボリックリンクが上書きされるとは思っていなかったので完全な盲点でした。また、なにはともあれ/var/log/messagesを読むことは大事ですね。

どなたかのお役に立てば幸いです。それでは!