Gebruik van GitLab Runner als Ansible Control Node

Richtlijn voor het gebruik van GitLab Runner als Ansible control node wanneer Ansible Automation Platform (AAP) niet beschikbaar is.

Probleem

Veel organisaties streven ernaar om Ansible Automatiseringsplatform ( AAP ) te gebruiken voor orkestratietaken, maar het is mogelijk niet altijd beschikbaar. In dergelijke gevallen hebben teams een alternatieve control node nodig om Ansible playbooks uit te voeren voor provisioning, terwijl ze beveiliging, schaalbaarheid en integratie met bestaande tools zoals GitLab behouden. Het kiezen van GitLab Runner voor dit doel introduceert uitdagingen zoals het beheren van meerdere pipelines, het uitvoeren van omgevingscontroles en het beperken van provisioning tot nodes die overeenkomen met de omgeving van de branch. Deze uitdagingen bestaan niet bij AAP, omdat het specifiek is ontworpen om orkestratie veilig te configureren en af te handelen, inclusief omgevingspecifieke controles, role-based access en gecentraliseerd beheer zonder aangepaste pipeline-logica.

Context

Ansible vereist een control node om playbooks uit te voeren tegen target hosts. Terwijl AAP een robuuste, enterprise-grade oplossing biedt, kunnen GitLab Runners dienen als een tijdelijk of lichtgewicht alternatief. Dit is vooral nuttig in omgevingen met GitLab CI/CD, waar runners kunnen worden geconfigureerd met Ansible execution environments. De aanpak veronderstelt dat een GitLab Runner met Ansible al is ingesteld en richt zich op het creëren van pipelines voor provisioning, met gebruik van features zoals CI/CD inputs voor flexibiliteit.

Deze setup vindt plaats in de context van een inventory project met group-based environments. De selectie van GitLab Runner als control node creëert uitdagingen zoals het afhandelen van meerdere pipelines voor verschillende taken, het valideren van omgevingen om ongeautoriseerde provisioning te voorkomen en het ervoor zorgen dat playbooks alleen nodes targeten in de bijbehorende omgevingsgroep op basis van de branch.

Oplossing

Configureer een GitLab CI/CD pipeline om een runner te gebruiken als de Ansible control node. Dit omvat het instellen van een hoofd .gitlab-ci.yml-bestand dat conditionele sub-bestanden bevat voor standaardtaken of Ansible provisioning. Gebruik CI/CD variables en inputs om de pipeline dynamisch en veilig te maken.

Aanpassen van de Pipeline voor Dubbele Workflows

Verander de gewone GitLab CI/CD pipeline voor het inventory project om twee distincte workflows te ondersteunen: één voor standaardtaken (bijv. linting, packaging) en een extra voor Ansible provisioning. Definieer CI/CD inputs in het hoofd .gitlab-ci.yml voor het selecteren van playbooks en CLI opties. Maak sub-bestanden zoals .gitlab-ci/ansible.yml voor provisioning en .gitlab-ci/default.yml voor niet-provisioning taken. Gebruik conditionals om het juiste sub-bestand in te sluiten op basis van pipeline triggers of variables.

Implementeren van Branch Validatie voor Provisioning

Voeg controles toe om ervoor te zorgen dat Ansible provisioning alleen kan draaien op specifieke branches, namelijk die welke overeenkomen met group-based environments in het inventory project. De pipeline moet falen als een gebruiker probeert te provisionen vanaf de master branch of een feature branch. Stel vereiste project variables in GitLab settings in, zoals PX_ANSIBLE_ENVIRONMENTS voor toegestane branches. In het provisioning sub-bestand, sluit validatielogica in om de huidige branch te controleren tegen deze lijst voordat je doorgaat.

Beperken van Playbook Uitvoering tot de Omgeving

Wanneer de Ansible pipeline draait vanaf een correcte omgevingsbranch, wijzig dan het ansible-playbook-commando om alleen nodes in die omgevingsgroep te targeten. Gebruik de --limit optie om uitvoering te beperken tot hosts in de bijbehorende groep, waardoor provisioning alleen de beoogde omgeving beïnvloedt. Pas deze limit automatisch toe op basis van de branch-naam, om beveiliging te bevorderen en accidentele wijzigingen aan niet-gerelateerde hosts te voorkomen.

Volg deze richtlijnen:

  1. Definieer CI/CD inputs in het hoofd .gitlab-ci.yml voor het selecteren van playbooks en CLI opties.
  2. Maak een sub-bestand (bijv. .gitlab-ci/ansible.yml) voor de provisioning stage, inclusief variable checks, branch validatie en playbook uitvoering met omgevingslimits.
  3. Maak een ander sub-bestand (bijv. .gitlab-ci/default.yml) voor niet-provisioning taken zoals linting en packaging, die alleen draaien op merge requests of de default branch.
  4. Stel vereiste project variables in GitLab settings in, zoals PX_ANSIBLE_ENVIRONMENTS voor toegestane branches.
  5. Zorg ervoor dat de runner een veilige image gebruikt met Ansible geïnstalleerd, en pas access controls toe voor beveiliging.

