Network Lab Simulation with Containerlab: Build Virtual Router and Switch Environments Faster Than GNS3

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Three years ago I was spinning up GNS3 to test a BGP failover scenario before pushing it to production. The VM took 8 minutes to boot, ate 12 GB of RAM, and crashed twice before I could even ping between routers. That was the moment I started looking for something better — and Containerlab changed everything.

Network engineers and DevOps practitioners both know the lab problem: you need a realistic environment to test against, but standing one up takes forever. Containerlab solves this by defining and deploying multi-vendor network topologies using containers instead of bloated VMs. Full routing protocol support, real vendor OS images, and the whole lab spins up in under 60 seconds.

Quick Start — Up and Running in 5 Minutes

Getting Containerlab running is genuinely fast. You need Docker installed and a Linux host (or WSL2 on Windows).

Install Containerlab

# One-liner install (official script)
bash -c "$(curl -sL https://get.containerlab.dev)"

# Verify installation
clab version

That’s it. No pip, no virtualenv, no dependency hell.

Your First Lab — Three Routers, Two Minutes

Create a file called lab01.yml:

name: first-lab

topology:
  nodes:
    router1:
      kind: linux
      image: frrouting/frr:latest
    router2:
      kind: linux
      image: frrouting/frr:latest
    router3:
      kind: linux
      image: frrouting/frr:latest

  links:
    - endpoints: ["router1:eth1", "router2:eth1"]
    - endpoints: ["router2:eth2", "router3:eth1"]

Deploy it:

sudo clab deploy -t lab01.yml

You’ll see the containers spin up and a table showing every node’s management IP. Total time from zero to three connected routers: about 25 seconds on a mid-range laptop.

To connect to router1:

sudo docker exec -it clab-first-lab-router1 vtysh

When you’re done:

sudo clab destroy -t lab01.yml

Containers gone, network interfaces cleaned up, nothing left behind.

Deep Dive — Understanding Containerlab Topology Files

Containerlab’s topology YAML does one job: describe your network. Once you internalize the structure, you can model almost any real-world scenario.

Node Kinds and Images

Containerlab supports several node kinds out of the box:

  • linux — any Docker image running Linux (FRRouting, Bird, VyOS)
  • srl — Nokia SR Linux (free, full-featured, excellent for labs)
  • ceos — Arista cEOS (requires free registration at arista.com)
  • crpd — Juniper cRPD (requires Juniper license)
  • vr-ros — MikroTik RouterOS via vrnetlab

For most labs without vendor licenses, FRRouting on Linux covers OSPF, BGP, IS-IS, MPLS, and more. Nokia SR Linux is free to pull and gives you a genuine network OS experience.

Configuring Nodes at Deploy Time

Startup configs mount directly into containers via the binds key — no manual copying after deploy:

name: ospf-lab

topology:
  nodes:
    r1:
      kind: linux
      image: frrouting/frr:latest
      binds:
        - configs/r1/frr.conf:/etc/frr/frr.conf
        - configs/r1/daemons:/etc/frr/daemons

    r2:
      kind: linux
      image: frrouting/frr:latest
      binds:
        - configs/r2/frr.conf:/etc/frr/frr.conf
        - configs/r2/daemons:/etc/frr/daemons

  links:
    - endpoints: ["r1:eth1", "r2:eth1"]
      mtu: 9000

Your router config lives on the host — version-controlled, diffable, and reproducible across machines.

Network Links and Attributes

Links are veth pairs under the hood. Set MTU, simulate latency, or bridge to a physical host interface — all in the topology file:

  links:
    # Simple link
    - endpoints: ["r1:eth1", "r2:eth1"]

    # With impairments (latency simulation)
    - endpoints: ["r1:eth2", "r3:eth1"]
      mtu: 1500

    # Bridge to host physical interface
    - endpoints: ["r2:eth3", "host:ens4"]

Advanced Usage — Multi-Vendor BGP Lab

I use this kind of setup to test BGP policy changes before touching production routers. The topology below runs in about 45 seconds on a 4-core machine with 8 GB RAM. GNS3 with equivalent Cisco IOS VMs would need 16 GB minimum.

BGP Lab with FRRouting

name: bgp-lab

topology:
  nodes:
    isp1:
      kind: linux
      image: frrouting/frr:latest
      binds:
        - configs/isp1/frr.conf:/etc/frr/frr.conf
        - configs/isp1/daemons:/etc/frr/daemons

    isp2:
      kind: linux
      image: frrouting/frr:latest
      binds:
        - configs/isp2/frr.conf:/etc/frr/frr.conf
        - configs/isp2/daemons:/etc/frr/daemons

    customer:
      kind: linux
      image: frrouting/frr:latest
      binds:
        - configs/customer/frr.conf:/etc/frr/frr.conf
        - configs/customer/daemons:/etc/frr/daemons

    client:
      kind: linux
      image: alpine:latest

  links:
    - endpoints: ["isp1:eth1", "customer:eth1"]
    - endpoints: ["isp2:eth1", "customer:eth2"]
    - endpoints: ["customer:eth3", "client:eth0"]

