Internet services / B61
View on GitHubKubernetes Cluster Deployment
Overview
This example introduces a Kubernetes compiler that converts a mini Internet topology into Kubernetes resource manifests and image build configurations, then deploys it to a K3s cluster using the accompanying tools. It provides deployment configurations based on local virtual machines, existing physical nodes, and multiple virtualization hosts, helping you understand the workflow from scenario compilation and infrastructure preparation to workload execution. You can further adjust the topology scale and deployment layout to evaluate resource usage, network connectivity, and runtime behavior across multiple nodes. It is particularly suited to large-scale network emulation on a single machine and distributed emulation across multiple machines.
B61 Native Kubernetes Example
This example compiles a SeedEMU mini-Internet topology to native Kubernetes
manifests and deploys it with seedemu.k8sTools. Kube-OVN/OVS is used as the
secondary network fabric for SeedEMU simulated networks. k8sTools.py keeps
this example directory small by copying setup/running resources into temporary
directories while commands run.
Files
| Path | Role |
|---|---|
mini_internet_k8s.py |
Compiles the SeedEMU topology into ./output by default. |
k8sTools.py |
Local CLI wrapper around seedemu.k8sTools.K8sTools. |
configKvmOvn.yaml |
Full local KVM + K3s + Kube-OVN example. |
configKvmOvnSimply.yaml |
Minimal local KVM template; it is the simplest form of configKvmOvn.yaml. |
configK3sOvn.yaml |
Existing physical nodes + K3s + Kube-OVN example. |
configMultiHostKvmOvn.yaml |
Multi-hypervisor KVM + K3s + Kube-OVN example. |
output/ |
Generated compiler output: manifests, images.yaml, and Docker build contexts. |
configK3s.yaml |
Generated by k8sTools.py build; consumed by up and destroy. |
kubeconfig.yaml |
Generated by k8sTools.py build; consumed by up, down, and kubectl. |
Compile
Run this once before deploying any of the four YAML examples:
cd examples/internet/b61_k8s_compile
python3 ./mini_internet_k8s.py
The default output directory is ./output. To write elsewhere:
python3 ./mini_internet_k8s.py --output-dir /tmp/seedemu-b61-output
To compile macvlan manifests instead of the default Kube-OVN/OVS manifests:
python3 ./mini_internet_k8s.py --cni-type macvlan
The default compiler mode writes k8s.kube-ovn.yaml, images.yaml, and one
Docker build context per compiled SeedEMU node. --cni-type macvlan writes
k8s.yaml with macvlan NetworkAttachmentDefinitions. k8sTools.py up also
accepts images.txt metadata when present. The default namespace is seedemu.
Common Deploy Commands
Every setup mode follows the same command shape:
python3 ./k8sTools.py build \
--input <one-config-yaml> \
--config-k3s configK3s.yaml \
--kubeconfig kubeconfig.yaml \
--inventory inventory.yaml
python3 ./k8sTools.py up -f ./output -k kubeconfig.yaml -d configK3s.yaml
python3 ./k8sTools.py clean -f ./output -k kubeconfig.yaml
python3 ./k8sTools.py destroy -d configK3s.yaml
build creates or prepares infrastructure and writes configK3s.yaml,
kubeconfig.yaml, and inventory.yaml. up builds/pushes workload images and
applies the SeedEMU namespace. clean removes only the workload namespace.
destroy removes the K3s/OVN setup and any KVM infrastructure recorded in
configK3s.yaml.
Add --keep-temp to any k8sTools.py command when you need to inspect its
temporary setup/running directory after a failure.
YAML Choices
configKvmOvnSimply.yaml
Use this when you want the shortest local KVM configuration.
python3 ./k8sTools.py build \
--input configKvmOvnSimply.yaml \
--config-k3s configK3s.yaml \
--kubeconfig kubeconfig.yaml \
--inventory inventory.yaml
This file is a minimal template for kind: kvmOvn. It only specifies the
cluster name, master/worker resources, worker count, and SSH user/key. The
k8sTools layer fills the normal KVM defaults such as VM names, IP/MAC planning,
registry port, Kube-OVN fabric, output paths, and K3s defaults. Treat it as the
starting point for a new local KVM experiment.
configKvmOvn.yaml
Use this for a more explicit local KVM deployment.
python3 ./k8sTools.py build \
--input configKvmOvn.yaml \
--config-k3s configK3s.yaml \
--kubeconfig kubeconfig.yaml \
--inventory inventory.yaml
Compared with configKvmOvnSimply.yaml, this file pins VM names, IP ranges,
MAC ranges, registry port, and fabric.type: ovn. It also disables the legacy
single base-image path with kvm.legacyBaseImagePath: "". This is the safer
choice when the same libvirt host may already contain other SeedEMU/K3s VMs
and you want predictable naming.
configK3sOvn.yaml
Use this when Kubernetes should be built on existing physical machines.
python3 ./k8sTools.py build \
--input configK3sOvn.yaml \
--config-k3s configK3s.yaml \
--kubeconfig kubeconfig.yaml \
--inventory inventory.yaml
Each nodes[] entry describes a real machine: name, role, management ip,
optional connection, and ssh.user/key. A node with connection: local runs
setup commands locally; other nodes are reached by SSH. Edit the IPs, users,
and keys before running this on another lab.
This path can install or reinstall K3s on the listed machines. Confirm SSH
key-based login and sudo -n true on every node first.
configMultiHostKvmOvn.yaml
Use this when multiple physical machines should act as KVM hypervisors for one K3s cluster.
python3 ./k8sTools.py build \
--input configMultiHostKvmOvn.yaml \
--config-k3s configK3s.yaml \
--kubeconfig kubeconfig.yaml \
--inventory inventory.yaml
The hypervisors[] section describes each physical KVM host. Each hypervisor
gets its own routed libvirt subnet through routedSubnet, and vmCount
controls how many K3s VMs are created there. vmSsh is the SSH account/key
injected into those guest VMs. master.placement selects which hypervisor owns
the K3s master. multiHostKvm.routingTunnel can create VXLAN next hops between
hypervisors when the underlay does not provide a direct L2 route.
This mode modifies every listed hypervisor: it may create libvirt networks, routes, optional VXLAN interfaces, VM disks, cloud-init data, and K3s nodes.
Prerequisites
All modes require Python 3.10+, Docker/buildx, kubectl, ansible-playbook,
ssh, scp, and curl.
The KVM modes also require libvirt/KVM tools such as virsh, virt-install,
qemu-img, and a working libvirt network. The physical-node and multi-host
flows require SSH key authentication and non-interactive sudo on all remote
machines.
Generate a dedicated SSH key if needed:
ssh-keygen -t ed25519 -f ~/.ssh/seedemu_k8s -C "seedemu-k8s"
chmod 600 ~/.ssh/seedemu_k8s
ssh-keygen -y -f ~/.ssh/seedemu_k8s > ~/.ssh/seedemu_k8s.pub
Then update the selected YAML:
ssh:
user: ubuntu
key: ~/.ssh/seedemu_k8s
For physical machines, install the public key and verify sudo:
ssh-copy-id -i ~/.ssh/seedemu_k8s.pub seed@192.0.2.11
ssh -i ~/.ssh/seedemu_k8s seed@192.0.2.11 'sudo -n true'
Runtime Notes
k8sTools.py upinfers the logical compiler image prefix fromoutput/images.yamloroutput/images.txt; use--image-registry-prefixonly for custom outputs.- During
up, generated DockerfileFROMimages such ashandsonsecurity/seedemu-base:2.0andhandsonsecurity/seedemu-router:2.0are prepared on the local host first and then loaded into the registry/master Docker daemon before remote buildx runs. k8sTools.py cleankeeps the cluster infrastructure and only removes the deployed SeedEMU workload.k8sTools.py destroyuses metadata embedded in generatedconfigK3s.yaml; do not delete that file before cleanup.- Real
build,up,down, anddestroycommands modify local or remote infrastructure. The compile step alone is non-destructive.
Quick Kubernetes Debug Commands
Run these commands from this directory. Use the local stable kubeconfig
explicitly so a stale KUBECONFIG from another experiment is not used by
mistake:
export B61_NS=seedemu
export B61_KUBECONFIG=./examples/internet/b61_k8s_compile/kubeconfig.yaml
Check namespace, nodes, and pod status:
kubectl --kubeconfig "${B61_KUBECONFIG}" get ns
kubectl --kubeconfig "${B61_KUBECONFIG}" get namespace "${B61_NS}"
kubectl --kubeconfig "${B61_KUBECONFIG}" get nodes -o wide
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" get pods -o wide
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" get pods -l seedemu.io/role=brd -o wide
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" get deploy -o wide
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" get events --sort-by='.lastTimestamp'
Inspect or enter one pod/deployment. Replace the object name with a real name
from kubectl get pods or kubectl get deploy:
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" describe pod <pod-name>
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" logs <pod-name> --tail=80
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" exec -it <pod-name> -- bash
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" exec -it deploy/<deploy-name> -- sh
kubectl --kubeconfig "${B61_KUBECONFIG}" -n "${B61_NS}" exec deploy/<deploy-name> -- birdc show protocols
as1862brd-r13-1.13.7.70-7564dbb49c-9wctj
Large post-BIRD runs can intermittently return TLS handshake timeout,
Client.Timeout exceeded, or http2: client connection lost while VM CPUs are
saturated. First retry the same command with an explicit request timeout:
kubectl --kubeconfig "${B61_KUBECONFIG}" --request-timeout=120s -n "${B61_NS}" get pods -l seedemu.io/role=brd -o wide
Source: SEED Emulator · B61 README