Story

I wanted to use Ansible Docker container module to manage my services instead of docker compose, but I was greeted with:

TASK [nas : Redis container] ***************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ModuleNotFoundError: No module named 'requests'
fatal: [nas]: FAILED! => {
    "changed": false
}

MSG:

Failed to import the required Python library (requests) on nas's Python /usr/bin/python3. 
Please read the module documentation and install it in the appropriate location. 
If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter

PLAY RECAP *********************************************************************************************************************************************
nas                        : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

How to fix it?

I probably can use default pip to install required packages, but it can be messy …

xkcd.com #1987
xkcd.com/1987

Also, it’s unraid, so some things disappear after reboot.
Surely there must be some easy and clean way?

venv to the rescue!

Smart and lazy people figured out that boxing with python deps is boring, and python just needs its own container. This way it can put all the toys in different versions and not pollute the rest of the system.

At the first step, pick some directory on cache or array for your new venv.
I personally created share “internals” on cache with nightly copying to array.
Next, enter new share and create venv in it:

cd /mnt/user/internals/
python3 -m venv python-venv-ansible
#cd !$

Enter venv and install selected packages

source /mnt/user/internals/python-venv-ansible/bin/activate
python3 -m pip install requests

Output should look like this when installing package, note prompt prefix (python-venv-ansible) which means we successfully activated venv with specified name:

(python-venv-ansible) root@nas:/mnt/user/internals# python3 -m pip install requests
Collecting requests
  Downloading requests-2.31.0-py3-none-any.whl (62 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.6/62.6 KB 1.3 MB/s eta 0:00:00
Collecting certifi>=2017.4.17
  Downloading certifi-2023.11.17-py3-none-any.whl (162 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 162.5/162.5 KB 3.5 MB/s eta 0:00:00
Collecting charset-normalizer<4,>=2
  Downloading charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (142 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 142.3/142.3 KB 13.3 MB/s eta 0:00:00
Collecting urllib3<3,>=1.21.1
  Downloading urllib3-2.1.0-py3-none-any.whl (104 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 104.6/104.6 KB 22.3 MB/s eta 0:00:00
Collecting idna<4,>=2.5
  Downloading idna-3.4-py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.5/61.5 KB 35.7 MB/s eta 0:00:00
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2023.11.17 charset-normalizer-3.3.2 idna-3.4 requests-2.31.0 urllib3-2.1.0

Now you have venv with required dependencies, just use it in Ansible Playbook as a different Python interpreter targeting <venv path>/bin/python

# playbook.yml
---
- hosts: nas
  vars:
    ansible_python_interpreter: "/mnt/user/internals/python-venv-ansible/bin/python"
  roles:
    - nas

Sources