Ansible Runner is a Python library and command-line tool designed to provide a consistent and stable interface for executing Ansible directly or as part of another system. It abstracts away the complexities of managing Ansible execution, handling artifact storage, and providing event-driven output. This makes it ideal for embedding Ansible within CI/CD platforms, web applications, or other automation tooling. The current version is 2.4.3, with an active development and release cadence, often aligning with updates to the broader Ansible ecosystem.
Install & Compatibility
Where this runs
tested against v2.4.3 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.316s · 22.2MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 2.2s · import 0.310s · 23MB
21MB installed
● package 21MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
run
✓ from ansible_runner import run
This is the primary function for executing Ansible playbooks or ad-hoc commands.
Runner
✓ from ansible_runner.runner import Runner
Used for more advanced, fine-grained control over the Ansible execution lifecycle and access to results. The `run` function is a helper around this class.
This quickstart demonstrates how to use `ansible_runner.run` to execute a simple Ansible playbook. It sets up a temporary `private_data_dir` with a basic project and inventory structure, runs a playbook that prints a debug message, and then reports the execution status and output.
import ansible_runner
import os
import tempfile
import shutil
# Create a temporary directory for ansible-runner's private_data_dir
with tempfile.TemporaryDirectory() as private_data_dir:
# Create project/ and inventory/ subdirectories
project_dir = os.path.join(private_data_dir, 'project')
inventory_dir = os.path.join(private_data_dir, 'inventory')
os.makedirs(project_dir, exist_ok=True)
os.makedirs(inventory_dir, exist_ok=True)
# Write a simple Ansible playbook
playbook_content = '''
- name: Test playbook
hosts: localhost
connection: local
tasks:
- name: Print a message
ansible.builtin.debug:
msg: "Hello from Ansible Runner!"
- name: Verify an environment variable (optional)
ansible.builtin.debug:
msg: "TEST_VAR is {{ lookup('env', 'TEST_VAR') }}"
when: lookup('env', 'TEST_VAR') | length > 0
'''
with open(os.path.join(project_dir, 'test_playbook.yml'), 'w') as f:
f.write(playbook_content)
# Write a simple inventory file
inventory_content = '''
localhost ansible_connection=local
'''
with open(os.path.join(inventory_dir, 'hosts'), 'w') as f:
f.write(inventory_content)
# Set an optional environment variable for the playbook to consume
os.environ['TEST_VAR'] = os.environ.get('MY_ANSIBLE_RUNNER_TEST_VAR', 'DefaultValueFromRunner')
print(f"Running Ansible playbook in: {private_data_dir}")
# Run the playbook using ansible-runner
r = ansible_runner.run(
private_data_dir=private_data_dir,
playbook='test_playbook.yml',
quiet=False # Set to True to suppress stdout from Ansible process
)
print(f"\nAnsible Runner Status: {r.status}")
print(f"Ansible Runner Return Code: {r.rc}")
if r.stdout:
print("\n--- Ansible Playbook Output ---")
# You can access stdout as a file-like object or iterate through events
# For simplicity, let's print the entire stdout content
stdout_path = os.path.join(r.artifact_dir, 'stdout')
if os.path.exists(stdout_path):
with open(stdout_path, 'r') as f:
print(f.read())
else:
print("Stdout file not found.")
if r.stderr:
print("\n--- Ansible Playbook Error Output ---")
stderr_path = os.path.join(r.artifact_dir, 'stderr')
if os.path.exists(stderr_path):
with open(stderr_path, 'r') as f:
print(f.read())
else:
print("Stderr file not found.")
# Clean up the environment variable
del os.environ['TEST_VAR']
ansible-runner --version
Debug
Known issues
breakingAnsible Runner 2.4.0 and later requires Python 3.9 or newer. Older versions supported Python 3.8 and earlier. Attempting to use newer `ansible-runner` versions with older Python interpreters will result in errors.fixEnsure your Python environment is version 3.9 or later before installing or upgrading `ansible-runner`.
affects: 2.4.0+
breakingStarting with Ansible Runner 2.4.1, the `container-volume-mount` option now passes volume specifications directly to the underlying container engine (Docker/Podman) unverified and unmodified. This change allows mounting individual files or non-existing source volumes, but the behavior for non-existing sources now depends on the specific container engine (Docker creates, Podman errors).fixReview existing container volume mounts, especially those involving non-existent source paths, and test behavior with your chosen container engine. Adjust as needed for Docker vs. Podman specifics.
affects: 2.4.1+
breakingAnsible Runner 2.4.3 introduced changes in how custom callback plugins should use the `get_option` API. If you have custom callback plugins, they might need updates to align with this new API usage, potentially causing issues with older implementations.fixConsult the `ansible-runner` changelog and documentation for `2.4.3` regarding callback plugin API changes and update your custom callback plugins to use the `get_option` API correctly.
affects: 2.4.3+
gotchaAnsible Runner expects a specific directory structure within the `private_data_dir` (e.g., `project/` for playbooks and roles, `inventory/` for hosts, `env/` for extra vars, passwords, etc.). Misconfigurations in this structure are a common source of 'file not found' or 'playbook not found' errors.fixAlways organize your Ansible content within the `private_data_dir` according to `ansible-runner`'s expected hierarchy. Refer to the official documentation for the complete structure.
affects: All
gotchaWhen using `ansible-runner` with containerized Execution Environments, SSH agent forwarding (`SSH_AUTH_SOCK`) might not work as expected if `~/.ssh/` files are symlinked to unmounted directories. Manual volume mounting might be necessary.fixIf SSH issues arise with Execution Environments, consider explicitly mounting your `~/.ssh/` directory or ensuring that any symlinked SSH keys are within mounted paths using the `container_volume_mounts` API option or CLI flags.
affects: All (when using containerization)
Errors
Common errors & fixes
AttributeError: 'NoneType' object has no attribute 'stdout'
This error occurs when attempting to access the 'stdout' attribute of a 'NoneType' object, indicating that the object was not properly initialized or assigned.
fixEnsure that the object is correctly initialized and assigned before accessing its attributes.
AttributeError: 'NoneType' object has no attribute 'run'
This error occurs when attempting to call the 'run' method on a 'NoneType' object, indicating that the object was not properly initialized or assigned.
fixEnsure that the object is correctly initialized and assigned before calling its methods.
AttributeError: 'NoneType' object has no attribute 'open_session'
This error occurs when attempting to call the 'open_session' method on a 'NoneType' object, indicating that the object was not properly initialized or assigned.
fixEnsure that the object is correctly initialized and assigned before calling its methods.
AttributeError: 'NoneType' object has no attribute 'exec_command'
This error occurs when attempting to call the 'exec_command' method on a 'NoneType' object, indicating that the object was not properly initialized or assigned.
fixEnsure that the object is correctly initialized and assigned before calling its methods.
AttributeError: 'NoneType' object has no attribute 'read'
This error occurs when attempting to call the 'read' method on a 'NoneType' object, indicating that the object was not properly initialized or assigned.
fixEnsure that the object is correctly initialized and assigned before calling its methods.
Audit
Dependencies
ansible-corerequiredAnsible Runner executes Ansible commands; therefore, an Ansible installation (typically ansible-core) is required in the environment where ansible-runner is run. This might be a local installation or within a containerized execution environment.