Voordelen

  • Maakt Ansible provisioning mogelijk zonder AAP, met gebruik van bestaande GitLab infrastructuur.
  • Bevordert flexibiliteit met dynamische inputs voor playbooks en opties.
  • Verbetert beveiliging door branch validatie en automatische beperking tot omgevingen.
  • Ondersteunt schaalbaarheid door integratie met GitLab’s CI/CD features voor automatisering.

Alternatieven (Optioneel)

Direct Ansible uitvoeren vanaf een lokale machine of dedicated server is mogelijk, maar het gebruik van GitLab Runners is verkozen voor integratie met version control, geautomatiseerde pipelines en schaalbaarheid in teamomgevingen. Als AAP beschikbaar wordt, migreer dan voor geavanceerde features zoals job scheduling en RBAC.

Voorbeelden en Implementatie

Deze sectie biedt YAML voorbeelden voor de pipeline-bestanden. Veronderstel een GitLab project met Ultimate features voor CI/CD inputs. De setup creëert twee pipelines: een default voor taken zoals linting, en een provisioning voor Ansible playbooks.

Hoofd Pipeline Bestand

Dit hoofd GitLab CI/CD pipeline bestand .gitlab-ci.yml definieert inputs en sluit andere YAML-bestanden conditioneel in.

 .gitlab-ci.yml

---
spec:
  inputs:
    play:
      type: string
      description: Ansible playbook file
      options: ["plays/core/linux.yml", "plays/core/windows.yml", "none"]
      default: 'none'
    cli_options:
      type: string
      description: Ansible CLI options
      default: --check
---
variables:
  ANSIBLE_PLAY: "\"$[[ inputs.play ]]\""
  ANSIBLE_CLI_OPTIONS: "\"$[[ inputs.cli_options ]]\""

include:
  - local: .gitlab-ci/default.yml
    rules:
      - if: "\"$[[ inputs.play ]]\" == \"none\""
  - local: .gitlab-ci/ansible.yml
    rules:
      - if: "\"$[[ inputs.play ]]\" != \"none\""

Ansible Provisioning Pipeline

Handhabt provisioning met controles en playbook uitvoering.

 .gitlab-ci/ansible.yml

---
default:
  image: registry.gitlab.com/c2platform/rws/ansible-execution-environment:0.1.25

stages:
  - validate
  - provision

validate:
  stage: validate
  script:
    - bash ./.gitlab-ci/scripts/validate.sh
  artifacts:
    paths:
      - variables.env
    expire_in: 1 hour

provision:
  stage: provision
  needs: [validate]
  script: |
    # Load exported variables
    source variables.env

    # Log and run the playbook
    echo "Running Ansible playbook: $CLEAN_PLAY, with options: $CLEAN_OPTIONS"
    echo "$ANSIBLE_CLI $CLEAN_PLAY $CLEAN_OPTIONS"
    # eval "$ANSIBLE_CLI \"$CLEAN_PLAY\" $CLEAN_OPTIONS"    

De validate.sh script valideert dat de branch correct is, met andere woorden een toegestane omgevingsbranch is (geconfigureerd met PX_ANSIBLE_ENVIRONMENTS). En het zorgt ervoor dat --limit wordt gebruikt om de group te targeten die

 .gitlab-ci/scripts/validate.sh

#!/bin/bash

# Check required variables
if [ -z "$PX_ANSIBLE_ENVIRONMENTS" ]; then
  echo "Error: Required variable PX_ANSIBLE_ENVIRONMENTS is not defined. Set it in CI/CD settings (e.g., 'development,test,acceptance,production'). Failing pipeline."
  exit 1
fi
if [ -z "$ANSIBLE_PLAY" ]; then
  echo "Error: Required variable ANSIBLE_PLAY is not defined. Set it to your playbook file/path (e.g., 'plays/core/linux.yml'). Failing pipeline."
  exit 1
fi
if [ -z "$ANSIBLE_CLI" ]; then
  ANSIBLE_CLI="ansible-playbook"  # Default if not set
  echo "ANSIBLE_CLI not defined. Defaulting to '$ANSIBLE_CLI'."
fi

# Strip surrounding double quotes from variables
clean_play="${ANSIBLE_PLAY#\"}"
clean_play="${clean_play%\"}"
clean_options="${ANSIBLE_CLI_OPTIONS#\"}"
clean_options="${clean_options%\"}"
clean_options=$(echo "$clean_options" | sed 's/""//g' | xargs)  # Trim extra spaces

