Clabernetes: Running ContainerLab Topologies in Kubernetes
Clabernetes: Running ContainerLab Topologies in Kubernetes
clabernetes takes containerlab — the popular network topology emulation tool — and brings it into Kubernetes. Instead of running labs on a single host, topologies become Kubernetes resources managed by a custom operator.
Why Clabernetes
ContainerLab is excellent for spinning up network labs locally, but it’s tied to a single machine. Clabernetes lifts this constraint by:
- Distributing lab nodes across a Kubernetes cluster
- Using CRDs to declare topologies as native Kubernetes resources
- Enabling multi-user lab environments with namespace isolation
- Persisting lab state through Kubernetes mechanisms
Custom Resource Definition
A containerlab topology becomes a Topology CRD:
apiVersion: clabernetes.containerlab.dev/v1alpha1
kind: Topology
metadata:
name: srl-spine-leaf
namespace: network-labs
spec:
definition:
nodes:
spine1:
kind: srl
image: ghcr.io/nokia/srlinux:latest
spine2:
kind: srl
image: ghcr.io/nokia/srlinux:latest
leaf1:
kind: srl
image: ghcr.io/nokia/srlinux:latest
leaf2:
kind: srl
image: ghcr.io/nokia/srlinux:latest
links:
- endpoints: ["spine1:e1-1", "leaf1:e1-49"]
- endpoints: ["spine1:e1-2", "leaf2:e1-49"]
- endpoints: ["spine2:e1-1", "leaf1:e1-50"]
- endpoints: ["spine2:e1-2", "leaf2:e1-50"]Operator Architecture
The clabernetes operator watches Topology resources and reconciles the desired state:
func (r *TopologyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
topology := &clabernetesv1alpha1.Topology{}
if err := r.Get(ctx, req.NamespacedName, topology); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
if err := r.reconcileNodes(ctx, topology); err != nil {
return ctrl.Result{}, err
}
if err := r.reconcileLinks(ctx, topology); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{}, r.updateStatus(ctx, topology)
}
func (r *TopologyReconciler) reconcileNodes(ctx context.Context, topology *clabernetesv1alpha1.Topology) error {
for nodeName, nodeDef := range topology.Spec.Definition.Nodes {
pod := r.buildNodePod(topology, nodeName, nodeDef)
if err := r.applyPod(ctx, pod); err != nil {
return fmt.Errorf("reconciling node %s: %w", nodeName, err)
}
}
return nil
}Node Pod Generation
Each containerlab node becomes a Kubernetes Pod with appropriate privileges for network emulation:
func (r *TopologyReconciler) buildNodePod(
topology *clabernetesv1alpha1.Topology,
nodeName string,
node clabernetesv1alpha1.NodeDefinition,
) *corev1.Pod {
return &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", topology.Name, nodeName),
Namespace: topology.Namespace,
Labels: map[string]string{
"clabernetes/topology": topology.Name,
"clabernetes/node": nodeName,
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Name: nodeName,
Image: node.Image,
SecurityContext: &corev1.SecurityContext{
Privileged: boolPtr(true),
},
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("500m"),
corev1.ResourceMemory: resource.MustParse("512Mi"),
},
},
}},
},
}
}Virtual Link Management
Inter-node links are implemented as veth pairs between pods, wired up by the operator:
type LinkManager struct {
client client.Client
}
func (lm *LinkManager) CreateLink(ctx context.Context, link TopologyLink) error {
srcPod, err := lm.getPod(ctx, link.SrcNode)
if err != nil {
return err
}
dstPod, err := lm.getPod(ctx, link.DstNode)
if err != nil {
return err
}
return lm.createVethPair(ctx, srcPod, link.SrcInterface, dstPod, link.DstInterface)
}CLI Usage
# Install the operator
kubectl apply -f https://github.com/bayars/clabernetes/releases/latest/install.yaml
# Deploy a topology
kubectl apply -f spine-leaf.yaml
# Check status
kubectl get topology -n network-labs
# NAME NODES LINKS STATUS
# srl-spine-leaf 4 4 Running
# Access a node
kubectl exec -it -n network-labs srl-spine-leaf-spine1 -- sr_cliComparison with Standalone ContainerLab
| Feature | ContainerLab | Clabernetes |
|---|---|---|
| Scale | Single host | Multi-node cluster |
| Isolation | Process/network NS | Kubernetes namespaces |
| State management | Files | Kubernetes resources |
| Multi-user | Limited | Native via RBAC |
| Persistence | Manual | Kubernetes-native |
Conclusion
Clabernetes extends containerlab’s reach into Kubernetes, enabling scalable, multi-user network labs that are declared and managed as native cluster resources. It’s a powerful tool for anyone running SR Linux, SROS, or other containerized network operating systems at scale.
Source: GitHub