Python is an open source, and widely used programming language known to be easy to learn and with powerful capabilities. There exists hundreds of libraries and frameworks created by the open source community that makes Python dynamic for adoption in any environment and varying use cases. Some of the popular python frameworks are Flask, Django, TensorFlow, PyTorch, Pandas, SciPy, among many others.
Overall, Python’s vast ecosystem make it a go-to programming language for a wide range of applications. You can use it as your favorite scripting language for Linux and other operating systems, and also to solve complex artificial intelligence and data analysis problems. To get the latest version of Python installed in your Debian or Ubuntu Linux, you’ll have to build from source. This article is created to automate the process of building and installing the latest release of Python from source using Ansible Playbook.
An Ansible playbook contains a set of instructions and tasks in YAML file. It is used to define and execute automations on a local host or remote server machines. A Playbook can be defined as the heart of Ansible configuration management since its execution results in the desired state of your system.
Before you can automate Python 3.x installation you’ll need Ansible installed. We have a number of articles that you can follow along to install Ansible.
$ ansible --version
ansible [core 2.16.0]
config file = None
configured module search path = ['/Users/jkmutai/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/Cellar/ansible/9.0.1/libexec/lib/python3.12/site-packages/ansible
ansible collection location = /Users/jkmutai/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.12.0 (main, Oct 2 2023, 12:03:24) [Clang 15.0.0 (clang-1500.0.40.1)] (/usr/local/Cellar/ansible/9.0.1/libexec/bin/python)
jinja version = 3.1.2
libyaml = True
Create inventory file with the IP address of Ubuntu or Debian server where Python is to be installed.
$ vim hosts
49.13.163.29
Create a Playbook for installing Python 3.x
vim build_install_python.yml
Here are the playbook contents. Parameters to set are host IP, remote user, and Python release number.
---
- name: Install Python 3.x on Debian / Ubuntu
hosts: 49.13.163.29
remote_user: root
become: yes
become_method: sudo
vars:
python_release: 3.12.1 # See https://www.python.org/downloads/source/
python_src_dir: /tmp
python_archive: Python-{{ python_release }}.tgz
python_url: "https://www.python.org/ftp/python/{{ python_release }}/{{ python_archive }}"
packages:
- git
- gcc
- make
- tar
- vim
- wget
- libncursesw5-dev
- libssl-dev
- libsqlite3-dev
- tk-dev
- libgdbm-dev
- libc6-dev
- libbz2-dev
- libffi-dev
- zlib1g-dev
- build-essential
- liblzma-dev
- tcl-dev
tasks:
- name: Upgrade OS packages
ansible.builtin.apt:
name: "*"
state: latest
update_cache: yes
- name: Check if a reboot is required
ansible.builtin.stat:
path: /var/run/reboot-required
get_checksum: no
register: reboot_required_file
- name: Reboot the server (if required).
ansible.builtin.reboot:
reboot_timeout: 900
when: reboot_required_file.stat.exists == true
- name: Install dependency packages
ansible.builtin.apt:
name: "{{ item }}"
state: latest
loop: "{{ packages }}"
- name: Download Python source archive
ansible.builtin.get_url:
dest: "{{ python_src_dir }}"
url: "{{ python_url }}"
- name: Extract archive
ansible.builtin.unarchive:
src: "{{ python_src_dir }}/{{ python_archive }}"
dest: "{{ python_src_dir }}"
remote_src: true
- name: Run ./configure
ansible.builtin.command:
cmd: ./configure --enable-optimizations --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
chdir: "{{ python_src_dir }}/Python-{{ python_release }}"
creates: "{{ python_src_dir }}/Python-{{ python_release }}/config.log"
- name: Run make to build python
community.general.make:
chdir: "{{ python_src_dir }}/Python-{{ python_release }}"
register: make_result
- name: Run make install
community.general.make:
chdir: "{{ python_src_dir }}/Python-{{ python_release }}"
target: install
register: install_result
when: make_result is not skipped
Default Python build configuration commands executed by playbook are as shown below. You can adjust them to suit your use case.
./configure --enable-optimizations --prefix=/usr/local --enable-shared LDFLAGS="-Wl,-rpath /usr/local/lib"
Copy SSH key to the remote server if you are doing password authentication.
ssh-copy-id remote_user@ServerIP
Next execute the playbook.
# Using user credentials defined in playbook file.
ansible-playbook -i hosts build_install_python.yml
# Using remote user called ubuntu with become password(sudo password)
ansible-playbook -i hosts build_install_python.yml --become --become-user=ubuntu --ask-become-pass
Sample execution output.
$ ansible-playbook -i hosts build_install_python.yml
PLAY [Install Python 3.x on Debian / Ubuntu] *********************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************************************
ok: [49.13.163.29]
TASK [Upgrade OS packages] ***************************************************************************************************************************************************************************
changed: [49.13.163.29]
TASK [Check if a reboot is required] *****************************************************************************************************************************************************************
ok: [49.13.163.29]
TASK [Reboot the server (if required).] **************************************************************************************************************************************************************
changed: [49.13.163.29]
TASK [Install dependency packages] *******************************************************************************************************************************************************************
ok: [49.13.163.29] => (item=git)
changed: [49.13.163.29] => (item=gcc)
changed: [49.13.163.29] => (item=make)
ok: [49.13.163.29] => (item=tar)
ok: [49.13.163.29] => (item=vim)
ok: [49.13.163.29] => (item=wget)
changed: [49.13.163.29] => (item=libncursesw5-dev)
changed: [49.13.163.29] => (item=libssl-dev)
changed: [49.13.163.29] => (item=libsqlite3-dev)
changed: [49.13.163.29] => (item=tk-dev)
changed: [49.13.163.29] => (item=libgdbm-dev)
ok: [49.13.163.29] => (item=libc6-dev)
changed: [49.13.163.29] => (item=libbz2-dev)
changed: [49.13.163.29] => (item=libffi-dev)
ok: [49.13.163.29] => (item=zlib1g-dev)
ok: [49.13.163.29] => (item=build-essential)
changed: [49.13.163.29] => (item=liblzma-dev)
ok: [49.13.163.29] => (item=tcl-dev)
TASK [Download Python source archive] ****************************************************************************************************************************************************************
changed: [49.13.163.29]
TASK [Extract archive] *******************************************************************************************************************************************************************************
changed: [49.13.163.29]
TASK [Run ./configure] *******************************************************************************************************************************************************************************
changed: [49.13.163.29]
TASK [Run make to build python] **********************************************************************************************************************************************************************
changed: [49.13.163.29]
TASK [Run make install] ******************************************************************************************************************************************************************************
changed: [49.13.163.29]
PLAY RECAP *******************************************************************************************************************************************************************************************
49.13.163.29 : ok=10 changed=8 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
After the playbook execution, login to the server and confirm Python installation. See examples below.
# Python 3.12
$ python3.12 -V
Python 3.12.1
# Python 3.11
$ python3.11 -V
Python 3.11.7
# Python 3.10
$ python3.10 -V
Python 3.10.13
Pip matching Python version is also installed.
$ pip3.12 -V
pip 23.2.1 from /usr/local/lib/python3.12/site-packages/pip (python 3.12)
Check the absolute path of both Python and Pip installed
$ which python3.12
/usr/local/bin/python3.12
$ which pip3.12
/usr/local/bin/pip3.12
You can run it using absolute bin path or just calling python<version> command.
$ /usr/local/bin/python3.12
Python 3.12.1 (main, Jan 7 2024, 19:29:29) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
#OR
$ python3.12
Python 3.12.1 (main, Jan 7 2024, 19:29:29) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Congratulations, you’ve just installed the latest release of Python by building it from source code and with the power of Ansible automation. We hope this article was helpful. You can check other Ansible guides available in our website.
- Create LVM Logical Volume and Mount using Ansible
- How To Deploy Matrix Server using Ansible and Docker
- Automate Linux Systems with Ansible System Roles