Version Control for Network Configurations
Git and GitLab CI/CD for Network Teams

Search for a command to run...
Git and GitLab CI/CD for Network Teams

No comments yet. Be the first to comment.
Network Validation and Testing for Modern Networks

A Practical Guide to the Tools That Bring It to Life

Building Your Network Source of Truth — Click by Click

Event-driven automation is redefining how networks respond to the unexpected. Here is what EDA is and why it is a game-changer.

codednetwork
17 posts
Network configurations change constantly — interfaces go up and down, routes shift, software gets upgraded. Without version control, there's no record of what changed, when, or by whom. Git addresses this for code. Here's how to extend that approach to your entire network.
Software developers have relied on version control for decades, tracking every line of code, attributing every change, and allowing mistakes to be undone with a single command. Network engineers, however, have traditionally lacked this convenience—configurations reside on devices, changes are made manually, and the audit trail depends on what you remember to document.
Applying Git to network configuration management changes this completely. When every config change is committed to a repository you get a full history of your network state, the ability to diff any two points in time, and the foundation for automation via CI/CD pipelines.
Git is a distributed version control system where each repository copy holds the complete history. You work locally, commit changes, and then push to a shared server, such as GitLab.
Before moving forward, let's ensure we have a clear understanding of some key terminology.
Repository : In Git, a repository refers to the database that holds all of a project's information, including files, metadata, and history. Here, "project" is used to denote any arbitrary collection of work
Working directory : This is the directory where you, as a Git user, modify the files within the repository.
Index : The index represents the repository’s directory structure and contents at a specific moment. It is a dynamic binary file managed by Git, which updates as you stage changes and commit them to the repository.
Commit : A commit is an entry in the Git repository that records metadata for each change made. This metadata includes the author, the date of the commit, and a commit message, which describes the change introduced to the repository.
| Command | Detail |
|---|---|
| git init | Start a new git repository in the current folder |
| git clone | Download a copy of a GitLab repository to your machine |
| git status | Show which files have changed since the last commit |
| git add . | Stage all changed files — prepare them for a commit |
| git commit -m "msg" | Save a named snapshot of all staged changes |
| git push origin main | Upload your commits to the remote GitLab repository |
| git pull origin main | Download and merge the latest changes from GitLab |
| git log --oneline | Show a compact history of all commits in the repo |
| git diff | Show exactly what lines changed in unstaged files |
| git reset --hard | Discard all local changes and return to last commit |
Here's the core workflow for managing network configuration files:
# Make a change to your router list
vim inventory.yml
# Stage the change
git add inventory.yml
# Save a named snapshot
git commit -m "Add router3 to lab inventory"
# Upload to GitLab — triggers pipeline automatically
git push origin main
What if your router configurations backed themselves up every night and flagged exactly what changed? Here is how I built a fully automated backup and inventory pipeline for Nokia SROS routers using GitLab CI/CD and Netmiko.
Manual router backups are tasks everyone knows they should perform but often neglect. You might make a change late on a Friday, forget to save a copy, and weeks later find yourself looking at a configuration that seems unfamiliar, with no clue when or how it was altered.
Managing a lab environment running Nokia SR OS routers brought this problem into sharp focus. The goal was simple: automate both the backup and change detection so that nothing slips through the cracks, and store everything in version control so you always have a full audit trail.
GitLab is a web-based platform that hosts Git repositories and adds powerful automation on top. The .gitlab-ci.yml file in your repository defines a pipeline — a sequence of automated jobs that run whenever specific events occur.
#.gitlab-ci.yml snapshot
backup-job: # job name
stage: backup # which stage it belongs to
variables:
GIT_STRATEGY: fetch # how to get the repo code
script:
- python backup.py # your automation script
- git add clab-backups/
- git commit -m "router backup [ci skip]"
- git push origin HEAD:$CI_COMMIT_BRANCH -o ci.skip
tags:
- nokia-runner # which machine runs this
This is a two-job GitLab CI/CD pipeline that runs on a schedule. One job gathers router inventory and identifies changes, while the other captures the complete configuration. All results are committed back to the same GitLab repository, providing a version-controlled history of your entire network state.
inventory-job — smart change detection
Connects to each router via SSH using Netmiko, executes show commands, and compares the output with the last saved report. A new file is created and committed to the repository only if changes are detected.
Smart saving: if nothing changed between runs the job exits cleanly with no commit and no push. Your git history only grows when something actually happened on the network.
backup-job — full config capture
Always runs on every pipeline. Captures the complete running configuration via admin display-config. Saves a timestamped file per router. Verifies completeness by checking for exit all at the end. Keeps the last three backups per router.
image: python:3.9.21
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
GIT_STRATEGY: fetch
cache:
paths:
- .cache/pip
- venv/
stages:
- inventory
- backup
before_script:
- python -V
- python -m pip install --upgrade pip
- python -m pip install virtualenv
- python -m virtualenv venv
- source venv/bin/activate
- pip install -r requirements.txt
- rm -fr .git/rebase-merge .git/rebase-apply
- git config --global user.email "$GITLAB_USER_EMAIL"
- git config --global user.name "$GITLAB_USER_ID"
- git config --global pull.rebase false
- git fetch origin
- git reset --hard origin/$CI_COMMIT_BRANCH
inventory-job:
stage: inventory
variables:
GIT_STRATEGY: fetch
script:
- python inventory.py
- git add clab-inventory/
- >
if ! git diff-index --quiet HEAD; then
git commit -m "inventory update [ci skip]"
git remote set-url --push origin "https://\(TOKEN_NAME:\)ACCESS_TOKEN@\(CI_SERVER_HOST/\)CI_PROJECT_PATH.git"
git push origin HEAD:$CI_COMMIT_BRANCH -o ci.skip
else
echo "No inventory changes to commit"
fi
rules:
- if: '$CI_PIPELINE_SOURCE == "push"'
changes:
- inventory.yml
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
tags:
- nokia-runner
backup-job:
stage: backup
variables:
GIT_STRATEGY: fetch
script:
- python backup.py
- git add clab-backups/
- >
if ! git diff-index --quiet HEAD; then
git commit -m "router backup [ci skip]"
git remote set-url --push origin "https://\(TOKEN_NAME:\)ACCESS_TOKEN@\(CI_SERVER_HOST/\)CI_PROJECT_PATH.git"
git push origin HEAD:$CI_COMMIT_BRANCH -o ci.skip
else
echo "No backup changes to commit"
fi
tags:
- nokia-runner
inventory-job log output
Created output files
Create Gitlab Project - Log into gitlab.com, click New Project, create a blank private project named router-backups.
Add your files - Create .gitlab-ci.yml, backup.py, inventory.py, inventory.yml, and requirements.txt in the repository root.
Set CI/CD variables - Go to Settings > CI/CD > Variables. Add ACCESS_TOKEN (Maintainer role), TOKEN_NAME, and ROUTER_PASSWORD (masked).
Register a GitLab Runner - Install gitlab-runner on the Linux machine that can reach your routers. Register with shell executor and tag nokia-runner.
Set up a schedule - Go to Build > Schedules, create a schedule with cron 0 2 * * * to run daily at 2 AM.
Run the first pipeline - Go to Build > Pipelines, click Run pipeline. Both jobs execute and first backup files appear in clab-backups/.
Once the runner is registered and variables are set, the system is self-maintaining. It backs up your routers and records changes automatically — no manual steps needed.
Use shell executor, not docker : Docker networking prevents the runner from reaching internal lab routers. Shell executor runs directly on the machine and has full network access to your SROS devices.
environment no more is not optional : Nokia SR OS paging will silently truncate your backups. This must be the first command you send after connecting — before any show commands or admin display-config.
Hard reset beats rebase in CI/CD : git reset --hard origin/main at the start of every job is more reliable than trying to rebase or merge diverged branches mid-pipeline.
Project Access Token needs Maintainer role : A token with Guest role cannot push to the repo. Create a Project Access Token and explicitly set the role to Maintainer during creation.
Filenames matter — check for hidden spaces : A leading space in inventory.yml caused hours of confusion. Always run ls -la on the runner to verify filenames have no invisible characters.
send_command_timing for large output : For admin display-config, timing-based reading is more reliable than pattern matching on large outputs that take unpredictable time to stream from the router.