Lab Hygiene
Lab Hygiene
Brilliant topologies rot without hygiene: colliding subnets, random hostnames, uncommitted click-ops, and mystery cables. This chapter is the professional layer on top of Containerlab—how to keep labs reproducible, reviewable, and kind to future you.
Learning goals
By the end of this chapter you can:
- Write an addressing plan before deploy
- Apply consistent node and interface naming
- Structure a lab repo/directory for git
- Keep diagrams and inventories in sync
- Run a personal definition-of-done for every lab
- Avoid cross-lab contamination on one host
Why hygiene is a skill
| Without hygiene | With hygiene |
|---|---|
| “Which 10.0.0.0/24 is this?” | Documented per-lab blocks |
| Works once after 40 hand edits | Destroy/deploy/verify loop |
| Cannot explain a failure | Journal + captures |
| Peer cannot run your lab | README + pins + scripts |
Hygiene is not bureaucracy; it is how lab craft scales.
Addressing plans
Never invent IPs mid-SSH.
Template
# Addressing — lab triangle-ospf
| Node | Interface | Address | Notes |
|------|-----------|---------|-------|
| r1 | eth1 | 10.0.12.1/24 | to r2 |
| r2 | eth1 | 10.0.12.2/24 | to r1 |
| r1 | eth2 | 10.0.13.1/24 | to r3 |
| r3 | eth2 | 10.0.13.2/24 | to r1 |
| r2 | eth2 | 10.0.23.1/24 | to r3 |
| r3 | eth1 | 10.0.23.2/24 | to r2 |
| h1 | eth1 | 192.168.1.10/24 | gw 192.168.1.1 (r1 lo/lan) |
Loopbacks:
| Node | lo |
|------|-----|
| r1 | 1.1.1.1/32 |
| r2 | 2.2.2.2/32 |
| r3 | 3.3.3.3/32 |
VLANs: n/a
ASNs: n/a
Mgmt: Containerlab default poolAllocation strategy (personal lab supernets)
Pick a lab supernet you will not confuse with home LAN:
| Use | Example block |
|---|---|
| Home LAN (real) | 192.168.1.0/24 (do not reuse in labs if VPN splits break) |
| Lab underlay P2P | 10.0.0.0/16 carved into /24 or /30 |
| Lab customer VRFs | 10.10.0.0/16 |
| Loopbacks | 10.255.0.0/24 as /32s |
| “Internet” sim | 203.0.113.0/24 (documentation range) / 192.0.2.0/24 |
Documentation ranges (RFC 5737) are great for examples in prose; inside isolated labs private space is fine—just write it down.
/30 vs /31 vs /24 on links
| Choice | When |
|---|---|
| /24 | Beginners, lots of headroom, wasteful |
| /30 | Classic P2P |
| /31 | Efficient P2P (ensure both NOS support) |
Be consistent within a lab.
Naming conventions
Lab name
name: l2-vlan-trunk # short, hyphenated, unique among active labsContainer names become clab-<name>-<node>.
Node names
| Pattern | Examples |
|---|---|
| Role + number | r1, r2, sw1, h1 |
| Role + site | edge-a, core-1 |
| Avoid | test, node, foo, router |
Interface names
Stick to what the image uses (eth1, eth2… for many Linux kinds). Document any breakout or rename.
Git branches / folders
labs/
03-l2-vlan-trunk/
04-static-triangle/
05-ospf-single-area/
Numeric prefixes match book order when useful.
Directory layout (canonical)
labs/04-static-triangle/
README.md # intent, pins, how to run
topology.clab.yml
addressing.md
journal.md
verify.sh
up.sh # optional deploy wrapper
down.sh # destroy --cleanup
config/
r1/
r2/
h1/
captures/
diagrams/
logical.png # or .svg / .drawio
README skeleton
# Static triangle
## Intent
Three FRR routers, static routes, dual hosts ping.
## Images
- quay.io/frrouting/frr:10.2.1
- alpine:3.20
## Run
sudo containerlab deploy -t topology.clab.yml
./verify.sh
sudo containerlab destroy -t topology.clab.yml --cleanup
## Failure drills
- shut transit link r1-r2
- remove return route on r3Git habits
git status
git add labs/04-static-triangle
git commit -m "lab: static triangle with verify.sh"Commit:
- Topology YAML
- Configs
- addressing.md
- verify.sh
- journal highlights (not necessarily huge pcaps)
Usually ignore:
- Large pcaps (store sparse samples or regenerate)
- Ephemeral logs
# example snippet
labs/**/captures/*.pcap
!labs/**/captures/.gitkeep
Never commit
- Production credentials
- Private keys
- Proprietary images
Diagram habit
Minimum viable diagram set:
- Logical — nodes and links
- Addressing — subnets/VLAN IDs on links
- Failure — which link you shut for the drill
ASCII is valid:
h1--r1------r2--h2
\ /
\ /
r3
Illustrated topology SVGs (self-contained light canvas) match this book’s lab figures under images/; conceptual models may stay monochrome. See images/README.md.
Configuration hygiene
| Do | Don’t |
|---|---|
Edit files under config/ |
Treasure unique vtysh-only state |
| Reload/restart from files | Assume memory is durable |
| Diff configs in git | Copy-paste from chat without review |
| Comment tricky policy lines | Leave “magic” prefix-lists |
FRR example: comment intent
! block lab RFC1918 from leaking to "isp" peer
ip prefix-list LAB-PRIV seq 5 permit 10.0.0.0/8 le 32
verify.sh hygiene
set -euo pipefail
- Explicit container names
- Timeouts on ping
- Exit non-zero on failure
- Print which check failed
#!/usr/bin/env bash
set -euo pipefail
PASS=0
fail() { echo "FAIL: $*" >&2; exit 1; }
docker exec clab-static-h1 ping -c 2 -W 1 10.2.0.10 \
|| fail "h1 cannot reach h2"
echo "OK: all checks passed"Cross-lab contamination
Symptoms:
- Wrong SSH target (same hostname different lab)
- Stale docker networks
- IP confusion in your brain
Mitigations:
sudo containerlab inspect --all 2>/dev/null || true
docker ps --format 'table {{.Names}}\t{{.Status}}' | grep clab || true
# Only one “heavy” lab running when learning
sudo containerlab destroy -t old.clab.yml --cleanupUse unique lab name: fields always.
Time hygiene
Put dates in journals; note Containerlab and image versions:
Date: 2026-08-04
containerlab: 0.xx.x
frr image: 10.2.1
kernel: $(uname -r)Future breakage is often a version drift story.
Definition of done (lab)
- Intent one-liner in README
- addressing.md complete
- topology deploys clean on fresh destroy
- verify.sh green
- One failure drill documented
- Diagrams match YAML
- Secrets absent
- Image tags pinned
- Committed to git
Predict → observe → fix: hygiene drill
- Predict: A peer can clone your lab folder and pass
verify.shwithout asking you questions.
- Observe: Remove your personal aliases; follow only README.
- Fix: Gaps become README bullets.
- Harden: Add
up.sh/down.sh.
#!/usr/bin/env bash
# up.sh
set -euo pipefail
sudo containerlab deploy -t topology.clab.yml
./verify.sh#!/usr/bin/env bash
# down.sh
set -euo pipefail
sudo containerlab destroy -t topology.clab.yml --cleanupCollaboration norms (optional)
If sharing labs:
- Prefer open images only
- Include expected verify output sample
- Note host requirements (RAM)
- License your configs clearly (e.g. MIT notes)
Summary
- Address first, deploy second
- Name labs and nodes for humans and
docker ps
- Canonical directory: topology, configs, verify, journal, diagrams
- Git is part of networking practice
- One clean destroy/deploy is worth ten fragile demos
- Definition of done prevents “almost labs”
Part checkpoint: topology-as-code should feel like muscle memory. Next part enters layer 2—Ethernet, VLANs, loops, aggregation, and failure drills.