Ansible on RHEL 10: what changed and how to work productively today
RHEL 10 is here—and with it, a more modern way to develop and run Ansible. If you’re coming from RHEL 8/9, you’ll notice that the monolithic ansible
RPM (“batteries included”) is deprecated and no longer shipped in RHEL or EPEL. The new baseline is ansible-core
: the lean automation engine plus the built-in modules and plugins you need to execute playbooks. Everything else—modules, plugins, and roles beyond the core—now lives in collections that you install explicitly.
This post breaks down what changed, why, and how to set up a smooth RHEL 10 workflow using ansible-core
, collections, and (optionally) Ansible Automation Platform Execution Environments and the Ansible Dev Tools container.
TL;DR
- Install:
dnf install ansible-core
- Extend with collections: declare them in
requirements.yml
, thenansible-galaxy collection install -r requirements.yml
- Develop with modern tooling: use the Ansible Dev Tools container (with VS Code Dev Containers), which includes
ansible-navigator
and friends—no RHEL RPMs required - Run at scale: use Execution Environments (EEs)—container images with
ansible-core
, collections, and Python deps preloaded—for consistency between dev and prod
What’s different in RHEL 10
1) The ansible
RPM is gone
Previously, installing ansible
gave you the engine and a large bundle of modules/roles. In RHEL 10 you install ansible-core
and then choose exactly which collections you need. This keeps systems smaller, clearer, and more reproducible.
2) You install content explicitly via collections
Most modules that used to feel “built-in” now ship in collections (e.g., ansible.posix
, community.general
, cloud/vendor collections). Declare them in a requirements.yml
and install with ansible-galaxy
.
3) Development tools are containerized
RHEL 10 stops shipping RPMs for tools like ansible-navigator
. Instead, Red Hat provides a Dev Tools container and a ready-to-use VS Code Dev Container configuration. You develop inside the container, benefiting from a curated toolchain that matches Automation Controller/EE runtimes.
4) Execution Environments are the default runtime
With Ansible Automation Platform (AAP), you run playbooks in standardized EEs—container images that bundle ansible-core
, specific collection versions, and Python dependencies. You can target different EEs per use case (e.g., network automation vs. cloud) without dependency conflicts.
Quick-start: ansible-core
+ collections on RHEL 10
- Install the engine
sudo dnf install -y ansible-core
- Declare your collections in
requirements.yml
---
collections:
- name: ansible.posix
- name: community.general
- name: containers.podman
- name: kubernetes.core
# add vendor/cloud collections as needed:
# - name: amazon.aws
# - name: azure.azcollection
# - name: google.cloud
- Install collections to your user or project path
ansible-galaxy collection install -r requirements.yml
# Or for a project-local path:
ansible-galaxy collection install -r requirements.yml -p ./collections
- Run a playbook
ansible-playbook -i inventory.ini site.yml
Tip: version-pin your collections with
version: "==X.Y.Z"
inrequirements.yml
for deterministic builds.
Modern dev workflow: Ansible Dev Tools container + VS Code
On RHEL 10, the recommended developer experience is containerized:
- Use the Ansible Dev Tools container as your development environment.
- Open your repository in VS Code with the Dev Containers extension; the editor automatically attaches to the container and provides
ansible-lint
,yamllint
,ansible-navigator
, and more—preconfigured. - Your host stays clean, and your dev environment mirrors production EEs closely.
Typical commands inside the Dev Tools container:
# Validate
ansible-lint
# Explore collections, run playbooks using an EE
ansible-navigator run site.yml -m stdout -e @group_vars/all.yml -i inventory.ini --eei <your-ee-image>
Understanding the pieces: ansible-core
, collections, EEs, and Navigator
ansible-core
: the engine (CLI:ansible
,ansible-playbook
,ansible-galaxy
,ansible-inventory
, etc.) plus theansible.builtin
content. Installed via RPM on RHEL 10.- Collections: modular content packages (modules, plugins, roles). Installed via
ansible-galaxy
. You choose which ones and which versions. - Execution Environments (EEs): container images that bundle
ansible-core
, specific collection versions, and Python deps. Ensures reproducibility across laptops, CI, and controllers. ansible-navigator
: a front-end for running playbooks and exploring content inside EEs. On RHEL 10, it’s provided via containers (Dev Tools/EE), not as RPMs.
Choosing your workflow
Goal | Recommended approach |
---|---|
Lightweight local runs | ansible-core + ansible-galaxy collections |
Reproducible dev that mirrors prod | VS Code + Ansible Dev Tools container |
CI/CD execution | Use a curated EE image in your pipeline |
At scale with AAP | Define EEs, register to Automation Controller, and run via controller/execution nodes |
Sample project layout (RHEL 10–friendly)
inventory/
hosts.ini
group_vars/
all.yml
roles/
webserver/
tasks/main.yml
collections/
# (optional) project-local collections path
requirements.yml
site.yml
Example site.yml
:
---
- name: Configure web tier
hosts: web
gather_facts: true
roles:
- role: webserver
Example role snippet (roles/webserver/tasks/main.yml
):
---
- name: Ensure httpd is installed
ansible.builtin.package:
name: httpd
state: present
- name: Enable and start httpd
ansible.builtin.service:
name: httpd
enabled: true
state: started
- name: Allow HTTP service (firewalld)
ansible.posix.firewalld:
service: http
permanent: true
state: enabled
immediate: true
Note how
firewalld
lives in theansible.posix
collection—this is a common migration gotcha coming from older “all-in-one” installs.
Migrating from RHEL 8/9 to RHEL 10
- Unbundle assumptions: Identify which modules/roles you relied on that now belong to collections.
- Create
requirements.yml
: Explicitly list those collections (and versions). - Pin versions: Lock versions to avoid surprise upgrades.
- Adopt Dev Tools & EEs: Develop and test in the Dev Tools container and run with the same EE you’ll use in CI/Controller.
- Automate lint/tests: Add
ansible-lint
and a CI step that pulls your EE and runsansible-playbook --syntax-check
and a small “smoke” play.
Frequently asked questions
Q: Do I still need ansible-navigator
?
A: It’s optional but very handy with EEs. On RHEL 10, use the Dev Tools container (or an EE) to run it—there’s no RPM to install.
Q: Can I run playbooks directly with ansible-playbook
?
A: Yes. That’s the simplest path with ansible-core
+ collections. For strict reproducibility, run the same playbooks inside an EE image.
Q: What about RHEL System Roles?
A: They’re delivered as collections and continue to work great on RHEL 10. Add them to requirements.yml
and use as usual.
Q: How do EEs help teams? A: They solve “works on my machine” problems. Each EE locks collection and Python dependency versions. You can maintain multiple EEs for different playbook families.
Minimal examples you can copy
requirements.yml
with version pins
collections:
- name: ansible.posix
version: ">=1.5.0,<2.0.0"
- name: community.general
version: ">=9.0.0,<10.0.0"
Install & verify
sudo dnf install -y ansible-core
ansible --version
ansible-galaxy collection install -r requirements.yml
ansible-inventory --graph -i inventory/hosts.ini
Run with an EE (if using navigator)
ansible-navigator run site.yml \
--eei quay.io/yourorg/ee-supported-rhel9:latest \
-i inventory/hosts.ini -m stdout
Final thoughts
RHEL 10 moves Ansible from a big “one-size-fits-all” RPM to a modular, declarative setup:
- Use
ansible-core
for the engine, - declare your collections explicitly,
- develop and run in containers (Dev Tools + EEs) for consistency.
You’ll gain cleaner dependencies, reproducible environments, and a workflow that scales from your laptop to production without surprises.