To run SONiC in containerlab, load the community docker-sonic-vs image and use the sonic-vs kind. The topology is five lines. The part the docs leave you to discover is how the image behaves once it is running, so this tutorial covers both.
Everything below ran on containerlab v0.82.0 on Ubuntu 24.04, on the 202511 branch build of docker-sonic-vs. containerlab is an independent open source project. NetPilot is a contributor and integrator, and the sonic-vs kind comes from the containerlab project.
NetPilot runs the same image on a cloud lab VM. The image is preloaded and the fixes in this post are already done, so a prompt gets you a working fabric. The rest of this post is for running it on your own host.
sonic-vs or sonic-vm
containerlab has two community SONiC kinds. This tutorial uses the container.
sonic-vs | sonic-vm | |
|---|---|---|
| Format | Container | VM in a vrnetlab container |
| Image | docker-sonic-vs.gz | sonic-vs.img.gz, built with vrnetlab |
| Boot | About 30 seconds to ports up, measured | About 1 minute, per the docs |
| Shell | docker exec | SSH, admin:admin per the docs |
| startup-config | No | Yes, per the docs |
Commercial builds have kinds of their own, such as dell_sonic.
Step 1: Get the image
You need Docker and containerlab on a Linux host, and no KVM, because sonic-vs is a plain container. The image is a build artifact, not a registry pull:
curl -L -o docker-sonic-vs.gz "https://sonic-build.azurewebsites.net/api/sonic/artifacts?branchName=202511&platform=vs&target=target/docker-sonic-vs.gz"
docker load -i docker-sonic-vs.gzLoaded image: docker-sonic-vs:latestThe file was 210 MB and the loaded image 816 MB. This URL follows the newest build on the branch, so your build number will differ from ours.
Step 2: Write the topology
Two switches, one link. It is also in the public repo.
name: sonic-two-switches
topology:
kinds:
sonic-vs:
image: docker-sonic-vs:latest
nodes:
sw1:
kind: sonic-vs
sw2:
kind: sonic-vs
links:
- endpoints: ["sw1:eth1", "sw2:eth1"]Links use ethN, and eth1 is the wire behind the SONiC port Ethernet0, eth2 behind Ethernet4. Use ethN in the topology and EthernetN on the switch. A link named Ethernet0 deploys without an error and the port never comes up.
Step 3: Deploy
sudo containerlab deploy -t two-switches.clab.yml│ clab-sonic-two-switches-sw1 │ sonic-vs │ running │ 172.20.20.2 │
│ clab-sonic-two-switches-sw2 │ sonic-vs │ running │ 172.20.20.3 │Deploy took under 4 seconds. The switch was not ready yet. In the first checks after deploy, the port table was empty, and the ports showed up about 30 seconds later. Wait, then open a shell:
docker exec -it clab-sonic-two-switches-sw1 bashYou are root inside the switch. There is no admin user and no password.
Step 4: Bring up the link
Ports boot admin down. On sw1:
config interface ip add Ethernet0 10.0.0.0/31
config interface startup Ethernet0On sw2:
config interface ip add Ethernet0 10.0.0.1/31
config interface startup Ethernet0Check the port, and do not be thrown by the first line:
show interfaces status Ethernet0/bin/sh: 1: sudo: not found
Interface Lanes Speed MTU FEC Alias Vlan Oper Admin Type Asym PFC
----------- ----------- ------- ----- ----- ------------ ------ ------ ------- ------ ----------
Ethernet0 25,26,27,28 10G 9100 N/A fortyGigE0/0 routed up up N/A N/AThen ping across it from sw1:
ping -c 3 10.0.0.164 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.446 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.348 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.303 ms
--- 10.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2032msStep 5: Start BGP
bgpd is stopped on this image, so start it on both switches:
supervisorctl start bgpdThen configure each side in vtysh. On sw1:
vtysh
configure terminal
router bgp 65001
no bgp ebgp-requires-policy
neighbor 10.0.0.1 remote-as 65002
endOn sw2, swap the numbers: router bgp 65002 and neighbor 10.0.0.0 remote-as 65001. Then:
vtysh -c 'show bgp summary'Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.0.1 4 65002 3 3 0 0 0 00:00:08 0 0 N/ASONiC FRR: configure BGP takes this to a leaf-spine fabric with ECMP and BFD.
What the image leaves out
docker-sonic-vs is built to test SONiC, so a few habits from a hardware switch do not carry over. Each of these came from the run above:
| You try | You get | Do this instead |
|---|---|---|
sudo config ... | sudo: command not found | Drop sudo, you are root |
show ip interfaces | Traceback, No such file or directory: 'sudo' | ip -br addr |
show version | KeyError: 'debian_version' | cat /etc/sonic/sonic_version.yml |
show ip bgp summary | No such command 'bgp' | vtysh -c 'show bgp summary' |
show ip route | Unable to get summary from bgp | vtysh -c 'show ip route' |
vtysh -c 'show bgp summary' on a fresh node | bgpd is not running | supervisorctl start bgpd |
Saving config, and what happens next
Save has two halves, and both work:
config save -y
vtysh -c writeKeep your expectations straight, though. docker restart is not a reboot here: the restarted node lost its links and its services did not come back, because containerlab starts them after deploy. containerlab destroy removes the containers and their files with them.
So keep config in files. The public BGP and EVPN labs bind a configs folder into each switch and run a script with exec, so one deploy gives you a configured fabric about 60 seconds later:
topology:
kinds:
sonic-vs:
image: docker-sonic-vs:latest
binds:
- configs:/configs:ro
nodes:
leaf1:
kind: sonic-vs
exec:
- bash /configs/leaf1.shThe script waits for its last port, then runs the same config and vtysh lines you typed above.
When you are done:
sudo containerlab destroy -t two-switches.clab.yml --cleanupWhen you would rather not run the host
Ask the NetPilot agent:
Build two SONiC switches connected by one link, with eBGP between them, and show me the neighbor state.
The image is already on the lab VM, sudo, show version, show ip interfaces and show ip route work, BGP is running when the deploy returns, and you can open a terminal on either switch to check by hand.
FAQ
How do I run SONiC in containerlab?
Download docker-sonic-vs.gz from the SONiC build pipeline, load it with docker load, and use the sonic-vs kind in a topology file. Deploy returns in seconds, the switch needs about 30 more seconds to create its ports, and you get a root shell with docker exec.
What is the difference between sonic-vs and sonic-vm in containerlab?
sonic-vs is SONiC as a container, so it starts fast and uses about 150 MB of memory per node at idle. sonic-vm runs the SONiC VM image inside a vrnetlab wrapper. The containerlab docs give it about 1 minute to boot, admin:admin SSH login and startup-config support.
Why does sudo fail on docker-sonic-vs?
The image has no sudo binary, and you are already root. Run config and show directly. Some show commands shell out to sudo, so they print sudo: not found, and show ip interfaces fails outright. ip -br addr gives the same answer.
Does SONiC config survive a docker restart in containerlab?
No. In our test a restarted sonic-vs node lost its links and its services did not come back, because containerlab starts them after deploy. Keep config in files and apply it at deploy, as the public labs do with exec.
Next steps
- SONiC NOS lab online: the hosted route, built from a prompt
- SONiC FRR: configure BGP: a leaf-spine fabric with ECMP and failover
- SONiC architecture on a running switch: read the databases
- containerlab in the cloud: the engine, hosted for you
- Open source contributions: what the NetPilot team sends upstream