Skip to content

Mission 5: Bring it all together with Gitlab CI/CD

In this mission, we integrate everything we've learned into a GitLab CI/CD pipeline, creating a fully automated network automation workflow. Throughout the previous missions, we have:

  • Automated network configurations using Ansible
  • Managed network hierarchy and inventory dynamically with NetBox
  • Prepared to ensured device configuration by verifying with pyATS

Now, we take these automation capabilities to the next level by orchestrating them into a GitLab CI/CD pipeline. This will allow us to:

  • Automate deployments whenever network changes are committed
  • Ensure consistency across network environments by integrating NetBox, Ansible, Catalyst Center, and pyATS into a structured, repeatable workflow

What do we need to have a functional Gitlab CI/CD pipeline?

To establish a fully operational GitLab CI/CD pipeline, three essential components must be in place:

  1. Runner: A host responsible for executing the pipeline jobs. The GitLab Runner can be installed on a physical server, virtual machine, Docker or Kubernetes cluster. It processes tasks defined in the pipeline configuration and executes them accordingly.
  2. Image: If the GitLab Runner operates within a Docker environment, a Docker image must be specified. This image provides the necessary dependencies and runtime environment required for executing automation tasks efficiently. You can specify a public available image or upload your custom image to the Gitlab container registry.
  3. Pipeline Configuration: The pipeline’s structure and execution logic are defined in a .gitlab-ci.yml file located at the root of the repository. This file dictates how jobs are executed, including steps for validation, deployment and testing.

We already have a shared runner in place, so we don't need to add an additional runner. But we still need to work on our image and the pipeline configuration.

Step 1: Create image and push it to the Gitlab container registry

  1. Have a look at the Dockerfile in the directory docker. The build file specifies the following:

    • Use ubuntu:24.04 as base image
    • Install python3 and pip3
    • Copy the requirements files into the containers working directory
    • Install the required python packages and ansible collections specified in the requirements files
  2. Let's build the image:

    docker build -t 198.18.134.23:5050/ltrops-2341/pod-2/ansible ./docker/.
    

    Warning

    If the build was not successful in the first try, just do it again. Could be a temporary connection issues between your workstation and the internet

  3. After the build we want to push it to our container registry:

    docker push 198.18.134.23:5050/ltrops-2341/pod-2/ansible
    
  4. Navigate to your Registry and verify that the image got pushed sucessfully.

    Key Value
    User user2
    Password C1sco12345

    Example Pod-1:

    Example Pod 1

Understanding pipeline configuration

The .gitlab-ci.yml file serves as the blueprint for our GitLab CI/CD pipeline, defining its structure and execution logic. The pipeline is organized into stages, each representing a distinct phase of the automation process, with jobs that execute specific tasks within those stages.

To ensure reliability and prevent unintended changes, each stage must complete successfully before the pipeline proceeds to the next. This approach guarantees that configurations are validated and tested before being applied to the network.

Each job runs within a GitLab Runner, leveraging a predefined Docker image to provide a consistent execution environment.

In this lab, we are using a simple pipeline, performing only minimal validation before deployment. However, in real-world scenarios, it is strongly recommended to implement comprehensive testing, including:

  • Deploying to a test environment first before making changes in production.
  • Performing impact analysis to assess potential risks before applying configurations to live networks.
  • Implementing an approval process to add a layer of governance by requiring manual validation before changes are promoted to production.

Below is a simplified version of our pipeline configuration, designed for learning purposes and to provide a foundational understanding of CI/CD workflows.

  • Verification (verify stage): A dry-run using Ansible to preview potential changes before deployment.
  • Deployment (deploy stage): Executes automation tasks to provision and configure network infrastructure.
  • Testing (test stage): Validates the deployed changes by verifying the actual network state through automated tests.
default:
  image: 198.18.134.23:5050/ltrops-2341/pod-2/ansible:latest

stages:
  - verify
  - deploy
  - test

ansible_dry-run:
  stage: verify
  script:
    - ansible-playbook ansible/create-site-hierarchy.yml --check

deploy_infastructure:
  stage: deploy
  script:
    - ansible-playbook ansible/create-site-hierarchy.yml

test_network_state:
  stage: test
  script:
    - pyats run job pyATS/job.py

This configuration results into the following Gitlab pipeline:

Example Pipeline

Key Pipeline Features Explained

To better understand how our pipeline functions, let's explore some essential GitLab CI/CD concepts used in the configuration. These features help optimize, control, and reuse configurations across different stages and jobs.

  • Artifacts: artifacts store generated files from a job so they can be downloaded or used later
  • Extends: extends allows jobs to inherit settings from predefined templates, reducing duplication
  • Rules: rules define when a job should execute based on conditions
  • When: The when: manual setting pauses execution until triggered manually by a user