A minimal FRRouting BGP config for the customer router (configs/customer/frr.conf):

frr version 9.0
frr defaults traditional
hostname customer

router bgp 65001
 bgp router-id 10.0.0.1
 neighbor 10.0.1.1 remote-as 65010
 neighbor 10.0.2.1 remote-as 65020
 !
 address-family ipv4 unicast
  network 192.168.100.0/24
  neighbor 10.0.1.1 soft-reconfiguration inbound
  neighbor 10.0.2.1 soft-reconfiguration inbound
 exit-address-family
!
line vty
!

And the daemons file to enable BGP:

bgpd=yes
ospfd=no
zebra=yes
vtysh_enable=yes

Inspecting the Running Lab

# Show all nodes and their management IPs
sudo clab inspect -t bgp-lab.yml

# Connect to customer router vtysh
sudo docker exec -it clab-bgp-lab-customer vtysh

# Inside vtysh — check BGP neighbors
show bgp summary
show ip route bgp

# Capture traffic on eth1
sudo ip netns exec clab-bgp-lab-customer tcpdump -i eth1 -n

Using Nokia SR Linux (Free, No License)

name: srl-lab

topology:
  nodes:
    leaf1:
      kind: srl
      image: ghcr.io/nokia/srlinux:latest
    leaf2:
      kind: srl
      image: ghcr.io/nokia/srlinux:latest
    spine1:
      kind: srl
      image: ghcr.io/nokia/srlinux:latest

  links:
    - endpoints: ["leaf1:e1-1", "spine1:e1-1"]
    - endpoints: ["leaf2:e1-1", "spine1:e1-2"]

SR Linux ships with a proper CLI plus gRPC, gNMI, and JSON-RPC interfaces — solid for testing automation scripts against something that actually behaves like a real vendor OS.

Practical Tips from the Field

Resource Comparison: Containerlab vs GNS3

On the same 8-core, 16 GB RAM machine, running a 5-node OSPF topology:

  • GNS3 with Cisco IOS VMs: ~10 GB RAM, 4-8 minutes boot time, one VM per router
  • Containerlab with FRRouting: ~400 MB RAM, under 30 seconds, one container per router
  • Containerlab with Nokia SR Linux: ~1.2 GB RAM per node, 60-90 seconds, full vendor OS

For most protocol testing — OSPF, BGP, MPLS, routing policies — FRRouting containers give you everything you need at a fraction of the resource cost.

Save and Restore Router Configs

After making manual changes in vtysh, save the config back to the host:

# Save running config from container to host
sudo docker exec clab-bgp-lab-customer vtysh -c "write memory"
sudo docker cp clab-bgp-lab-customer:/etc/frr/frr.conf ./configs/customer/frr.conf

Now your lab config is version-controlled. Push it to Git, share with teammates, recreate the identical lab anywhere.

Integrate Containerlab into CI/CD

The YAML-file-plus-Docker-image model fits naturally into CI pipelines. Validate network config changes before they ever merge:

# .github/workflows/network-test.yml
jobs:
  network-lab-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Containerlab
        run: bash -c "$(curl -sL https://get.containerlab.dev)"
      - name: Deploy lab
        run: sudo clab deploy -t tests/bgp-lab.yml
      - name: Run connectivity tests
        run: |
          sleep 30  # Wait for BGP convergence
          sudo docker exec clab-bgp-lab-client ping -c 3 192.168.100.1
      - name: Destroy lab
        if: always()
        run: sudo clab destroy -t tests/bgp-lab.yml

Graphing Your Topology

There’s also a built-in topology visualizer:

sudo clab graph -t bgp-lab.yml

This opens a web browser with an interactive topology diagram — useful for documentation and understanding large labs at a glance.

Useful clab Commands to Keep Handy

# List all running labs
sudo clab inspect --all

# Redeploy without destroying (reconfigure)
sudo clab redeploy -t lab01.yml

# Deploy with specific prefix to avoid naming collisions
sudo clab deploy -t lab01.yml --prefix myproject

# Save all node configs at once
sudo clab save -t lab01.yml

If you’re doing serious network engineering or infrastructure automation, Containerlab fluency pays off fast. Spin up, test, break, and rebuild — all in under a minute, no physical lab required, no VM hypervisor tax. Once your topology YAMLs and router configs share a Git repo, the distance between “lab testing” and “production confidence” shrinks to almost nothing.

Start with a two-router FRRouting setup. Get comfortable with the YAML syntax, then graduate to SR Linux or cEOS when you need vendor-specific behavior. An afternoon is enough to get productive.

Share: