The paradigm shift toward Configuration-as-Code (CaC) has redefined how enterprise environments manage complex automation controllers. By integrating GitLab CI/CD with Ansible, organizations move away from manual, imperative configuration steps and toward a declarative, version-controlled lifecycle. This integration leverages the GitLab Runner—a lightweight, highly scalable application designed to execute jobs within a GitLab CI/CD pipeline—to orchestrate Ansible playbooks that manage the state of an Ansible Automation Controller.
In a modern DevOps ecosystem, the GitLab Runner acts as the execution engine that bridges the gap between the version-controlled repository and the target infrastructure. When paired with Ansible, the runner can trigger playbooks that interact with the Automation Controller API, applying configurations ranging from organization structures and LDAP integrations to sophisticated Role-Based Access Control (RBAC) settings. This approach ensures that every change to the automation infrastructure is audited, tested, and repeatable, reducing the risk of configuration drift and manual error.
The utility of this architecture extends beyond mere deployment. It enables a continuous integration and continuous deployment (CI/CD) workflow for infrastructure itself. By treating the controller configuration as code, teams can utilize the same rigorous testing standards applied to application software—linting playbooks, testing against staging environments, seeking human approval, and finally deploying to production—all within a single, unified platform. This eliminates the friction of managing disparate tools and centralizes the entire automation lifecycle within the GitLab environment.
The GitLab Runner and Ansible Integration Ecosystem
The GitLab Runner serves as the primary executor for GitLab CI/CD pipelines. It is an application that communicates with the GitLab server to pick up jobs and execute them in a specified environment. In the context of Ansible automation, the runner provides the isolated execution environment necessary to run playbooks without polluting the host machine's configuration.
The following table outlines the core components required to establish a functional GitLab-Ansible automation pipeline:
| Component | Role in the Ecosystem | Technical Requirement/Specification |
|---|---|---|
| GitLab Instance | The orchestration platform and source of truth for code and CI/CD definitions. | Admin access required; hosts the .gitlab-ci.yml file. |
| GitLab Runner | The execution agent that runs the CI/CD jobs. | Requires connectivity to GitLab via ports 80 or 443. |
| Ansible Automation Controller | The target system being managed via Configuration-as-Code. | Requires admin access and API accessibility. |
| Ansible Execution Environment (EE) | A container image containing the necessary Ansible versions and collections. | Must include ansible.controller and infra.controller_configuration collections. |
| Container Registry | The storage location for the Ansible Execution Environment images. | Must be accessible by the GitLab Runner. |
The integration is particularly robust when using a Container-based approach. By utilizing an Ansible Execution Environment (EE), the runner ensures that the exact versions of Ansible, Python libraries, and specific collections are available for every job. This solves the "it works on my machine" problem by providing a standardized, immutable runtime for every playbook execution.
Technical Specifications for Ansible-Based GitLab Runner Deployment
When deploying a GitLab Runner specifically optimized for Ansible workloads, several configuration variables and versioning requirements must be addressed, especially when utilizing Ansible roles for deployment.
Ansible Role Requirements and Versioning
For administrators utilizing Ansible roles to manage the installation and configuration of the runner (such as the specialized ansible-gitlab-runner role), strict dependency management is mandatory.
- Ansible Version Requirement: The deployment process requires Ansible version 2.13 or higher to ensure compatibility with modern modules and collection structures.
- Galaxy Collections: The deployment must include the installation of specific Ansible Galaxy collections as defined in a
requirements.ymlfile. - Package Naming Conventions: In GitLab versions 10.x and later, the package name is
gitlab-runner. For legacy environments using versions prior to 10.x, the variablegitlab_runner_package_namemust be set togitlab-ci-multi-runner. - Version Control for Runners: Administrators can specify the desired version of the runner using
gitlab_runner_wanted_versionfor macOS and Windows environments, orgitlab_runner_package_versionfor Linux-based systems. - Concurrency Management: The
gitlab_runner_concurrentvariable defines the maximum number of jobs that can run simultaneously. By default, this is set to the number of available processor cores on the host.
Registration and Token Management
The process of linking a runner to a GitLab instance involves a registration phase that requires specific credentials and metadata.
- Registration Token: This is the unique identifier used to authorize the runner. If
gitlab_runner_registration_token_typeis set to the deprecatedregistration-token, the token can be used globally. In modern implementations, a uniquetokenmust be specified for each individual runner within thegitlab_runner_runnerslist. - Group vs. Instance Runners: Users can register a group runner via the GitLab UI under CI/CD > Runners by selecting "Register a group runner" and copying the resulting token.
- Executor Selection: During registration, the executor defines the environment where the job runs. For Ansible automation, the
dockerexecutor is preferred overshellorsshbecause it allows the use of specialized Ansible Execution Environments. - Tagging Strategy: Tags are critical for job routing. A runner must be assigned tags (e.g.,
controller-system-ee) so the GitLab CI/CD engine knows to dispatch specific Ansible jobs to the runner equipped with the correct container image.
Implementing the Runner in Disconnected and Containerized Environments
A significant challenge in enterprise environments is the "air-gapped" or disconnected scenario, where security protocols prohibit direct internet access. This necessitates a different approach to dependency management and runner configuration.
The Disconnected Environment Strategy
In an air-gapped environment, the runner cannot pull images from public registries like Docker Hub or Quay.io during runtime. All dependencies, including the GitLab Runner RPM and the Ansible Execution Environment images, must be pre-staged in a local container registry.
- RPM Acquisition: The administrator must manually obtain the correct GitLab Runner RPM corresponding to the specific processor architecture of the RHEL 8 node.
- Image Availability: The Ansible EE image, containing the necessary
ansible.controllerandinfra.controller_configurationcollections, must be hosted on a local, reachable container registry. - Connectivity: While the runner is disconnected from the internet, it must still maintain port 80 or 443 connectivity to the local GitLab instance and the Automation Controller API.
Transitioning from Docker to Podman
In many modern Linux distributions, particularly RHEL, Podman is the preferred container engine over Docker. To redirect a GitLab Runner from the Docker daemon to the Podman socket, the config.toml file must be manually modified.
The configuration process involves the following steps:
Access the configuration file using elevated privileges:
sudo vim /etc/gitlab-runner/config.tomlLocate the
[runners.docker]section within the file.Add the
hostparameter to point to the Podman socket. For a specific user, the path typically follows the pattern of the Podman socket location.
The resulting configuration block should be structured as follows:
toml
[runners.docker]
tls_verify = false
image = "aapah.chrislab.internal/controller-system-ee:latest"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0
host = "unix:///run/user/1001/podman/podman.sock"
Note that the unix:/// prefix is mandatory to instruct the runner to look for the socket on the local machine. This transition is vital for environments utilizing rootless containerization or those where Docker is not the native container runtime.
Orchestrating the Ansible Automation Controller via CI/CD
Once the runner is registered and configured to use the correct Ansible Execution Environment, the final stage is the creation of the CI/CD project. This project contains the .gitlab-ci.yml file, which acts as the blueprint for the automation lifecycle.
Pipeline-as-Code Workflow
The core benefit of this setup is the ability to manage the Automation Controller's internal state through a pipeline. This includes:
- Organization Management: Automating the creation and lifecycle of different organizations within the controller.
- User and Team Configuration: Managing access levels and team groupings.
- Identity Management: Configuring LDAP integration for centralized authentication.
- RBAC Enforcement: Deploying complex role-based access control policies.
The workflow follows a structured progression:
- Code Commit: An administrator updates an Ansible playbook or a configuration variable in the Git repository.
- Trigger: The GitLab CI/CD engine detects the change and initiates a pipeline.
- Job Dispatch: The engine identifies the runner tagged with the required executor/image (e.g.,
controller-system-ee) and dispatches the job. - Execution: The GitLab Runner pulls the specified Ansible EE from the local container registry and executes the playbook.
- API Interaction: The Ansible playbook communicates with the Automation Controller via the API to apply the desired state.
The Importance of Execution Environments in Pipelines
The Execution Environment (EE) is the cornerstone of reliable Ansible automation in a CI/CD context. Without a properly configured EE, the runner would lack the specific collections required to interact with the controller.
The following table describes the essential components of a specialized Ansible EE for controller management:
| Component | Purpose | Implementation Detail |
|---|---|---|
ansible.controller |
Collection for managing Automation Controller. | Must be pre-installed in the image. |
infra.controller_configuration |
Collection for infrastructure-level settings. | Must be pre-installed in the image. |
| Container Registry | Provides the image to the runner. | Must be accessible via the network. |
| Runner Tag | Maps the job to the EE. | e.g., controller-system-ee. |
Conclusion
The integration of GitLab Runner and Ansible provides a sophisticated framework for managing enterprise automation infrastructure. By transitioning from manual configuration to a Configuration-as-Code model, organizations achieve a level of consistency and auditability that is impossible through traditional methods. The ability to swap between Docker and Podman, manage runners in air-gapped environments, and leverage specialized Execution Environments ensures that this architecture is adaptable to the most stringent security and operational requirements. Ultimately, this synergy between GitLab CI/CD and Ansible transforms the Automation Controller from a standalone tool into a dynamic, version-controlled component of a broader DevOps ecosystem, enabling continuous improvement and rapid scaling of automation capabilities.