Step 2: Review and edit the pipeline configuration

  1. Open the file .gitlab-ci.yml.

  2. Go to Gitlab and copy the image path by click on the icon:

    Example Pipeline

  3. Edit the image on top to match your newly added Docker image:

    default:
      image: path_to_your_image
    

Pipeline triggers

By default, GitLab pipelines are triggered by code changes, such as:

  • Pushing commits to a branch.
  • Creating or updating a merge request.

This approach is commonly used in Infrastructure as Code (IaC) workflows, where changes to network configurations are managed via Git. Merge request pipelines allow for extensive testing and approval before deployment, ensuring infrastructure stability.

In a NetBox-Driven Environment

Unlike traditional IaC, our network infrastructure is managed through NetBox rather than direct code changes. This means:

  • Code does not change, but deployment data does.
  • NetBox updates (e.g., adding devices, modifying configurations) must trigger automation.

Alternative Triggering Methods

Since we cannot rely on Git changes, we use manual pipeline triggers:

  • Web Triggers (UI-Based Execution)
  • API Trigger with Tokens

Step 3: Update your git repository

git add .
git commit -m "mission-5 gitlab-ci"
git push

Step 4: Trigger the pipeline via Web for site-creation

The pipeline has been structured into two distinct workflows to separate site creation from switch onboarding. This approach reflects real-world network automation scenarios, where:

  • A site can be pre-provisioned independently, without immediately adding a switch
  • A switch can be added later to an existing site without requiring a full site deployment

Since our sites have already been created and we don't want to delete and recreate them, we will manually trigger the site-creation pipeline via the GitLab Web UI.

  1. Navigate to your Repository

  2. In the left menu click on Build > Pipelines

    Example Pipeline Menu

  3. In the top right corner, click on New pipeline

  4. Add a variable named SITE_PIPELINE and add the the value true to it. Click on New pipeline:

    Example Web trigger

  5. Wait for the site-creation_dry-run to sucessfully complete and then you have to option to verify by clicking on it.

  6. Navigate back and trigger the deploy job:

    Example site create pipeline

  7. As soon as the job successfully executed, check in Catalyst Center if the site hierarchy was created sucessfully.

    Example Pod-1:

    Example Pod1 site hierarchy

Step 5: Create a pipeline trigger token

  1. Navigate to Settings > CI/CD > Pipeline trigger tokens in your Gitlab repository.

  2. Create a new token by clicking on Add new token. Add a description and click on Create pipeline trigger token.

Step 6: Adjust your netbox custom script to trigger the pipeline

  1. Open the Netbox custom-script ./netbox/pod2_switches.py and add the following to the end of the script.

            if commit:
                self.log_info("Commit is set. Triggering GitLab pipeline...")
                project = "8"
                url = f"http://198.18.134.23/api/v4/projects/{project}/ref/master/trigger/pipeline"
                token = "YOUR TOKEN HERE" # replace with your token
    
                params = {
                    "token": token,
                    "variables[SWITCH_PIPELINE]": "true"
                }
    
                try:
                    response = requests.post(url, params=params)
                    response.raise_for_status()
    
                    if response.status_code == 201:
                        self.log_success("Pipeline triggered successfully.")
                    else:
                        self.log_warning(
                            f"Unexpected response status: {response.status_code}. Response: {response.text}"
                        )
                except requests.exceptions.RequestException as e:
                    self.log_failure(f"Failed to trigger pipeline: {e}")
            else:
                self.log_info("Commit is not set. Skipping GitLab pipeline trigger.")
    
  2. Copy your newly created trigger Token.

    Copy pipeline trigger token

  3. Replace the token in your script.

  4. Commit and push your changes to git:

    git add .
    git commit -m "mission-5 custom script"
    git push
    
  5. In Netbox Devices > Devices make sure to delete your previously created switch.

  6. Navigate to Operations > Data Sources, click on your data source and then on Sync.

  7. Recreate the switch by navigating to Customization > Scripts and run your custom script Add Switches to Site.

    Switch creation variables
    Key Value
    Tenant pod2
    Site $YOUR_SITE
    Device Type C9KV-UADP-8P
    Device Role Branch Switch
    Device Uplink GigabitEthernet1/0/1
    Serial Numbers CML12SW1
    Commit changes true
  8. Check the pipeline status in your Repository, by clicking on the running pipeline. Once the dry-run went through, you can verify the output by clicking on it.

  9. Trigger the deploy stage. The pipeline can easily take up to 15 minutes, as we are doing a PnP and a switch provision before moving forward. Feel free to take a break!

  10. Meanwhile you can check the status also in Catalyst Center. You should see your switch there in different states before reaching Provisioned

  11. When the pipeline successfully went through, your switch should be in active state in Netbox and also added to your site in Catalyst Center Inventory.