Python virtual environment (venv)
Python venv Installing Packages
You can run pip by calling the python executable inside the venv folder.
# This installs 'wheel' specifically into that virtual environment
/opt/venv/bin/python -m pip install wheel
Python venv Running Scripts
you can run your Python script by pointing fully to the venv python executable.
/opt/venv/bin/python /path/to/your/script.py
When you run Python this way, it automatically looks for modules inside /opt/venv/lib/pythonX.X/site-packages. It is fully isolated from the system Python.
Python venv Example for Cron
If you wanted to run a script every day at 5 AM via Cron, you would write:
# Correct way (No activation needed)
0 5 * * * /opt/venv/bin/python /home/user/scripts/daily_task.py
Python venv + direnv (ansible example)
direvn allows automatical venv activation when you switch to the venv directory.
- venv with ansible-core + pip deps
sudo python3 -m venv /opt/ansible_venv
sudo /opt/ansible_venv/bin/pip install --upgrade pip
sudo /opt/ansible_venv/bin/pip install "ansible-core==2.21.*"
- direnv hook
echo 'eval "$(direnv hook bash)"' | sudo tee /etc/profile.d/direnv.sh
- .envrc so direnv activates the venv on cd
cat > /opt/ansible/.envrc <<'EOF'
export VIRTUAL_ENV=/opt/ansible_venv
export PATH="$VIRTUAL_ENV/bin:$PATH"
EOF
cd /opt/ansible && direnv allow
After direnv allow, every cd /opt/ansible puts /opt/ansible_venv/bin first in PATH - ansible, ansible-playbook, ansible-galaxy all resolve to the venv automatically.
- Install Galaxy roles and collections ansible-galaxy comes with ansible-core in the venv. Run from /opt/ansible so direnv has activated it:
cd /opt/ansible
ansible-galaxy install -r requirements-modern.yml
ansible-galaxy collection install -r requirements-modern.yml --force
- ansible.cfg + /etc/ansible
[defaults]
inventory = /opt/ansible/inventory/
forks = 5
sudo_user = root
ask_sudo_pass = True
ask_pass = True
gathering = implicit
gather_timeout = 60
host_key_checking = False
timeout = 60
remote_user = <your domain user>
vault_password_file = /etc/ansible/vaultpasswd
display_skipped_hosts = False
error_on_undefined_vars = True
system_warnings = True
nocows = 0
fact_caching = memory
retry_files_enabled = False
retry_files_save_path = ~/.ansible-retry
allow_world_readable_tmpfiles = True
callbacks_enabled = ansible.posix.profile_tasks
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = True
[ssh_connection]
pipelining = True
retries = 3
ssh_args = -o ControlMaster=auto -o ControlPersist=1200s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR
control_path = %(directory)s/%%h-%%r
[persistent_connection]
connect_timeout = 30
connect_retry_timeout = 30
command_timeout = 15