# Validate branch
environments=$(echo "$PX_ANSIBLE_ENVIRONMENTS" | tr ',' ' ')
found=""
for env in $environments; do
  if [ "$CI_COMMIT_REF_NAME" = "$env" ]; then
    found="1"
    break
  fi
done
if [ -z "$found" ]; then
  echo "Error: Branch '$CI_COMMIT_REF_NAME' is not in allowed environments ($PX_ANSIBLE_ENVIRONMENTS). Failing pipeline."
  exit 1
fi

# Modify clean_options based on --limit
env="$CI_COMMIT_REF_NAME"
if echo "$clean_options" | grep -q -- --limit; then
  clean_options=$(echo "$clean_options" | sed -E "s/--limit ([^ ]+)/--limit \1:\&$env/")
else
  clean_options="$clean_options --limit $env"
fi

# Export to env file for next job
echo "CLEAN_PLAY=$clean_play" > variables.env
echo "CLEAN_OPTIONS=$clean_options" >> variables.env
echo "ANSIBLE_CLI=$ANSIBLE_CLI" >> variables.env

Default Pipeline

Voor linting, packaging en releasing. Dit is in .gitlab-ci/default.yml.

 .gitlab-ci/default.yml

---
default:
  image: registry.gitlab.com/c2platform/rws/ansible-execution-environment:0.1.25

variables:
  DOWNLOAD_SCRIPT: download.py
  COLLECTIONS_DIR: ansible-collections-tarball
  C2_PACKAGE_NAME: phx-ansible-collections

before_script:
  - python3 --version
  - pip3 --version
  - ansible --version
  - ansible-lint --version
  - yamllint --version

workflow:  # run the pipeline only on MRs and default branch
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

stages:
  - prepare
  - linters
  - package
  - release

yamllint:
  stage: linters
  script:
    - yamllint -c .yamllint .

ansible-lint:
  stage: linters
  script:
    - ansible-lint -c .ansible-lint

prepare:
  stage: prepare
  script:
    - C2_VERSION=$(grep -oP '\d+\.\d+\.\d+' CHANGELOG.md | head -1)
    - echo "C2_VERSION=$C2_VERSION" >> variables.env
  artifacts:
    reports:
      dotenv: variables.env

package:
  stage: package
  when: manual
  only:
    - master
  script:
    - |
      ansible-galaxy collection download -r collections/requirements.yml -p ./$COLLECTIONS_DIR
      cd $COLLECTIONS_DIR
      tar -czvf ../${C2_PACKAGE_NAME}.${C2_VERSION}.tar.gz .      
  artifacts:
    paths:
      - ${C2_PACKAGE_NAME}.${C2_VERSION}.tar.gz

publish:
  stage: package
  only:
    - master
  needs:
    - job: package
    - job: prepare
  script:
    - |
      env | grep C2
      curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file ${C2_PACKAGE_NAME}.${C2_VERSION}.tar.gz \
        ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${C2_PACKAGE_NAME}/${C2_VERSION}/${C2_PACKAGE_NAME}.${C2_VERSION}.tar.gz      

release:
  stage: release
  only:
    - master
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  needs:
    - job: publish
    - job: package
  before_script: []
  script:
    - echo "Create release for $C2_VERSION"
  release:
    name: phx-inventory-$C2_VERSION
    description: PHX Ansible Inventory Project
    tag_name: $C2_VERSION
    ref: $CI_COMMIT_SHA
    assets:
      links:
        - name: "${C2_PACKAGE_NAME}.${C2_VERSION}.tar.gz"
          url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${C2_PACKAGE_NAME}/${C2_VERSION}/${C2_PACKAGE_NAME}.${C2_VERSION}.tar.gz"

Gebruiksnotities

  • Stel CI/CD variables in zoals PX_ANSIBLE_ENVIRONMENTS in project settings.
  • De pipeline valideert branches en beperkt playbooks tot de huidige omgeving.
  • Gebruik een veilige runner image en access controls voor best practices.
  • Deze setup schaalt goed met GitLab zonder AAP nodig te hebben.

Aanvullende Informatie

Voor aanvullende inzichten en begeleiding:

  • Omgevingen op basis van Groepen: Organiseer je Ansible-inventaris en variabelen voor verschillende omgevingen.
  • Ansible Inventarisproject: Een Ansible Inventarisproject bevat inventarisbestanden, plays, hostconfiguraties, groepsvariabelen en kluisbestanden. Het wordt ook wel aangeduid als een playbook-project of configuratieproject.


Laatst gewijzigd 2025.09.05: guidelines using alert C2-872 (41b9396)