Execution Environments
What are Execution Environments?
Execution Environments (EEs) are container images that package Ansible, collections, Python dependencies, and system packages into a portable, reproducible runtime environment. They solve dependency conflicts and ensure consistent automation across different systems.
Key Benefits:
- Reproducibility: Same environment everywhere (dev, test, prod)
- Isolation: No conflicts with system Python or packages
- Portability: Run anywhere containers are supported
- Versioning: Pin exact versions of Ansible and collections
Core Components
ansible-builder
Tool for creating Execution Environment container images
ansible-navigator
Command-line interface for running playbooks and ad-hoc commands inside Execution Environments
ansible-runner
Python library and CLI for interfacing with Ansible, designed to work with Execution Environments
Installation
# Install ansible-builder
pip install ansible-builder
# Install ansible-navigator
pip install ansible-navigator
# Install ansible-runner (optional)
pip install ansible-runner
# Verify installations
ansible-builder --version
ansible-navigator --version
Building Execution Environments
Basic Structure
# execution-environment.yml
---
version: 3
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
galaxy: requirements.yml
python: requirements.txt
system: bindep.txt
additional_build_steps:
prepend_base:
- RUN echo "Custom build step"
append_final:
- RUN chmod -R ug+rw /runner
Dependencies Files
# requirements.yml - Ansible collections
---
collections:
- name: community.general
version: ">=5.0.0"
- name: ansible.posix
- name: community.docker
# requirements.txt - Python packages
jinja2>=3.0
netaddr
requests>=2.28
boto3
# bindep.txt - System packages
python3-dev [platform:rpm]
python3-devel [platform:dpkg]
git [platform:rpm platform:dpkg]
rsync [platform:rpm platform:dpkg]
Building the Image
# Build with default settings
ansible-builder build --tag my-ee:latest
# Build with custom name
ansible-builder build \
--tag my-organization/my-ee:1.0.0 \
--container-runtime podman
# Build with verbose output
ansible-builder build --tag my-ee:latest -v 3
# Build and push to registry
ansible-builder build --tag quay.io/myuser/my-ee:1.0.0
podman push quay.io/myuser/my-ee:1.0.0
Using ansible-navigator
Configuration
# ansible-navigator.yml
---
ansible-navigator:
execution-environment:
image: my-ee:latest
pull:
policy: missing
container-engine: podman
enabled: true
volume-mounts:
- src: /path/on/host
dest: /path/in/container
environment-variables:
pass:
- HOME
- USER
set:
ANSIBLE_FORCE_COLOR: 'true'
logging:
level: info
file: /tmp/navigator.log
playbook-artifact:
enable: true
save-as: /tmp/playbook-artifacts/{playbook_name}-{ts_utc}.json
Running Playbooks
# Run playbook with default EE
ansible-navigator run playbook.yml
# Run with specific EE image
ansible-navigator run playbook.yml \
--execution-environment-image my-ee:latest
# Run in interactive mode
ansible-navigator run playbook.yml --mode interactive
# Run in stdout mode (traditional output)
ansible-navigator run playbook.yml --mode stdout
# Pass extra vars
ansible-navigator run playbook.yml \
-e "version=1.2.3" \
-e "environment=production"
# Use specific inventory
ansible-navigator run playbook.yml \
-i inventory/production
# Disable EE (use local Ansible)
ansible-navigator run playbook.yml \
--execution-environment false
Interactive Features
# Start in interactive mode
ansible-navigator
# Available actions:
# :run playbook.yml - Run a playbook
# :collections - Browse installed collections
# :config - View Ansible configuration
# :doc module_name - View module documentation
# :inventory - Explore inventory
# :images - List EE images
# :quit or :q - Exit
# Example session
ansible-navigator
:doc ansible.builtin.copy
:collections
:run site.yml
Example Execution Environment Definitions
Web Application Deployment
# execution-environment.yml
---
version: 3
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
galaxy: |
---
collections:
- name: community.general
- name: ansible.posix
- name: community.docker
python: |
docker
kubernetes
openshift
jinja2>=3.0
netaddr
system: |
git [platform:rpm platform:dpkg]
python3-dev [platform:dpkg]
python3-devel [platform:rpm]
additional_build_steps:
append_final:
- COPY custom_plugins /usr/share/ansible/plugins/
- RUN chmod -R 755 /usr/share/ansible/plugins
Cloud Infrastructure
# execution-environment.yml
---
version: 3
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
galaxy: |
---
collections:
- name: amazon.aws
- name: azure.azcollection
- name: google.cloud
- name: community.general
python: |
boto3>=1.26
botocore>=1.29
azure-cli-core
google-auth
requests
system: |
git
jq
aws-cli [platform:rpm]
Network Automation
# execution-environment.yml
---
version: 3
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
galaxy: |
---
collections:
- name: cisco.ios
- name: cisco.nxos
- name: junipernetworks.junos
- name: arista.eos
python: |
netaddr
jxmlease
paramiko
ncclient
textfsm
system: |
openssh-client
Advanced Features
Multi-Stage Builds
# execution-environment.yml
---
version: 3
build_arg_defaults:
ANSIBLE_GALAXY_CLI_COLLECTION_OPTS: '--pre'
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
galaxy: requirements.yml
python: requirements.txt
system: bindep.txt
additional_build_steps:
prepend_base:
- RUN whoami
- RUN cat /etc/os-release
prepend_galaxy:
- RUN ansible-galaxy collection list
append_final:
- RUN echo "Build complete"
- RUN ls -la /usr/share/ansible/collections
Private Collection Repositories
# execution-environment.yml with private repos
---
version: 3
images:
base_image:
name: quay.io/ansible/ansible-runner:latest
dependencies:
galaxy: |
---
collections:
- name: my_namespace.my_collection
source: https://private-galaxy.company.com
additional_build_steps:
prepend_galaxy:
- COPY ansible.cfg /etc/ansible/ansible.cfg
- COPY galaxy_token /tmp/galaxy_token
append_final:
- RUN rm /tmp/galaxy_token
ansible-runner Integration
# Python script using ansible-runner
import ansible_runner
# Run playbook
r = ansible_runner.run(
private_data_dir='/tmp/demo',
playbook='playbook.yml',
inventory='inventory',
container_image='my-ee:latest',
container_runtime='podman',
envvars={
'ANSIBLE_FORCE_COLOR': 'true'
}
)
# Check results
print(f"Status: {r.status}")
print(f"Return code: {r.rc}")
# Access events
for event in r.events:
print(event['stdout'])
CI/CD Integration
GitHub Actions
# .github/workflows/ee.yml
name: Build Execution Environment
on: [push]
jobs:
build-ee:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install ansible-builder
run: pip install ansible-builder
- name: Build EE
run: ansible-builder build --tag my-ee:${{ github.sha }}
- name: Login to registry
run: echo "${{ secrets.REGISTRY_TOKEN }}" | \
podman login -u ${{ secrets.REGISTRY_USER }} --password-stdin quay.io
- name: Push to registry
run: |
podman tag my-ee:${{ github.sha }} quay.io/myorg/my-ee:latest
podman push quay.io/myorg/my-ee:latest
Using EE in GitLab CI
# .gitlab-ci.yml
stages:
- build
- deploy
build-ee:
stage: build
image: quay.io/ansible/ansible-builder:latest
services:
- docker:dind
script:
- ansible-builder build --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
deploy:
stage: deploy
image: quay.io/ansible/ansible-navigator:latest
script:
- ansible-navigator run playbook.yml \
--execution-environment-image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Best Practices
- Version Everything: Pin versions of Ansible, collections, and dependencies
- Tag Images: Use semantic versioning for EE images
- Minimize Size: Only include required dependencies
- Layer Efficiently: Order build steps to maximize cache hits
- Test Locally: Build and test EEs before CI/CD
- Document Dependencies: Comment why each dependency is needed
- Use Base Images: Start from official ansible-runner images
- Security Scan: Scan images for vulnerabilities
Troubleshooting
Common Issues:
- Build Failures: Check requirements file syntax and network connectivity
- Module Not Found: Ensure collection is in requirements.yml
- Permission Errors: Verify volume mounts and user permissions
- Large Image Size: Remove unnecessary dependencies
- Slow Builds: Use container registry caching
Debugging Build Process
# Build with verbose output
ansible-builder build -v 3 --tag debug-ee:latest
# Inspect build context
ansible-builder create
# Check generated files
ls -la context/
cat context/Containerfile
# Build manually with podman/docker
cd context
podman build -t manual-ee:latest .
Inspecting Running Containers
# Run interactive shell in EE
ansible-navigator exec -- /bin/bash
# Check installed collections
ansible-navigator exec -- ansible-galaxy collection list
# Check Python packages
ansible-navigator exec -- pip list
# Check system packages
ansible-navigator exec -- rpm -qa # or dpkg -l
Migration from Traditional Ansible
# Traditional approach
ansible-playbook -i inventory playbook.yml
# Execution Environment approach
ansible-navigator run playbook.yml -i inventory \
--execution-environment-image my-ee:latest
# Hybrid approach (transition period)
ansible-navigator run playbook.yml \
--execution-environment false # Uses local Ansible
Quick Reference
# ansible-builder
ansible-builder build --tag my-ee:latest # Build EE
ansible-builder create # Create build context
ansible-builder build -v 3 # Verbose build
# ansible-navigator
ansible-navigator run playbook.yml # Run playbook
ansible-navigator --mode interactive # Interactive mode
ansible-navigator doc module_name # Module docs
ansible-navigator collections # Browse collections
ansible-navigator inventory # Explore inventory
ansible-navigator config # View config
# EE image management
podman images # List images
podman pull quay.io/ansible/ansible-runner:latest # Pull image
podman push my-registry.com/my-ee:latest # Push image
podman inspect my-ee:latest # Inspect image
Next Steps
- Learn about CI/CD Integration for automated EE builds
- Explore Best Practices for EE design
- Master Roles and Collections to package in EEs
- Try the Playground to experiment with Ansible