ContainerLab 〡 Tutorials

ContainerLab for Network Automation Labs – Part 2: NetOps Server and Routing

Milan Zapletal
December 21, 2025

Table Of Contents

Building on our ContainerLab foundation to create a complete network automation environment.

In Part 1 of our ContainerLab series, we established a solid foundation by deploying Google Cloud VMs with ContainerLab. Now we’re ready to build the complete network automation environment by deploying a dedicated NetOps server and configuring the essential routing that enables seamless management of our containerized network devices.

What We’ll Accomplish

This post focuses on two critical objectives:

  1. Deploy a production-ready NetOps server using Netodata’s proven setup approach
  2. Configure Google Cloud VPC routing to enable connectivity between our NetOps server and ContainerLab management networks

By the end of this guide, you’ll have a fully functional network automation environment where your NetOps server can manage and automate containerized network devices through proper routing configuration.

Architecture Overview

Our target architecture includes:

  • NetOps Server: Dedicated VM running Python, Nornir, and network automation tools
  • ContainerLab Server: Our existing VM from Part 1 hosting network device containers
  • Management Network: Routed connectivity enabling NetOps server to manage devices
  • Google Cloud VPC Routes: Proper routing configuration for inter-VM communication

Part 1: NetOps Server Deployment

Script-Based Deployment (Recommended)

At Netodata, we’ve developed a comprehensive setup script that automates the deployment of all necessary NetOps dependencies. This approach ensures consistency across environments and reduces deployment time from hours to minutes.

High-Level Requirements

Our NetOps server includes these essential components:

Core Infrastructure:

  • Python 3 with virtual environment isolation
  • Git for version control and configuration management
  • System utilities for network troubleshooting

Network Automation Stack:

  • Nornir: Python-based automation framework
  • NetMiko & NAPALM: Multi-vendor device connectivity
  • PyNetBox: NetBox API integration
  • Jinja2: Configuration templating engine

Directory Structure:

Bash
/opt/netops/
├── scripts/          # Automation scripts
├── inventory/        # Device inventories
├── templates/        # Jinja2 configuration templates
├── logs/            # Execution logs
├── backups/         # Configuration backups
├── data/            # Runtime data
└── venv/            # Python virtual environment

Quick Deployment

Deploy your NetOps server with our automated script:

Bash
# Deploy with URL format for GitLab raw files
curl -sSL https://gitlab.com/netodata/netodata-toolkit/-/raw/main/netops_server/deploy.sh | sudo bash

Or:

Bash
# Download the script first
curl -sSL https://gitlab.com/netodata/netodata-toolkit/-/raw/main/netops_server/deploy.sh -o deploy.sh

# Inspect the script before running
head -20 deploy.sh

# Make executable and run
chmod +x deploy.sh
sudo ./deploy.sh

# Verify installation
source /opt/netops/venv/bin/activate
python -c "import nornir, netmiko, napalm; print('NetOps environment ready')"

Complete script and documentation:

Bash
# Other ways to confirm deployment after installation
(venv) ubuntu@lettered-grison:~$ python /opt/netops/verify_install.py

NetOps Installation Verification
------------------------------
Python version: 3.10.12 (main, Feb  4 2025, 14:57:36) [GCC 11.4.0]
Platform: Linux-5.15.0-140-generic-aarch64-with-glibc2.35
Nornir version: 3.5.0
Netmiko version: 4.5.0
NAPALM version: 5.0.0

All required packages are installed correctly.
NetOps environment is ready to use.

Alternative Deployment Approaches

For enterprise environments, consider these advanced deployment methods:

Infrastructure as Code (Terraform):

  • Automated cloud resource provisioning
  • Version-controlled infrastructure changes
  • Consistent deployments across environments

CI/CD Pipeline Integration:

  • Automated testing and deployment
  • Configuration drift detection
  • Rollback capabilities

Note: Detailed implementation of these advanced approaches will be covered in future enterprise-focused posts.

Part 2: Network Routing Configuration

Understanding Google Cloud VPC Routing

Before configuring routes, it’s essential to understand how Google Cloud’s Software Defined Networking differs from traditional networking approaches.

Key Concepts:

  • VPC-Level Control: All routing decisions occur at the VPC level, not individual VMs
  • Distributed Routing: No physical routing devices; routing is handled by Google’s network fabric
  • Route Precedence: VPC routes override any VM-level routing configurations

Why VM-Level Routes Don’t Work:

Many network engineers initially attempt to configure routes using traditional Linux commands:

Bash
# This approach WILL NOT WORK on Google Cloud
sudo ip route add 172.20.20.0/24 via 10.128.0.50

Even when this route appears in the VM’s routing table, inter-VM traffic will still fail with “network unreachable” errors because Google Cloud’s VPC doesn’t recognize VM-level routes for inter-instance communication.

Configure VPC Routes for Management Access

Method 1: Google Cloud Console (GUI)

For users who prefer graphical interfaces:

  1. Navigate to VPC Network → Routes
  2. Click “Create Route”
  3. Configure route parameters:
  • Name: netops-to-containerlab-mgmt
  • Description: Route NetOps traffic to ContainerLab management subnet
  • Destination IP range: 172.20.20.0/24
  • Priority: 1000
  • Next hop: Instance
  • Next hop instance: containerlab-server
  • Next hop instance zone: us-central1-a
Listed routes in Google Cloud Console

Method 2: gcloud CLI (Recommended)

For automation and documentation purposes:

Bash
# Create custom route in GCP VPC
gcloud compute routes create netops-to-containerlab-mgmt \
    --destination-range=172.20.20.0/24 \
    --next-hop-instance=containerlab-server \
    --next-hop-instance-zone=us-central1-a \
    --priority=1000 \
    --description="Route NetOps traffic to ContainerLab management subnet"

# Verify route creation
gcloud compute routes list --filter="name:netops-to-containerlab-mgmt"

Why GCP-Level Routing is Essential

Google Cloud’s VPC routing requirements exist because:

  1. Centralized Control: VPC manages routing decisions for the entire network fabric
  2. Security Model: Only explicitly defined routes are allowed between instances
  3. Performance: Routing decisions are made at the hardware level in Google’s network infrastructure

Without proper VPC routes, packets destined for the ContainerLab management subnet are dropped with ICMP “network unreachable” messages, regardless of VM-level routing configurations.

Configure Network Device Default Routes

Once VPC routing is established, containerized network devices need default routes pointing to their management gateway.

Sample ContainerLab Topology:

YAML
name: netops-routing-lab
topology:
  defaults:
    kind: linux
  nodes:
    spine1:
      kind: ceos
      image: ceos:4.28.3M
      mgmt-ipv4: 172.20.20.10
    leaf1:
      kind: ceos
      image: ceos:4.28.3M
      mgmt-ipv4: 172.20.20.11
    leaf2:
      kind: ceos
      image: ceos:4.28.3M
      mgmt-ipv4: 172.20.20.12
  links:
    - endpoints: ["spine1:eth1", "leaf1:eth1"]
    - endpoints: ["spine1:eth2", "leaf2:eth1"]

Device Configuration Examples

Arista cEOS Configuration:

Bash
# Connect to cEOS device
docker exec -it clab-netops-routing-lab-spine1 Cli

# Configure default route
configure
ip route 0.0.0.0/0 172.20.20.1
copy running-config startup-config
exit

Nokia SR Linux Configuration:

Bash
# Connect to SR Linux device
docker exec -it clab-netops-routing-lab-leaf1 sr_cli

# Configure default route
configure
/network-instance default static-routes route 0.0.0.0/0 next-hop 172.20.20.1
commit save
exit

FRRouting Configuration:

Bash
# Connect to FRR container
docker exec -it clab-netops-routing-lab-leaf2 vtysh

# Configure default route
configure terminal
ip route 0.0.0.0/0 172.20.20.1
write memory
exit

Part 3: Connectivity Testing and Validation

End-to-End Connectivity Tests

Basic Network Connectivity

Test fundamental network connectivity from your NetOps server:

Bash
# Test management subnet reachability
ping -c 3 172.20.20.10

