The Cube CNI plugin supports per-node subnet allocation through Kubernetes node labels. This allows you to assign different pod CIDR ranges to different nodes, enabling flexible network segmentation and IP address management.
When the CNI plugin DaemonSet starts on a node, the init container:
- Queries the node's labels for
cni.cube.io/pod-subnet - If the label exists, decodes its value by replacing
-with/to get CIDR notation - If the label doesn't exist, uses the default subnet from the ConfigMap (
10.244.0.0/16) - Validates the decoded CIDR format
- Generates the final CNI configuration file with the resolved subnet
- Writes the configuration to
/etc/cni/net.d/10-cube-cni.conflist
Label Key: cni.cube.io/pod-subnet
Label Value: A dash-encoded CIDR notation (e.g., 10.244.1.0-24)
Kubernetes label values have strict validation rules and cannot contain forward slashes (/). Since CIDR notation uses / (e.g., 10.244.1.0/24), we must encode the CIDR when storing it in a label.
Encoding Scheme:
- Replace
/with-(dash) when setting the label - The init container automatically decodes by replacing
-with/ - Example:
10.244.1.0/24→10.244.1.0-24(for label) →10.244.1.0/24(decoded)
Valid vs Invalid Examples:
✅ Correct - Dash-encoded format:
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24
kubectl label node worker-2 cni.cube.io/pod-subnet=10.244.2.0-25
kubectl label node worker-3 cni.cube.io/pod-subnet=10.244.3.0-26❌ INVALID - Contains forward slash (will be rejected by Kubernetes):
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0/24- Must be in valid dash-encoded format:
X.X.X.X-Y - After decoding, must be valid CIDR:
X.X.X.X/Y - Prefix length must be between
/1and/32 - Must not overlap with other node subnets (your responsibility to manage)
- Should be appropriately sized for the expected number of pods on the node
/24(254 usable IPs) - Standard nodes with moderate pod density/25(126 usable IPs) - Smaller nodes or controlled environments/26(62 usable IPs) - Minimal pod deployments/23(510 usable IPs) - Large nodes with high pod density
# Label a specific node with a custom subnet (dash-encoded)
kubectl label node <node-name> cni.cube.io/pod-subnet=10.244.1.0-24Example:
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24
kubectl label node worker-2 cni.cube.io/pod-subnet=10.244.2.0-24
kubectl label node worker-3 cni.cube.io/pod-subnet=10.244.3.0-24Encoding Examples:
# /24 subnet (254 usable IPs)
10.244.1.0/24 → 10.244.1.0-24
# /25 subnet (126 usable IPs)
10.244.2.0/25 → 10.244.2.0-25
# /26 subnet (62 usable IPs)
10.244.3.0/26 → 10.244.3.0-26
# /23 subnet (510 usable IPs)
10.244.4.0/23 → 10.244.4.0-23# Label all nodes matching a selector
kubectl label nodes -l node-role.kubernetes.io/worker cni.cube.io/pod-subnet=10.244.0.0-16# View all labels on a node
kubectl get node <node-name> --show-labels
# View only the pod-subnet label (encoded format)
kubectl get node <node-name> -o jsonpath='{.metadata.labels.cni\.cube\.io/pod-subnet}'
# View all node subnets in a table
kubectl get nodes -o custom-columns=NAME:.metadata.name,SUBNET:.metadata.labels.cni\\.cube\\.io/pod-subnet# Remove the pod-subnet label (node will use default subnet after restart)
kubectl label node <node-name> cni.cube.io/pod-subnet--
Before installation: Label nodes with desired subnets (optional, dash-encoded)
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24
-
Install CNI plugin: Run the installation script
./deploy/install.sh
-
Verify configuration: Check the generated config on each node
kubectl exec -n kube-system -l app=cube-cni-plugin -- cat /host/etc/cni/net.d/10-cube-cni.conflist
Important: Configuration is generated at DaemonSet pod startup. To apply label changes:
-
Update the node label (dash-encoded):
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.5.0-24 --overwrite
-
Restart the DaemonSet pod on that node:
# Delete the pod on the specific node (it will be recreated) kubectl delete pod -n kube-system -l app=cube-cni-plugin --field-selector spec.nodeName=worker-1 -
Verify the new configuration:
kubectl exec -n kube-system -l app=cube-cni-plugin --field-selector spec.nodeName=worker-1 -- cat /host/etc/cni/net.d/10-cube-cni.conflist -
Restart existing pods on that node to get IPs from the new subnet (optional but recommended)
# View the generated CNI config on a specific node
kubectl exec -n kube-system -l app=cube-cni-plugin --field-selector spec.nodeName=<node-name> -- cat /host/etc/cni/net.d/10-cube-cni.conflist# View logs from the config generation init container
kubectl logs -n kube-system -l app=cube-cni-plugin -c install-cni-configExpected output for labeled node:
=== CNI Configuration Generator ===
Node: worker-1
Querying node labels...
✓ Found encoded label value: 10.244.1.0-24
✓ Decoded to CIDR notation: 10.244.1.0/24
✓ Using subnet from label: 10.244.1.0/24
✓ CIDR validation passed
Generating CNI configuration...
✓ CNI configuration generated successfully
Expected output for unlabeled node:
=== CNI Configuration Generator ===
Node: worker-2
Querying node labels...
✓ No label found, using default subnet: 10.244.0.0/16
✓ CIDR validation passed
Generating CNI configuration...
✓ CNI configuration generated successfully
# Create test pods on specific nodes
kubectl run test-pod-1 --image=busybox --overrides='{"spec":{"nodeName":"worker-1"}}' -- sleep 3600
kubectl run test-pod-2 --image=busybox --overrides='{"spec":{"nodeName":"worker-2"}}' -- sleep 3600
# Check pod IPs (should be from the respective node's subnet)
kubectl get pods -o wideSymptom: Node label changed but pods still get IPs from old subnet
Solution: Restart the DaemonSet pod on that node
kubectl delete pod -n kube-system -l app=cube-cni-plugin --field-selector spec.nodeName=<node-name>Symptom: Init container fails with "Invalid CIDR format" or "Invalid encoded value" error
Check the label value:
kubectl get node <node-name> -o jsonpath='{.metadata.labels.cni\.cube\.io/pod-subnet}'Common mistakes:
# ❌ Wrong - using forward slash instead of dash
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0/24
# ✅ Correct - using dash encoding
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24
# ❌ Wrong - missing prefix length
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0
# ✅ Correct - includes prefix length
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24Fix: Ensure the label value is in valid dash-encoded format
kubectl label node <node-name> cni.cube.io/pod-subnet=10.244.1.0-24 --overwrite
kubectl delete pod -n kube-system -l app=cube-cni-plugin --field-selector spec.nodeName=<node-name>Validation command:
# Check if label is properly encoded (should contain dash, not slash)
LABEL=$(kubectl get node <node-name> -o jsonpath='{.metadata.labels.cni\.cube\.io/pod-subnet}')
if echo "$LABEL" | grep -q '/'; then
echo "ERROR: Label contains forward slash - use dash encoding"
else
echo "OK: Label is properly encoded"
fiSymptom: Init container fails with "forbidden" or permission errors
Check RBAC:
kubectl get clusterrole cube-cni-plugin -o yaml
kubectl get clusterrolebinding cube-cni-plugin -o yamlVerify the ServiceAccount has permissions:
kubectl auth can-i get nodes --as=system:serviceaccount:kube-system:cube-cni-plugin
kubectl auth can-i list nodes --as=system:serviceaccount:kube-system:cube-cni-pluginSymptom: /etc/cni/net.d/10-cube-cni.conflist doesn't exist on the node
Check init container logs:
kubectl logs -n kube-system -l app=cube-cni-plugin -c install-cni-configCheck volume mounts:
kubectl describe daemonset cube-cni-plugin -n kube-systemSymptom: Pods on different nodes have IP conflicts
Prevention: Plan your subnet allocation carefully
- Use non-overlapping CIDR ranges for each node
- Document your subnet allocation scheme
- Consider using a subnet calculator tool
Example allocation for 3 nodes:
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24 # 10.244.1.1 - 10.244.1.254
kubectl label node worker-2 cni.cube.io/pod-subnet=10.244.2.0-24 # 10.244.2.1 - 10.244.2.254
kubectl label node worker-3 cni.cube.io/pod-subnet=10.244.3.0-24 # 10.244.3.1 - 10.244.3.254-
Plan subnet allocation before deployment
- Document your subnet scheme
- Ensure no overlaps between node subnets
- Leave room for future node additions
-
Label nodes before installing CNI
- Avoids need to restart DaemonSet pods
- Ensures correct configuration from the start
-
Use consistent subnet sizing
- Makes management easier
- Simplifies troubleshooting
-
Monitor IP allocation
- Check
/var/lib/cni/networks/on nodes - Ensure subnets aren't exhausted
- Check
-
Document your allocation
- Keep a record of which subnets are assigned to which nodes
- Update documentation when making changes
# Assign /24 subnets to each node (dash-encoded)
kubectl label node control-plane cni.cube.io/pod-subnet=10.244.0.0-24
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.1.0-24
kubectl label node worker-2 cni.cube.io/pod-subnet=10.244.2.0-24
# Install CNI
./deploy/install.sh
# Verify
kubectl get nodes -o custom-columns=NAME:.metadata.name,SUBNET:.metadata.labels.cni\\.cube\\.io/pod-subnet# Large nodes get /23 (510 IPs) - dash-encoded
kubectl label node large-worker-1 cni.cube.io/pod-subnet=10.244.0.0-23
kubectl label node large-worker-2 cni.cube.io/pod-subnet=10.244.2.0-23
# Standard nodes get /24 (254 IPs) - dash-encoded
kubectl label node worker-1 cni.cube.io/pod-subnet=10.244.4.0-24
kubectl label node worker-2 cni.cube.io/pod-subnet=10.244.5.0-24
# Small nodes get /25 (126 IPs) - dash-encoded
kubectl label node small-worker-1 cni.cube.io/pod-subnet=10.244.6.0-25
kubectl label node small-worker-2 cni.cube.io/pod-subnet=10.244.6.128-25# Only label nodes that need custom subnets (dash-encoded)
kubectl label node special-worker-1 cni.cube.io/pod-subnet=10.244.100.0-24
kubectl label node special-worker-2 cni.cube.io/pod-subnet=10.244.101.0-24
# All other nodes will use the default: 10.244.0.0/16
# (Note: This may cause IP conflicts if not managed carefully)