← All TILs · ansible

Ansible controllers in 2026: AWX paused, AAP, Semaphore UI, or plain CI

ansible - 2026-10-22

Second entry in the Running IaC and CaC from a controller series. The first entry separated the three roles: the control node runs ansible-playbook; a runner runs CI jobs; a controller is a service that stores projects, inventories, credentials and templates, launches runs and keeps their history. This one compares the four ways a team can run its Ansible centrally today, and runs one of them, Semaphore UI, against a playbook kept in GitLab.

The four options

Plain GitLab CI AWX AAP Semaphore UI
What it is a pipeline job runs ansible-playbook, usually in an execution environment the open-source upstream of AAP's controller Red Hat's supported product: controller, automation hub, Event-Driven Ansible an independent open-source web interface for Ansible, OpenTofu/Terraform, Bash and PowerShell
Licence GitLab CE: MIT Apache 2.0 Red Hat subscription MIT
Latest release GitLab and GitLab Runner release monthly 24.6.1, 2 July 2024; releases paused 2.6, with patch releases into 2026 2.19.17, used here
Runs on any runner (Docker, Kubernetes, shell…) Kubernetes, through the AWX operator RHEL with Podman (containerized installer), OpenShift (operator) or RPM (deprecated) one container with SQLite, or with MySQL or PostgreSQL
Credentials CI/CD variables, or an external secrets manager encrypted credential store encrypted credential store key store
Who may run what GitLab project roles, protected branches and environments organisations, teams, role-based access same as AWX, behind the platform gateway projects and project roles
History of runs pipelines and job logs jobs, with per-task events same as AWX tasks with their log and the commit they ran
ansible-core version whatever the job's image or EE contains the EE chosen per template the EE chosen per template the one bundled in its image, unless you build your own

CI/CD variables are values GitLab passes to jobs as environment variables, optionally masked in logs or limited to protected branches. An external secrets manager is a separate service, such as HashiCorp Vault, that jobs ask for secrets at run time.

AWX: code still moving, nothing released

The AWX README now opens with a caution: "The last release of this repository was released on Jul 2, 2024. Releases of this project are now paused during a large scale refactoring", and points to the forum posts on refactoring AWX into a "pluggable, service-oriented architecture" (ansible/awx). The devel branch keeps changing, and the Ansible forum has a thread asking whether AWX has a future (Is there a future for AWX?). As of October 2026, no release date has been announced.

What that means for a team starting today: installing AWX means installing 24.6.1, through the AWX operator, on Kubernetes, and every fix made since July 2024 exists only in unreleased code. Teams already on AWX keep a working controller; teams choosing one now are choosing a version more than two years old. That is why this series doesn't run AWX in its lab.

AAP: the supported controller

AAP is what AWX becomes once Red Hat packages and supports it. Since AAP 2.5 (October 2024), a platform gateway handles login and access for all of its services in one interface, and a containerized installer deploys it on RHEL with Podman (AAP 2.5 release notes). The 2.6 documentation lists patch releases into 2026 (AAP 2.6 release notes). It needs a Red Hat subscription, and Red Hat offers a time-limited trial.

A controller with a web interface invites changes made by clicking, which Git never sees. Red Hat's Communities of Practice (CoP), in their automation good practices, ask for the opposite: "All AAP objects -- organizations, teams, credentials, projects, inventories, job templates, workflow templates, execution environments, schedules, and settings -- should be defined as YAML data in a Git repository", with "no manual changes" through the interface, applied "through CI/CD pipelines, not manually". The CoP's collection for this is infra.aap_configuration for AAP 2.5 and later; infra.controller_configuration covers AAP 2.4 and earlier. Done that way, a controller is configured by a pipeline like any other system, and the interface is for launching and reading runs. This series describes AAP from Red Hat's documentation and doesn't run it; the inventory series' AAP entry covers how its inventories work.

Semaphore UI, run against GitLab

Semaphore UI organises work in projects. Its README lists what a project holds: task templates, schedules, inventories and variable groups; running a template creates a task. A project also has a key store for credentials and a list of repositories, the Git URLs its templates run from. Example 02-semaphore-from-gitlab sets this up through Semaphore's API against the lab's GitLab CE 19.5.1:

  1. site.yml goes into a private GitLab project.
  2. GitLab creates a project access token, a token tied to one project rather than to a person, with the Reporter role and only the read_repository scope, valid for one day.
  3. Semaphore gets that token as a login_password key, a repository http://gitlab/root/ctl-02.git that uses it, a static inventory (semaphore-container, the Semaphore container itself), a variable group setting ansible_connection: local, and a template for site.yml on branch main.
  4. The template runs, and the script prints what the task reported.

The playbook prints the ansible-core version it ran with:

- name: Show the ansible-core version Semaphore used
  ansible.builtin.debug:
    msg: >-
      ansible-core {{ ansible_version.full }} ran site.yml
      for {{ inventory_hostname }}
    verbosity: 0

The output, from Semaphore UI 2.19.17:

Semaphore task: success
Commit run: site.yml for Semaphore UI
Cloning Repository http://gitlab/root/ctl-02.git
No <repo>/collections/requirements.yml file found. Skip galaxy install process.
No <repo>/requirements.yml file found. Skip galaxy install process.
No <repo>/roles/requirements.yml file found. Skip galaxy install process.
msg: ansible-core 2.20.10 ran site.yml for semaphore-container
semaphore-container : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Three things in it:

Plain CI: the pipeline as the controller

Without a controller, a GitLab pipeline does the controller's work: the project holds the playbooks, the job's image is the execution environment, CI/CD variables hold the secrets, pipeline schedules replace job schedules, and the pipeline list is the history of runs, each tied to a commit and to whoever merged it. What's missing is anything outside Git: there is no inventory or credential screen, and running a playbook means running a pipeline. Later entries in this series build that setup step by step.

What decides between them

These questions separate the options more than feature lists do:

The commands above ran in a Linux container with Docker: GitLab CE 19.5.1, GitLab Runner 19.5.1 and Semaphore UI 2.19.17 from the companion repository's lab. AWX and AAP were not run.

Created 2026-10-22T22:48:00+02:00, updated 2026-10-22T23:35:14+02:00 · History · Edit