Introduction
Running Ansible in a Python virtual environment keeps your system Python clean and lets you pin exact versions of Ansible, collections, and Python dependencies per project. Pipenv combines pip + virtualenv into a single workflow with lockfiles for reproducible builds.
Why Virtual Environments for Ansible?
| Problem | Virtual Env Solution |
|---|---|
| System Ansible conflicts with pip packages | Isolated Python environment |
| Different projects need different Ansible versions | Separate venv per project |
| "Works on my machine" issues | Lockfile ensures identical deps |
| CI/CD needs reproducible installs | Pipfile.lock deterministic builds |
Quick Start
Install Pipenv
pip install pipenv
Create an Ansible Project
mkdir ansible-project
cd ansible-project
# Initialize with Python 3
pipenv --python 3
# Install Ansible
pipenv install ansible
# Install development tools
pipenv install --dev ansible-lint yamllint molecule
Activate the Environment
# Start a shell inside the venv
pipenv shell
# Verify Ansible
ansible --version
# ansible [core 2.16.0]
# python version = 3.12.0
# Run playbooks
ansible-playbook -i inventory site.yml
# Exit the venv
exit
Run Without Activating
# Run a single command in the venv
pipenv run ansible-playbook site.yml
pipenv run ansible-lint playbook.yml
Understanding Pipfile
# Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
ansible = "~=9.0"
boto3 = "*" # AWS modules
pywinrm = "*" # Windows modules
netaddr = "*" # ipaddr filter
[dev-packages]
ansible-lint = "*"
yamllint = "*"
molecule = "*"
molecule-docker = "*"
pytest-testinfra = "*"
[requires]
python_version = "3.12"
Version Pinning
# Exact version
ansible = "==9.1.0"
# Compatible release (9.x but not 10.x)
ansible = "~=9.0"
# Minimum version
ansible-lint = ">=6.0"
Pipfile.lock — Reproducible Builds
# Generate/update lockfile
pipenv lock
# Install exactly what's in the lockfile (CI/CD)
pipenv install --deploy
# Fails if Pipfile.lock is out of date
pipenv install --deploy --ignore-pipfile
Common Workflows
Add a New Dependency
# Add to [packages]
pipenv install jmespath
# Add to [dev-packages]
pipenv install --dev molecule-docker
# Remove a package
pipenv uninstall boto3
Update Dependencies
# Update all packages
pipenv update
# Update a specific package
pipenv update ansible
# Check for security vulnerabilities
pipenv check
Show Dependency Tree
pipenv graph
# ansible==9.1.0
# - ansible-core [required: ~=2.16.0, installed: 2.16.0]
# - cryptography [required: Any, installed: 41.0.7]
# - jinja2 [required: >=3.0.0, installed: 3.1.2]
# - PyYAML [required: >=5.1, installed: 6.0.1]
Pipenv vs venv vs conda
| Feature | Pipenv | venv + pip | conda |
|---|---|---|---|
| Lockfile | ✅ Pipfile.lock | ❌ (use pip freeze) | ✅ environment.yml |
| Auto-creates venv | ✅ | ❌ Manual | ✅ |
| Security audit | ✅ pipenv check | ❌ | ❌ |
| Dependency resolution | ✅ Advanced | Basic | ✅ Advanced |
| Speed | Slower | Faster | Varies |
| Ansible support | ✅ | ✅ | ✅ |
Using venv Instead (Lightweight Alternative)
# Create venv
python3 -m venv .venv
source .venv/bin/activate
# Install Ansible
pip install ansible ansible-lint
# Freeze dependencies
pip freeze > requirements.txt
# Reproduce elsewhere
pip install -r requirements.txt
CI/CD Integration
GitHub Actions
# .github/workflows/ansible-lint.yml
name: Ansible Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install pipenv
pipenv install --deploy --dev
- name: Run ansible-lint
run: pipenv run ansible-lint
GitLab CI
# .gitlab-ci.yml
ansible-lint:
image: python:3.12
script:
- pip install pipenv
- pipenv install --deploy --dev
- pipenv run ansible-lint
Multiple Ansible Versions
Test playbooks against different Ansible versions:
# Project A — Ansible 8.x
cd project-a
pipenv install "ansible~=8.0"
# Project B — Ansible 9.x
cd project-b
pipenv install "ansible~=9.0"
# Each project has its own venv and lockfile
Troubleshooting
"Command not found: ansible" After pipenv install
# You need to activate the shell first
pipenv shell
ansible --version
# Or use pipenv run
pipenv run ansible --version
Slow Dependency Resolution
# Skip locking (faster, less reproducible)
pipenv install --skip-lock ansible
Virtual Environment Location
# Show venv path
pipenv --venv
# /home/user/.local/share/virtualenvs/ansible-project-abc123
# Store venv in project directory instead
export PIPENV_VENV_IN_PROJECT=1
pipenv install ansible
# Creates .venv/ in project root
Related Articles
- Install Ansible on Ubuntu
- Ansible Configuration Settings
- Ansible-Lint Guide
- VS Code for Ansible
- Ansible Best Practices Guide
Conclusion
Use pipenv install ansible to create an isolated environment, pipenv install --dev ansible-lint molecule for development tools, and pipenv lock + pipenv install --deploy for reproducible CI/CD builds. Pin Ansible versions with ~=9.0 syntax, run pipenv check for security audits, and store Pipfile + Pipfile.lock in version control. For simpler projects, python3 -m venv with requirements.txt works fine too.