A learning-focused Kubernetes Container Network Interface (CNI) plugin built from scratch to understand how container networking really works.
Cube CNI is an educational project designed to demystify Kubernetes networking by implementing a fully functional CNI plugin from the ground up. This isn't just another CNI pluginβit's a learning platform with extensive logging, clear code structure, and comprehensive documentation to help you understand:
- π How Kubernetes networking actually works under the hood
- π How pods get IP addresses and communicate
- π§ How CNI plugins integrate with Kubernetes
- π¦ How to build production-grade Go projects with Bazel
- π§ͺ How to test network components with property-based testing
Perfect for platform engineers, SREs, and anyone curious about Kubernetes internals!
- Extensive Logging: Every operation is logged with context for easy debugging
- Clear Code Structure: Well-organized packages with single responsibilities
- Comprehensive Documentation: Detailed docs explaining every component
- Property-Based Testing: Learn advanced testing techniques
- Bridge-Based Networking: Simple but effective pod-to-pod communication
- IPAM (IP Address Management): Automatic IP allocation and tracking
- Node Label-Based Subnets: Flexible per-node subnet configuration
- CNI Spec Compliance: Implements CNI specification 0.4.0+
- Kubernetes Integration: DaemonSet deployment with RBAC
- Go 1.21+: Modern, efficient, and easy to understand
- Bazel Build System: Fast, reproducible builds
- Container Images: OCI-compliant images ready for deployment
- Cross-Platform Development: Build on macOS, deploy to Linux
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Kubernetes Node β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Host Network Namespace β β
β β β β
β β βββββββββββββββββββββββββββββββ β β
β β β Linux Bridge (cni0) β β β
β β β IP: 10.244.0.1/24 β β β
β β ββββββββββββ¬βββββββββββββββββββ β β
β β β β β
β β ββββββββββββΌβββββββββββ¬βββββββββββ β β
β β β β β β β β
β β veth-a veth-b veth-c veth-d β β
β ββββββββββΌβββββββββββΌβββββββββββΌβββββββββββΌββββββββββββ β
β β β β β β
β ββββββββββΌβββββββ βββΌβββββββ βββΌβββββββ βββΌβββββββ β
β β Pod 1 β β β Pod 2 β β Pod 3 β β Pod 4 β β
β β ββββββββΌβββββ β β ββββββββΌββ β ββββββββΌββ β ββββββββΌβ β β
β β β eth0 β β β β eth0 ββ β β eth0 ββ β β eth0 β β β
β β β10.244.0.2 β β β β.0.3 ββ β β.0.4 ββ β β.0.5 β β β
β β βββββββββββββ β β ββββββββββ β ββββββββββ β βββββββββ β β
β βββββββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
cube-cni-plugin/
βββ cmd/cni-plugin/ # Main CNI plugin binary
β βββ main.go # Entry point, command routing
βββ pkg/
β βββ ipam/ # IP Address Management
β β βββ allocator.go # IP allocation and persistence
β βββ logging/ # Structured logging
β β βββ logger.go # File-based logger
β βββ netns/ # Network namespace management
β β βββ manager.go # Namespace operations
β βββ network/ # Network configuration
β β βββ bridge.go # Linux bridge management
β β βββ veth.go # Veth pair management
β β βββ configurator.go # Orchestrates network setup
β βββ plugin/ # CNI command handlers
β β βββ handlers.go # ADD, DEL, CHECK, VERSION
β βββ types/ # Data models
β βββ types.go # CNI configuration structures
βββ deploy/ # Kubernetes manifests
βββ daemonset.yaml # DaemonSet with RBAC
βββ configmap.yaml # CNI configuration
βββ install.sh # Installation script
- Kubernetes Cluster: Local (kind, minikube) or remote
- kubectl: Configured to access your cluster
- Bazel: For building (or use pre-built images)
- Go 1.21+: For development
# Clone the repository
git clone https://github.com/cube-k8s/cube-cni-plugin.git
cd cube-cni-plugin
# Install to your cluster
./deploy/install.sh
# Verify installation
kubectl get pods -n kube-system -l app=cube-cni-plugin
kubectl logs -n kube-system -l app=cube-cni-plugin -c install-cni-config# Build everything
./scripts/build.sh all
# Install to cluster
./deploy/install.sh# Create test pods
kubectl run test1 --image=busybox -- sleep 3600
kubectl run test2 --image=busybox -- sleep 3600
# Check pod IPs
kubectl get pods -o wide
# Test connectivity
kubectl exec test1 -- ping -c 3 $(kubectl get pod test2 -o jsonpath='{.status.podIP}')Read the Requirements β .kiro/specs/kubernetes-cni-plugin/requirements.md
- Understand what a CNI plugin must do
- Learn about CNI specification compliance
Explore the Design β .kiro/specs/kubernetes-cni-plugin/design.md
- See how components fit together
- Understand the architecture decisions
Start with the Entry Point β cmd/cni-plugin/main.go
// See how CNI commands are parsed and routed
func main() {
// Parse CNI environment variables
env := parseCNIEnv()
// Route to appropriate handler
switch env.Command {
case "ADD": handleAdd()
case "DEL": handleDel()
case "CHECK": handleCheck()
case "VERSION": handleVersion()
}
}Follow the ADD Flow β pkg/plugin/handlers.go
// See how a pod gets networking
func HandleAdd(config, env) {
1. Allocate IP address (IPAM)
2. Create Linux bridge
3. Create veth pair
4. Move veth to pod namespace
5. Configure IP and routes
6. Return result to Kubernetes
}Understand IPAM β pkg/ipam/allocator.go
// See how IPs are allocated and tracked
func (ia *IPAllocator) AllocateIP(containerID) {
- Find next available IP in subnet
- Mark as allocated
- Persist to disk
- Return IP to caller
}Try Node-Specific Subnets β docs/NODE_LABEL_SUBNETS.md
# Assign different subnets to different nodes
kubectl label node worker-1 cni.cube.io/pod-cidr=10.244.1.0/24
kubectl label node worker-2 cni.cube.io/pod-cidr=10.244.2.0/24
# Restart CNI pods to apply
kubectl delete pod -n kube-system -l app=cube-cni-pluginWatch the Logs
# See every operation in detail
kubectl logs -n kube-system -l app=cube-cni-plugin -c install-cni-config
# Check CNI plugin logs on nodes
kubectl exec -n kube-system -l app=cube-cni-plugin -- cat /var/log/cni/plugin.logProperty-Based Testing β pkg/ipam/allocator_test.go
// Learn advanced testing techniques
Property: "All allocated IPs must be within subnet"
Property: "No two containers get the same IP"
Property: "Allocation persists across restarts"Run Tests Yourself
./scripts/build.sh testA CNI (Container Network Interface) plugin is a program that Kubernetes calls to:
- ADD: Set up networking when a pod starts
- DEL: Clean up networking when a pod stops
- CHECK: Verify networking is still working
- VERSION: Report supported CNI versions
1. Kubernetes creates a pod
2. Kubelet calls CNI plugin with ADD command
3. CNI plugin:
- Allocates an IP address
- Creates a veth pair (virtual ethernet cable)
- Connects one end to a bridge
- Moves other end into pod's network namespace
- Configures IP address and routes
4. Pod can now communicate!
A network namespace is like a separate network stack:
- Each pod gets its own namespace
- Isolated from other pods and the host
- Has its own interfaces, IPs, and routes
- Connected to host via veth pairs
A Linux bridge is like a virtual network switch:
- All pods on a node connect to it
- Forwards packets between pods
- Enables pod-to-pod communication
- Simple but effective for learning
Assign different IP subnets to different nodes:
# Small nodes get /25 (126 IPs)
kubectl label node small-worker cni.cube.io/pod-cidr=10.244.1.0/25
# Large nodes get /23 (510 IPs)
kubectl label node large-worker cni.cube.io/pod-cidr=10.244.2.0/23
# Unlabeled nodes use default: 10.244.0.0/16How it works:
- DaemonSet init container reads node labels
- Generates CNI config with appropriate subnet
- Writes config to
/etc/cni/net.d/ - CNI plugin uses that subnet for IP allocation
See docs/NODE_LABEL_SUBNETS.md for details.
Every operation is logged for learning and debugging:
=== CNI Configuration Generator ===
Node: worker-1
Querying node labels...
β Using subnet from label: 10.244.1.0/24
β CIDR validation passed
Generating CNI configuration...
β CNI configuration generated successfully
[INFO] CNI ADD command received
[INFO] Container ID: abc123
[INFO] Network namespace: /var/run/netns/pod-ns
[INFO] Allocating IP address...
[INFO] Allocated IP: 10.244.1.5/24
[INFO] Creating bridge: cni0
[INFO] Bridge already exists, skipping creation
[INFO] Creating veth pair: veth-abc123 <-> eth0
[INFO] Moving veth to namespace...
[INFO] Configuring IP address...
[INFO] Adding default route...
[INFO] Network setup complete!
Learn advanced testing with properties that must hold for all inputs:
// Property: All allocated IPs must be within subnet
Property("IP within subnet", func(subnet string) bool {
allocator := NewIPAllocator(subnet)
ip := allocator.AllocateIP("container-123")
return subnet.Contains(ip)
})
// Property: No duplicate IPs
Property("Unique IPs", func(containerIDs []string) bool {
allocator := NewIPAllocator("10.244.0.0/24")
ips := make(map[string]bool)
for _, id := range containerIDs {
ip := allocator.AllocateIP(id)
if ips[ip] {
return false // Duplicate found!
}
ips[ip] = true
}
return true
})# Build binary for Linux
./scripts/build.sh binary
# Build container image
./scripts/build.sh image
# Run tests
./scripts/build.sh test
# Build everything
./scripts/build.sh allSee BUILD_INSTRUCTIONS.md for detailed build documentation.
cube-cni-plugin/
βββ .kiro/specs/ # Design specifications
β βββ kubernetes-cni-plugin/
β βββ requirements.md # What the plugin must do
β βββ design.md # How it's designed
β βββ tasks.md # Implementation tasks
βββ cmd/ # Binaries
β βββ cni-plugin/ # Main CNI plugin
βββ pkg/ # Libraries
β βββ ipam/ # IP address management
β βββ logging/ # Logging infrastructure
β βββ netns/ # Network namespace ops
β βββ network/ # Network configuration
β βββ plugin/ # CNI handlers
β βββ types/ # Data models
βββ deploy/ # Kubernetes manifests
β βββ daemonset.yaml # DaemonSet + RBAC
β βββ configmap.yaml # CNI configuration
β βββ install.sh # Installation script
β βββ uninstall.sh # Cleanup script
βββ docs/ # Documentation
β βββ NODE_LABEL_SUBNETS.md
β βββ CONTAINER_IMAGE.md
β βββ TESTING_NODE_LABELS.md
βββ scripts/ # Build scripts
β βββ build.sh # Main build script
βββ MODULE.bazel # Bazel dependencies
βββ go.mod # Go dependencies
βββ README.md # This file!
- Update Requirements β
.kiro/specs/kubernetes-cni-plugin/requirements.md - Update Design β
.kiro/specs/kubernetes-cni-plugin/design.md - Add Tasks β
.kiro/specs/kubernetes-cni-plugin/tasks.md - Implement β Write code in
pkg/orcmd/ - Test β Add tests, run
./scripts/build.sh test - Document β Update relevant docs
# All tests
./scripts/build.sh test
# Specific test
bazel test --config=macos //pkg/ipam:ipam_test
# With coverage
bazel coverage --config=macos //pkg/...- Quick Start Guide - Get up and running quickly
- Requirements - What the plugin must do
- Design - Architecture and components
- Build Instructions - How to build and test
- Node Label Subnets - Per-node subnet configuration
- Cross-Node Routing - How pods communicate across nodes
- Container Image - Image build and deployment
- Testing Guide - Testing node label features
- Troubleshooting - Common issues and solutions
After working with this project, you'll understand:
β
CNI Specification: How CNI plugins integrate with Kubernetes
β
Network Namespaces: How Linux isolates network stacks
β
Veth Pairs: How virtual ethernet cables connect namespaces
β
Linux Bridges: How virtual switches enable pod communication
β
IPAM: How IP addresses are allocated and tracked
β
Kubernetes Networking: How pods get IPs and communicate
β
DaemonSets: How to deploy node-level components
β
RBAC: How to secure Kubernetes service accounts
β
Bazel: How to build reproducible Go projects
β
Property-Based Testing: Advanced testing techniques
This is a learning project! Contributions that improve clarity, add documentation, or enhance the learning experience are welcome.
- π More detailed code comments
- π Additional documentation or tutorials
- π§ͺ More test cases with explanations
- π¨ Diagrams explaining concepts
- π Bug fixes with learning notes
- β¨ New features with educational value
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests and documentation
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Check CNI plugin is running
kubectl get pods -n kube-system -l app=cube-cni-plugin
# Check logs
kubectl logs -n kube-system -l app=cube-cni-plugin -c install-cni-config
# Check CNI config on node
kubectl exec -n kube-system -l app=cube-cni-plugin -- cat /host/etc/cni/net.d/10-cube-cni.conflist# Check bridge exists
kubectl exec -n kube-system -l app=cube-cni-plugin -- ip link show cni0
# Check IP allocation
kubectl exec -n kube-system -l app=cube-cni-plugin -- cat /var/lib/cni/networks/cube-cni/allocations.json
# Check routes
kubectl exec test1 -- ip route# Clean and rebuild
./scripts/build.sh clean
./scripts/build.sh all
# Check dependencies
go mod tidy
bazel mod tidySee BUILD_INSTRUCTIONS.md for more troubleshooting.
This project is licensed under the MIT License - see the LICENSE file for details.
- CNI Project: For the excellent specification and reference implementations
- Kubernetes Community: For comprehensive networking documentation
- Bazel Team: For the amazing build system
- Go Community: For the fantastic language and ecosystem
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Project Wiki
Built with β€οΈ for learning Kubernetes networking
β Star this repo if it helped you learn something new!