2026年こそPython2.7とお別れしたい
みなさんメリークリスマス。さいとうです。今日はAnsibleコミュニティ方面からきました。
Ansible Advent Calendar 2025の最終日の記事として、そろそろ真面目に考えはじめたPython2.7との別れについて、つらつらと書いてみたいと思います。今年もいい感じの図はありません文章だけですごめんなさい。
はじめに - Ansible CoreとAnsibleの関係
2025年12月25日現在、Ansible Coreの最新リリースは2.20.1、そして標準的なCollection(僕は選ばれし者たちと呼んでます)と合わせてAnsibleコミュニティーがパッケージングしてリリースしているAnsibleは13.1.0です。
Ansible Coreはいわゆるansibleコマンドやansible-playbookコマンドなどのコマンドラインインターフェイスと、templateモジュールやcopyモジュールといったbuiltin collectionを含んだエンジン部分です。
一般的にAnsibleと世の中で認識されているのは後者ですが、「バージョンは?」という質問に対する回答で帰ってくるのは前者のバージョンです。
この記事では、Ansibleとは後者のコミュニティーがパッケージングしてリリースしているバージョンを指すものとします。
Ansible CoreのPython2サポートの現在地
AnsibleのPlaybookを実行するときに意識すべきPythonインタプリタは2種類あります。
- Control Node Python: Playbookを実行する側(コントローラ)で必要なPythonインタプリタ。
- Target Python: 操作される側(ターゲット)でモジュールを実行するために必要なPythonインタプリタ。
このControl Node PythonとTarget Pythonのサポートマトリクスは以下のリンクで確認できます。
ご覧の通り、Ansibleコミュニティではコントローラ側のPythonインタプリタ(Control Node Python)はAnsible Core 2.11を最後にPython2.7は公式サポートされなくなりました。ターゲットノード側でのPython2サポートも実はAnsible Core 2.16で終了しています。
Control Node PythonとPython2.7
前述の通り、AnsibleはすでにPython2と決別しています。ですから、Python2.7とpipの組み合わてAnsible Coreをインストールしようとした場合、インストールの対象となるのは2.11.12までです。(ここでは利用可能なバージョンをリストアップさせるために、バージョンを無指定で実行しています)
$ python --version Python 2.7.5 $ pip --version pip 20.3.4 from /usr/lib/python2.7/site-packages/pip (python 2.7) $ pip install ansible-core== DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality. Defaulting to user installation because normal site-packages is not writeable ERROR: Could not find a version that satisfies the requirement ansible-core== (from versions: 0.0.1a1, 2.11.0b1, 2.11.0b2, 2.11.0b3, 2.11.0b4, 2.11.0rc1, 2.11.0rc2, 2.11.0, 2.11.1rc1, 2.11.1, 2.11.2rc1, 2.11.2, 2.11.3rc1, 2.11.3, 2.11.4rc1, 2.11.4, 2.11.5rc1, 2.11.5, 2.11.6rc1, 2.11.6, 2.11.7rc1, 2.11.7, 2.11.8rc1, 2.11.8, 2.11.9rc1, 2.11.9, 2.11.10rc1, 2.11.10, 2.11.11rc1, 2.11.11, 2.11.12rc1, 2.11.12) ERROR: No matching distribution found for ansible-core==
とはいえ、コントローラでサポートされなくなるというのは、利用者にとってそれほど大きな影響はないのではないかと思います。コントローラがPython2.7を標準Pythonインタプリタとしているような古いOSで動作していても、OSのディストリビュータからPython3インタプリタが提供されていることが多いので、Python2とPython3を共存させる形で運用できるかもしれません。
いざとなったらAnsible Coreの実行環境をコンテナ化してコントローラのOSから分離してしまって、コンテナ中でPythonインタプリタを含めてメンテナンスしていくという手もあります。Ansible Navigator、Ansible Runner、Execution Environment Containerの組み合わせであれば、このようなアイデアを比較的簡単(だと思う)に実現できます。
ちなみに、Ansible Coreの最新版を利用したいのであれば、Control Node PythonとしてPython3.12以降が必要です。
$ pip3.11 index versions ansible-core ansible-core (2.19.5) Available versions: 2.19.5, 2.19.4, ... , 2.11.0 $ pip3.12 index versions ansible-core ansible-core (2.20.1) Available versions: 2.20.1, 2.20.0, ... , 2.11.0
Target PythonとPython2.7
Ansible Core 2.16までは、Target Python(つまり自動化の対象となるターゲットノードのPythonインタプリタ)として公式にPython2.7をサポートしています。Ansibleのテクニカルサポートを提供している企業が、サポート対象のAnsible Coreの実行環境でいまだに2.16を標準的に提供している理由は恐らくこれです。
ターゲットノードでは、Ansible Coreのコマンド群やプラグインを実行するわけではありません。モジュールから生成されたプログラムさえSSH経由で実行できれば良いわけです。 そのためControl Node Pythonのように、Ansible Coreやそれが利用しているPythonライブラリ群の利用要件にしたがってPythonバージョンを上げていく必要性も「あまり」ありません。
そこで、可能な限り幅広いターゲットノードをカバーするというコンセプトで、Target PythonはControl Node Pythonよりも緩いバージョン縛りになっています。
Target Pythonで注意すべきこと
Ansible Coreは、Playbookをタスク単位で実行します。一般的に、タスクにはモジュールとそのパラメータが指定され、Windows以外のターゲットを対象にしているタスクでは、指定したモジュールとパラメータをもとに、実行可能なPythonプログラムが生成されてターゲットノードにSSH経由で転送されます。
以下は、ansible.posix collectionのインテグレーションテストからの抜粋です。この場合はfirewalldモジュールをベースにPythonプログラムが生成されます。
- name: Firewalld port range test permanent enabled
ansible.posix.firewalld:
port: 5500-6850/tcp
permanent: true
state: enabled
register: result
タスクをもとに生成されたPythonプログラムは、Ansible Coreが提供するいくつかのPythonライブラリが含まれた形でZIP圧縮されて作られます。これらのライブラリは、モジュールから利用される基本的な機能を提供していて、実行時に解凍されてターゲットノード上の作業ディレクトリに展開されます。最終的に、モジュールはこれらのライブラリの助けを借りながらターゲットノード上で仕事をすることになるわけです。
このタスク(モジュール)実行の仕組みが今回のポイントで、モジュールから生成されたPythonプログラムはターゲットノード上のPythonインタプリタ(Target Python)を利用して実行されます。
Ansible 2.8(当時はAnsible CoreではなくAnsibleと呼ばれていました)からは、このターゲットノード上のPythonインタプリタをOSのディストリビューションとバージョンから自動判別するInterpreter Discoveryという機能が実装されています。最優先で選択されるのはPython3なので、Python2とPython3を含めた複数のバージョンのPythonインタプリタが動作しているシステムでは /usr/bin/Python3 が優先して選択されます。
このInterpreter Discoveryの恩恵で、利用者はターゲットノード上のPythonインタプリタをあまり意識しなくても済むようになったわけですが、困ったもので世の中には、Red Hat Enterprise Linux 7 のようにOS標準のPythonインタプリタが2.7であり、Python3がインストールされていない環境も存在しています。
現実には、このような環境んもカバーしなければなりませんから、簡単にはPython2を切り捨てることはできません。このために、モジュール側でPython2とPython3の両方をカバーするようなコードを書く必要性が生じます。
モジュールでPython2とPython3の差異を吸収する
PythonコードをPython2でもPython3でも動作するようにする...というのは思いのほか面倒です。そこで世の中にはsixというPythonライブラリが提供されていて、コレを使えばPython2とPython3両方に対応したコードを比較的楽に書くことができます。
ゼロから書くのは大変なのでsixを使おう...あぁまじでよかったPythonコミュニティありがとう。なんて思うかもしれませんが、Ansibleが行う自動化の性質上そう簡単にはいかないのです。
$ pip install six Collecting six Downloading six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB) Downloading six-1.17.0-py2.py3-none-any.whl (11 kB) Installing collected packages: six Successfully installed six-1.17.0 $ Name: six Version: 1.17.0 Summary: Python 2 and 3 compatibility utilities Home-page: https://github.com/benjaminp/six Author: Benjamin Peterson Author-email: benjamin@python.org License: MIT Location: /home/azureuser/devel/venv/devel/lib64/python3.12/site-packages Requires: Required-by:
なぜなら、「モジュールはターゲットノードのPythonインタプリタで実行される」からです。つまり、sixを使ったモジュールを実行することでターゲットノードに自動化を適用したいのであれば、モジュールが必要とするsixを含めたPythonライブラリ群もすべてターゲットノード上にあらかじめインストールされていなければならないからです。
検証用の数台ならいいけれど、数千台あるターゲットノードにsixをインストールします? 無理ですよねぇもう絶望しかないですよ...絶望には慣れてるけど...
sixあります
そんなかわいそうすぎる我々のために、Ansible Coreはヘルパーモジュールとして自前のsixを提供してくれています。
$ python Python 3.13.9 (main, Oct 14 2025, 00:00:00) [GCC 14.3.1 20250617 (Red Hat 14.3.1-2)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from ansible.module_utils import six >>> six.PY2 False >>> six.PY3 True >>>
以下はstable-11の community.general.decompress モジュールのsixを利用している箇所の抜粋です。Pythonインタプリタのバージョンによって呼び出すメソッドを変えていますが、その判定に自前のsixが使われています。
...
from ansible.module_utils import six
...
def bz2_decompress(src):
if six.PY3:
return bz2.open(src, "rb")
else:
return bz2.BZ2File(src, "rb")
...
ところで、このsixは前述したZIP圧縮されたPythonプログラムに含まれる形で配布されます。
$ tree $HOME/.ansible/
/home/foo/.ansible/
└── tmp
└── ansible-tmp-1766630173.576013-11733-80347744334354
└── AnsiballZ_setup.py
このAnsiballZモジュール名.pyは、ansible.builtin.setupを実行したときに生成されるPythonプログラムで、自己解凍式になっています。そして、このAnsiballZモジュール名.pyは、自前のsixを含む形で生成されるので、ターゲットノード上で実行時に解凍されれば、sixも同時に配置される仕組みになっています。
$ cd $HOME/.ansible/tmp/ansible-tmp-1766630173.576013-11733-80347744334354
$ python AnsiballZ_setup.py explode
Module expanded into:
/home/foo/.ansible/tmp/ansible-tmp-1766630173.576013-11733-80347744334354/debug_dir
$ find . -type d -name "six" -exec find {} \;
./debug_dir/ansible/module_utils/six
./debug_dir/ansible/module_utils/six/__init__.py
ここまで説明したように、Python2をサポートし続けるということは、Pythonインタプリタのバージョンによる振る舞いの違いを、モジュールやプラグインでケアし続けるということを意味します。そして、それはAnsible Coreが独自実装・提供しているsixに依存することで成立しているのです。
Target PythonもPython2とお別れしたいの
Ansible Coreは自前のsixを提供することで、モジュールがPython2とPython3の両方をサポートしやすい仕組みを提供しています。しかし、Python2はすでにサポートされなくなっていますから、このsixもいつまで提供されるかわかりません。そこで、モジュールを提供するCollection側でもPython2を見切る動きが進んでいます。
たとえば、先ほど例にあげた community.general.decompress は、stable-12ではすでにPython2を見切っています。
...
def bz2_decompress(src):
return bz2.open(src, "rb")
...
上記のコードでは、Python2,3の判定箇所が削除され、残されているのはPython3向けのコードのみとなっていますから、Python2では動作しません。
$ python Python 2.7.5 (default, Aug 13 2020, 02:51:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import bz2 >>> src = "/tmp/testfile.bz2" >>> bz2.open(src, "rb") Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'open' >>> bz2.BZ2File(src, "rb") <bz2.BZ2File object at 0x7f7712659168>
つまり、最新のcommunity.general collectionでは、Python2を利用した場合の動作は保証されない状況になっています(モジュールによっては動くかもしれないし、動かないかもしれない)。
Ansibe Coreがこの先も継続してsixを提供し続ける可能性はそれほど多くないでしょう。将来的にこのsixが廃止される可能性を考えると、遠からずCollecitonのメンテナたちはPython2を見切ってPython3だけを意識したコードにシフトすることになります。
2026年のAnsibleとわたし
ターゲットノードの古いOSは、現在も延長サポートによって延命できているかもしれませんが、それにも限界があります。周囲のエコシステムの状況を考えると、2026年はAnsibleに関わる我々にとって「Pythonの世代交代を真剣に見据える年」になりそうです。
ほとんどのOSSプロダクトは、それ単体だけで構成されているわけではなく、さまざまなライブラリ群を利用しています。それらの動作要件で変えたくなくても変わらざるをえない場合もあるのです。 つらつらと書きましたが、個人的に、2026年は「この先のターゲットノードのPythonインタプリタをどう扱うべきか」を真剣に考える良いチャンスではないかと思っています。
それではみなさん素敵なクリスマスを!