CentOS 7, Ansible and the end of Python 2
Python 2 vs 3 mismatches have been causing problems in our CentOS 7 server adminstration. We use Ansible for automatic configuration and continuous integration deployments. A few of our long-used jobs recently broke because Python 2 dependencies were out-of-date. CentOS 7 itself depends on Python 2. It is officially supported until June 2024, but I think that the sunsetting of Python 2 will hasten its demise.
The notes below explain how we solved our issues with CentOS 7 and Ansible. Hopefully they will be helpful to others.
Background
Ansible configures servers by connecting via SSH and running
shell scripts and/or Python scripts to apply the requested settings.
In CentOS 7, these scripts are run by Python 2.7.
This causes two main problems with Python tools installed using the pip
package manager:
- An increasing number of packages are Python 3 only, and others are not receiving updates for Python 2. Ansible’s
pip
module uses the system Python 2 interpreter by default, so it may fail or get an out-of-date version. - Other Ansible modules rely on Python libraries installed on the system. By default, Ansible will try to use the Python 2 version. Again, these may be missing or old.
Making Ansible work with Python 3
The solution to this is to make Ansible use Python 3 on the target system. The following steps are required:
Ensure Python 3 and pip are present
The following tasks ensure the server is able to use Python 3.
---
- name: Install python 3.6 and pip3
yum:
name:
- python36
- libselinux-python
state: present
- name: Install SELinux for Python 3
pip:
name:
- selinux
state: present
executable: pip3
vars:
ansible_python_interpreter: /usr/bin/python3
Note that Python 3 is not available in the default repositories, so it is
necessary to enable the EPEL repo or
similar. EPEL has Python 3.6, which automatically includes pip3
. The
SELinux dependencies are required by some Ansible modules.
Use pip3 to install packages
The Ansible pip
module has a executable
option to specify which pip
to
use. Use this to install
packages to the system’s Python 3.
- name: Install ETLHelper
pip:
name:
- etlhelper
state: present
executable: pip3
Tell Ansible to use Python 3 interpreter where required
Ansible uses the ansible_python_interpreter
variable to define which Python to
use. This must be specified wherever a module uses a Python 3 dependency e.g.
- name: Use dnsupdate to update ip host
nsupdate:
server: ""
zone: ""
record: ""
value: ""
ttl: 600
vars:
ansible_python_interpreter: /usr/bin/python3
Without this setting, the task will fail with an ImportError
as the Python
2 interpreter fails to find the library installed via pip3
.
Ansible reads variable definitions according to a defined
hierarchy.
In the example above, the variable only applies for a single
task and Python 2 is used elsewhere. We find this preferable to setting for
an entire host or playbook because it makes the intention more explicit.
Also, some modules (notably yum
) will only work with Python 2, so using Python 3 for the whole playbook will break those steps.
Trivia: yum
(“Yellowdog updater, modified”) is the package manager in CentOS 7. It requires Python 2. CentOS 8 uses dnf
package manager (“Dandified Yum”), which can use Python 3.
comments