Thanks to visit codestin.com
Credit goes to github.com

Skip to content

cube-k8s/cube-cni-plugin

Repository files navigation

🧊 Cube CNI Plugin

A learning-focused Kubernetes Container Network Interface (CNI) plugin built from scratch to understand how container networking really works.

License: MIT Go Version Bazel


🎯 Project Purpose

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!


✨ Features

πŸŽ“ Learning-First Design

  • 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

πŸš€ Production-Ready Components

  • 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

πŸ› οΈ Modern Development Stack

  • 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

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     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   β”‚ β”‚ β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Component Overview

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

πŸš€ Quick Start

Prerequisites

  • 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

Option 1: Use Pre-Built Image (Fastest)

# 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

Option 2: Build from Source

# Build everything
./scripts/build.sh all

# Install to cluster
./deploy/install.sh

Verify It Works

# 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}')

πŸ“š Learning Path

1. Start with the Basics

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

2. Dive into the Code

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
}

3. Experiment with Features

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-plugin

Watch 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.log

4. Study the Tests

Property-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 test

πŸŽ“ Key Concepts Explained

What is a CNI Plugin?

A CNI (Container Network Interface) plugin is a program that Kubernetes calls to:

  1. ADD: Set up networking when a pod starts
  2. DEL: Clean up networking when a pod stops
  3. CHECK: Verify networking is still working
  4. VERSION: Report supported CNI versions

How Does Pod Networking Work?

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!

What is a Network Namespace?

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

What is a Linux Bridge?

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

πŸ”§ Advanced Features

Node Label-Based Subnet Allocation

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/16

How it works:

  1. DaemonSet init container reads node labels
  2. Generates CNI config with appropriate subnet
  3. Writes config to /etc/cni/net.d/
  4. CNI plugin uses that subnet for IP allocation

See docs/NODE_LABEL_SUBNETS.md for details.

Extensive Logging

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!

Property-Based Testing

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
})

πŸ› οΈ Development

Building

# 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 all

See BUILD_INSTRUCTIONS.md for detailed build documentation.

Project Structure

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!

Adding Features

  1. Update Requirements β†’ .kiro/specs/kubernetes-cni-plugin/requirements.md
  2. Update Design β†’ .kiro/specs/kubernetes-cni-plugin/design.md
  3. Add Tasks β†’ .kiro/specs/kubernetes-cni-plugin/tasks.md
  4. Implement β†’ Write code in pkg/ or cmd/
  5. Test β†’ Add tests, run ./scripts/build.sh test
  6. Document β†’ Update relevant docs

Running Tests

# All tests
./scripts/build.sh test

# Specific test
bazel test --config=macos //pkg/ipam:ipam_test

# With coverage
bazel coverage --config=macos //pkg/...

πŸ“– Documentation


🎯 Learning Objectives

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


🀝 Contributing

This is a learning project! Contributions that improve clarity, add documentation, or enhance the learning experience are welcome.

Ideas for Contributions

  • πŸ“ 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

How to Contribute

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests and documentation
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

πŸ” Troubleshooting

Pods Not Getting IPs

# 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

Pods Can't Communicate

# 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

Build Issues

# Clean and rebuild
./scripts/build.sh clean
./scripts/build.sh all

# Check dependencies
go mod tidy
bazel mod tidy

See BUILD_INSTRUCTIONS.md for more troubleshooting.


πŸ“œ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ™ Acknowledgments

  • 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

πŸ“¬ Contact & Support


πŸŽ“ Additional Resources

Learn More About CNI

Learn More About Kubernetes Networking

Learn More About Linux Networking


Built with ❀️ for learning Kubernetes networking

⭐ Star this repo if it helped you learn something new!

Report Bug Β· Request Feature Β· Documentation

About

Cube K8s CNI Plugin

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors