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, then ansible-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

  1. Install the engine
sudo dnf install -y ansible-core
  1. 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
  1. 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
  1. Run a playbook
ansible-playbook -i inventory.ini site.yml

Tip: version-pin your collections with version: "==X.Y.Z" in requirements.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 the ansible.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

GoalRecommended approach
Lightweight local runsansible-core + ansible-galaxy collections
Reproducible dev that mirrors prodVS Code + Ansible Dev Tools container
CI/CD executionUse a curated EE image in your pipeline
At scale with AAPDefine 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 the ansible.posix collection—this is a common migration gotcha coming from older “all-in-one” installs.


Migrating from RHEL 8/9 to RHEL 10

  1. Unbundle assumptions: Identify which modules/roles you relied on that now belong to collections.
  2. Create requirements.yml: Explicitly list those collections (and versions).
  3. Pin versions: Lock versions to avoid surprise upgrades.
  4. Adopt Dev Tools & EEs: Develop and test in the Dev Tools container and run with the same EE you’ll use in CI/Controller.
  5. Automate lint/tests: Add ansible-lint and a CI step that pulls your EE and runs ansible-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.