# Verify routing table entries
ip route show | grep 172.20.20

# Test TCP connectivity to device management ports
nc -zv 172.20.20.10 22    # SSH
nc -zv 172.20.20.10 443   # HTTPS management

Device Management Protocol Testing

Bash
# SSH connectivity test
ssh admin@172.20.20.10 "show version"

# SNMP connectivity test
snmpwalk -v2c -c public 172.20.20.10 1.3.6.1.2.1.1.1.0

# HTTP/HTTPS management interface test
curl -k https://172.20.20.10/command-api

Automated Connectivity Validation

Python Connectivity Test Script

Create a comprehensive connectivity test using Nornir:

Python
#!/usr/bin/env python3
"""
NetOps Server Connectivity Validation Script
Tests connectivity to all ContainerLab management interfaces
"""

from nornir import InitNornir
from nornir.plugins.tasks.networking import netmiko_send_command
from nornir.plugins.functions.text import print_result
import ipaddress
import subprocess
import sys

def test_icmp_connectivity(mgmt_subnet="172.20.20.0/24"):
    """Test ICMP connectivity to management subnet"""
    print(f"Testing ICMP connectivity to {mgmt_subnet}")

    network = ipaddress.IPv4Network(mgmt_subnet)
    reachable_hosts = []

    for host in list(network.hosts())[:10]:  # Test first 10 hosts
        result = subprocess.run(
            ['ping', '-c', '1', '-W', '2', str(host)], 
            capture_output=True, 
            text=True
        )
        if result.returncode == 0:
            reachable_hosts.append(str(host))
            print(f"✓ {host} - Reachable")
        else:
            print(f"✗ {host} - Unreachable")

    return reachable_hosts

def test_device_connectivity():
    """Test device connectivity using Nornir"""
    nr = InitNornir(config_file="/opt/netops/config.yaml")

    # Test basic connectivity
    result = nr.run(
        task=netmiko_send_command,
        command_string="show version"
    )

    print_result(result)
    return result

if __name__ == "__main__":
    print("NetOps Server Connectivity Validation")
    print("=" * 40)

    # Test ICMP connectivity
    reachable = test_icmp_connectivity()

    if reachable:
        print(f"\nFound {len(reachable)} reachable devices")
        # Test device management connectivity
        test_device_connectivity()
    else:
        print("No devices reachable - check routing configuration")
        sys.exit(1)

Part 4: Troubleshooting Common Issues

Routing Problems

Issue: Route not appearing in routing table

Bash
# Check VPC routes
gcloud compute routes list --filter="nextHopInstance:containerlab-server"

# Verify instance exists and is running
gcloud compute instances list --filter="name:containerlab-server"

Solution:

  • Ensure instance name and zone are correct
  • Verify the instance is in RUNNING state
  • Check IAM permissions for route creation

Issue: “Network unreachable” errors despite correct routes

This typically indicates routing asymmetry or missing return routes.

Bash
# Test from NetOps server
traceroute 172.20.20.10

# Check ContainerLab server routing
gcloud compute ssh containerlab-server --command="ip route show"

Solution:

  • Verify bidirectional routing
  • Check ContainerLab bridge configuration
  • Ensure IP forwarding is enabled on ContainerLab server

ContainerLab Connectivity Issues

Issue: Containers unreachable despite VPC routing

Bash
# Check ContainerLab status
sudo containerlab inspect --all

# Verify bridge configuration
ip addr show clab-br-*

# Check container networking
docker network ls
docker inspect <container_name>

Solution:

  • Restart ContainerLab topology
  • Verify management IP assignments
  • Check container default routes

Device Configuration Problems

Issue: Default routes not persistent after container restart

ContainerLab containers may lose configuration after restarts.

Solution:

  • Use startup-config files
  • Implement configuration automation
  • Add route configuration to ContainerLab topology file
YAML
# Example: Persistent route configuration in topology
nodes:
  spine1:
    kind: ceos
    image: ceos:4.28.3M
    mgmt-ipv4: 172.20.20.10
    exec:
      - ip route add default via 172.20.20.1

Complete Environment Check

Once routing is configured, validate your complete environment:

Bash
# From NetOps server, test full automation workflow
cd /opt/netops
source venv/bin/activate

# Test Nornir inventory
python -c "
from nornir import InitNornir
nr = InitNornir(config_file='config.yaml')
print(f'Loaded {len(nr.inventory.hosts)} devices')
for host in nr.inventory.hosts:
    print(f'  - {host}: {nr.inventory.hosts[host].hostname}')
"

# Test device automation
python scripts/device_discovery.py

Network Topology Verification

Your completed environment should demonstrate:

  1. NetOps Server can reach ContainerLab management subnet
  2. Network devices have default routes to management gateway
  3. Bidirectional connectivity for management protocols
  4. Automation tools can successfully connect to all devices

Next Steps: Preparing for Automation

With routing configured and connectivity established, you now have a complete foundation for network automation. In Part 3, we’ll explore:

  • Testing automation scripts across the complete environment
  • Configuration management using Nornir and NetBox integration
  • Compliance checking and drift detection
  • Advanced automation workflows for enterprise networks

Your environment is now ready to support sophisticated network automation use cases that mirror production enterprise networks.

Conclusion

We’ve successfully built a complete network automation environment by:

  1. Deploying a production-ready NetOps server with Nornir and automation tools
  2. Configuring Google Cloud VPC routing for management network access
  3. Establishing device connectivity with proper default routes
  4. Validating end-to-end connectivity with comprehensive testing

This foundation enables network automation workflows that scale from lab testing to production deployment. The combination of containerized network devices and cloud-based automation servers provides the flexibility and reliability needed for modern network operations.

Key Takeaways:

  • Google Cloud VPC routing is essential for inter-instance communication
  • VM-level routes are insufficient for cloud networking
  • Proper routing configuration enables seamless automation workflows
  • Testing and validation are critical for reliable network automation

At Netodata, we help organizations implement similar network automation solutions in production environments. Our expertise in network automation, combined with proven deployment methodologies, enables enterprises to achieve operational excellence through automation.

Related Posts:


Ready to implement network automation in your organization? Contact Netodata to learn how we can help you build robust automation solutions tailored to your network infrastructure.

NETWORK AUTOMATION INSIGHTS
Stay informed about the latest in network automation:
Technical deep dives - Implementation guides -
Industry best practices
Netodata official logo featuring a stylized green geometric icon and the brand name "NETODATA" in white and green typography on a transparent background.
From initial consulting to seamless implementation, we manage your network automation journey every step of the way. Our comprehensive suite of professional services caters to diverse enterprises, ranging from startups to established players.
Contact
1-234-1234
info@netodata.io
Address
Nové sady 988/2
602 00, Brno
Czech Republic
ICO: 23213035
GET IN TOUCH
Address
Netodata Labs, s.r.o. © 2026 All Rights Reserved
Nautobot icon

Nautobot

The central Source of Truth for network infrastructure data. Nautobot serves as:
Authoritative inventory database
IP address components tracking
Configuration template repository
Automation platform

Nornir

A Python automation framework specifically designed for network automation. Nornir provides:
High-performance concurrent task execution
Deep Python integration
Flexible inventory management
Fine-grained control over network operations
CI/CD

Orchestration & CD/CI

We integrate industry-standard orchestration tools to ensure reliable automation delivery:
Git-based version control
Automated pipelines
Controlled deployment workflows
Continuous integration practices

Ansible

An industry-standard automation platform that excels at network configuration management. We utilize Ansible for:
Network device configuration deployment
State validation and compliance checking
Integration with custom Python modules
Standardized workflow automation

Netbox

The central Source of Truth for network infrastructure data. NetBox serves as:
Authoritative inventory database
IP address components tracking
Configuration template repository
REST API provider for automation workflows

Python

The foundation of our automation framework, Python enables us to create modular, maintainable, and efficient network automation solutions. We leverage Python's extensive standard library and carefully selected packages to build:
Reusable automation components
Custom network management tools
API integrations
Data processing pipelines