Setting up Kind Cluster Using Calico as CNI¶
This guide provides a complete workflow to replace Flannel (the default CNI in Kind) with Calico in a Kind cluster, based on the provided kind-cluster-config.yaml. It covers configuration updates, Calico installation, and verification, with explanations of key concepts like --cluster-cidr. The setup assumes an IPv4-only cluster (IPv6DualStack: false) but includes notes for dual-stack if needed.
1. Why Use Calico Instead of Flannel?¶
Calico offers advanced features compared to Flannel, making it suitable for specific use cases:
- Network Policies: Calico supports Kubernetes
NetworkPolicyresources for fine-grained control over pod-to-pod communication, enhancing security. - BGP Support: Calico supports Border Gateway Protocol (BGP) for advanced routing, useful in hybrid or multi-cluster setups.
- Dual-Stack Networking: Calico fully supports IPv4/IPv6 dual-stack networking, though this guide focuses on IPv4-only.
- Flexibility: Calico is highly configurable, supporting various environments and networking requirements.
Flannel vs. Calico Comparison:
| Feature | Flannel | Calico |
|---|---|---|
| Ease of Use | Simple, lightweight, default | Requires manual installation |
| Network Policies | Not supported | Fully supported |
| Performance | Minimal overhead | Slightly higher due to features |
| IPv6 Support | Limited | Full dual-stack support |
| BGP Support | Not supported | Supported |
| Use Case | Simple clusters, testing | Security-focused, complex setups |
Rationale for Calico: - The kind-cluster-config.yaml is designed for a local development or testing cluster named ibtisam with a single control-plane and worker node. Switching to Calico allows you to leverage network policies and prepare for potential future needs (e.g., security, advanced networking), while maintaining compatibility with your existing setup.
2. Understanding Key Concepts¶
Before proceeding, let’s clarify critical terms:
- CNI (Container Network Interface):
-
The CNI is responsible for setting up pod networking in Kubernetes, assigning IP addresses to pods and enabling communication between them. Flannel is Kind’s default CNI, but you’re replacing it with Calico.
-
podSubnet:
-
The
podSubnetinkind-cluster-config.yaml(e.g.,10.244.0.0/16) defines the IP range for pod IPs. It’s equivalent to the--cluster-cidrparameter in Kubernetes, used by the CNI and Kubernetes components to manage pod networking. -
--cluster-cidr:
- This is the Kubernetes configuration parameter that specifies the CIDR range for pod IPs. In Kind, it’s set via the
podSubnetfield (e.g.,10.244.0.0/16). The CNI (Calico) must use a CIDR that matches or falls within this range to assign valid pod IPs. -
Example: Your
podSubnet: "10.244.0.0/16"sets--cluster-cidrto10.244.0.0/16. -
serviceSubnet:
-
The
serviceSubnet(e.g.,10.96.0.0/12) defines the IP range for Kubernetes service IPs, used for cluster-internal load balancing. It’s separate frompodSubnetand doesn’t directly affect Calico configuration. -
IPv6DualStack:
-
When enabled (
IPv6DualStack: true), the cluster supports both IPv4 and IPv6 for pods and services. Since you’ve chosenIPv6DualStack: false, the cluster will be IPv4-only, simplifying Calico’s configuration. -
CALICO_IPV4POOL_CIDR:
- This setting in the Calico manifest specifies the IPv4 CIDR from which Calico assigns pod IPs. It must match the
podSubnet(e.g.,10.244.0.0/16) to ensure proper networking.
3. Prerequisites¶
- Kind Installed: Ensure Kind is installed on your system (
kind --version). - kubectl Installed: Verify
kubectlis installed and configured (kubectl version --client). - Docker Running: Kind uses Docker to run cluster nodes, so Docker must be active (
docker info). - Sufficient Resources: Ensure your host has adequate resources (e.g., 8GB RAM, 4 CPUs, 20GB disk) for a small cluster with one control-plane and one worker node.
4. Update kind-cluster-config.yaml¶
The original kind-cluster-config.yaml needs minor changes to disable Flannel, set IPv4-only mode, and ensure compatibility with Calico. Below is the updated configuration with only the necessary changes highlighted.
Updated kind-cluster-config.yaml¶
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: ibtisam
nodes:
- role: control-plane
image: kindest/node:v1.32.3
extraPortMappings:
- containerPort: 30000
hostPort: 3000
protocol: TCP
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
name: control-plane-1
- role: worker
image: kindest/node:v1.32.3
kubeadmConfigPatches:
- |
kind: JoinConfiguration
nodeRegistration:
name: worker-1
networking:
disableDefaultCNI: true # Changed: Disable Flannel to use Calico
podSubnet: "10.244.0.0/16" # Unchanged: IPv4 pod subnet
serviceSubnet: "10.96.0.0/12" # Unchanged
apiServerAddress: "127.0.0.1" # Unchanged
apiServerPort: 6443 # Unchanged
kubeadmConfigPatches:
- |
kind: ClusterConfiguration
apiServer:
extraArgs:
authorization-mode: Node,RBAC
containerdConfigPatches:
- |
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "overlayfs"
Key Changes¶
- disableDefaultCNI: true:
- Disables Flannel, preventing Kind from installing the default CNI. This allows you to manually install Calico after cluster creation.
-
Without a CNI, pods (e.g.,
coredns) will be in aPendingstate until Calico is applied. -
IPv6DualStack: false:
-
Disables dual-stack networking, configuring the cluster for IPv4-only. This simplifies Calico’s configuration, as you won’t need an IPv6 pool.
-
podSubnet: "10.244.0.0/16":
-
Retained as is, as it’s a standard, conflict-free range for pod IPs. This matches the
--cluster-cidrand will be used by Calico. -
Other Settings:
- The
serviceSubnet, node configurations, port mappings, RBAC, andoverlayfssettings remain unchanged, as they don’t directly affect the CNI switch.
Why Keep podSubnet: "10.244.0.0/16"?¶
- Avoid Conflicts: The
10.244.0.0/16range is unlikely to overlap with local networks (unlike Calico’s default192.168.0.0/16, which may conflict with home routers or Docker). - Standard Practice: It’s a common default for Kubernetes clusters (used by Flannel, k3s, etc.), ensuring compatibility with tools and tutorials.
- No Cluster Recreation: Keeping the existing
podSubnetavoids the need to recreate the cluster or update workloads that rely on this range.
5. Configure the Calico Manifest¶
Calico’s manifest (calico.yaml) must be updated to align with your cluster’s podSubnet (10.244.0.0/16). Since IPv6DualStack is disabled, only the IPv4 pool needs configuration.
Steps to Update calico.yaml¶
- Download the Manifest:
- Get the latest Calico manifest compatible with Kubernetes v1.32.3 (use Calico v3.28 or newer as of April 2025):
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml -
Check the Calico documentation for the latest version.
-
Modify
CALICO_IPV4POOL_CIDR: - Open
calico.yamland locate thecalico-nodeDaemonSet configuration (search forCALICO_IPV4POOL_CIDR). Update it to:- name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16" - name: CALICO_DISABLE_FILE_LOGGING value: "true" - Changes:
- Replace the default
192.168.0.0/16(or uncomment the line if commented) with10.244.0.0/16to match thepodSubnet. - Keep
CALICO_DISABLE_FILE_LOGGING: "true"to ensure logs are accessible viakubectl logs.
- Replace the default
-
No IPv6 Configuration:
- Since
IPv6DualStack: false, do not addCALICO_IPV6POOL_CIDRor any IPv6 settings. Calico will operate in IPv4-only mode.
- Since
-
Optional: Explicitly Disable IPv6:
- To ensure Calico doesn’t attempt IPv6, you can add: This is usually unnecessary, as
- name: IP value: "autodetect" - name: IP6 value: "none"IPv6DualStack: falsealready configures the cluster for IPv4-only.
Why Modify calico.yaml Instead of podSubnet?¶
- Alignment with Cluster: The
CALICO_IPV4POOL_CIDRmust match thepodSubnet(10.244.0.0/16), which is the--cluster-cidr. A mismatch causes pods to receive invalid IPs, breaking networking. - Avoid Conflicts: Calico’s default
192.168.0.0/16may conflict with local networks (e.g., home routers, Docker). Using10.244.0.0/16is safer. - Simpler Change: Editing
calico.yamlis a localized change that doesn’t require recreating the cluster, unlike changingpodSubnet. - Best Practice: Kubernetes clusters commonly use
10.244.0.0/16, and Calico’s manifest is designed to be customized to match the cluster’s--cluster-cidr.
6. Deploy the Cluster and Install Calico¶
Follow these steps to create the cluster and set up Calico:
- Save the Updated
kind-calico-cluster-config.yaml: -
Ensure the config includes
disableDefaultCNI: true,podSubnet: "10.244.0.0/16", andIPv6DualStack: falseas shown above. -
Create the Kind Cluster:
- Run:
kind create cluster --config kind-calico-cluster-config.yaml -
This creates the cluster named
ibtisamwithout a CNI. Pods likecorednswill be in aPendingstate until Calico is installed. -
Apply the Calico Manifest:
- Apply the modified
calico.yaml:kubectl apply -f calico.yaml - This deploys Calico’s components, including:
calico-nodeDaemonSet (runs on each node for networking).calico-kube-controllers(manages network policies and IP pools).
7. Verify the Setup¶
After applying Calico, verify that the cluster and networking are functioning correctly:
- Check Calico Pods:
- Ensure
calico-nodepods are running on all nodes:Expected output:kubectl get pods -n kube-system -l k8s-app=calico-nodeNAME READY STATUS RESTARTS AGE calico-node-xyz 1/1 Running 0 2m -
Verify
calico-kube-controllers:kubectl get pods -n kube-system -l k8s-app=calico-kube-controllers -
Verify System Pods:
-
Check that
corednsand other system pods are no longerPending:Expected output: All pods inkubectl get pods -n kube-systemRunningstate. -
Test Pod Networking:
-
Deploy a sample pod to verify IP assignment:
Expected output:kubectl run nginx --image=nginx --restart=Never kubectl get pods -o wideConfirm the IP is in theNAME READY STATUS RESTARTS AGE IP NODE nginx 1/1 Running 0 1m 10.244.0.5 worker-110.244.0.0/16range (e.g.,10.244.0.5). -
Test Connectivity:
-
Create a second pod to test pod-to-pod communication:
Inside the pod, ping thekubectl run test --image=busybox --restart=Never --rm -it -- /bin/shnginxpod’s IP (e.g.,10.244.0.5):Expected output: Successful pings.ping 10.244.0.5 -
Optional: Test Network Policies:
- Calico’s key feature is support for
NetworkPolicy. Create a sample policy to allow traffic to thenginxpod:Apply it:apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-nginx namespace: default spec: podSelector: matchLabels: run: nginx policyTypes: - Ingress ingress: - from: - podSelector: {}Test connectivity again to ensure the policy allows traffic.kubectl apply -f nginx-policy.yaml
8. Troubleshooting¶
If issues arise, use these steps to diagnose:
- Pods Stuck in
Pending: - Check Calico pod logs:
kubectl logs -n kube-system -l k8s-app=calico-node -
Verify the
calico-nodeDaemonSet:kubectl get ds -n kube-system -
Networking Issues:
- Confirm the IP pool matches
podSubnet:Expectedkubectl get ippool -o yamlcidr:10.244.0.0/16. -
Check for CIDR mismatches or conflicts with local networks.
-
Resource Constraints:
-
Ensure your host has sufficient CPU/memory (e.g., 8GB RAM, 4 CPUs). Calico is slightly more resource-intensive than Flannel.
-
Common Errors:
- IP assignment failure: Ensure
CALICO_IPV4POOL_CIDRis10.244.0.0/16incalico.yaml. - Calico pods not starting: Check for image pull issues or resource limits (
kubectl describe pod -n kube-system).
9. Considerations for IPv6DualStack¶
If you later decide to enable IPv6DualStack: true, you’ll need additional Calico configuration:
- Update Kind Config:
-
Set
featureGates: IPv6DualStack: trueinkind-cluster-config.yaml. -
Update Calico Manifest:
- Add an IPv6 pool:
- name: CALICO_IPV6POOL_CIDR value: "fd00:10:244::/48" -
Ensure
CALICO_IPV4POOL_CIDRremains10.244.0.0/16. -
Enable IPv6 in Docker:
- Update
/etc/docker/daemon.json:{ "ipv6": true, "fixed-cidr-v6": "fd00::/80" } -
Restart Docker:
sudo systemctl restart docker -
Verify Dual-Stack:
- Pods should receive both IPv4 (e.g.,
10.244.0.5) and IPv6 (e.g.,fd00:10:244::5) addresses.
Since you’ve chosen IPv6DualStack: false, these steps are unnecessary for now.
10. Why Modify Calico Manifest Instead of podSubnet?¶
You might wonder why we update CALICO_IPV4POOL_CIDR in calico.yaml to match podSubnet: "10.244.0.0/16" instead of changing podSubnet to Calico’s default 192.168.0.0/16. Here’s why:
- Avoid Network Conflicts:
192.168.0.0/16is a common private IP range used by home routers, VPNs, or Docker’s bridge network. Using it risks IP conflicts, causing pods to be unreachable or misrouted.-
10.244.0.0/16is a safer, Kubernetes-standard range unlikely to overlap with local networks. -
No Cluster Recreation:
- Changing
podSubnetrequires deleting and recreating the cluster:kind delete cluster --name ibtisam kind create cluster --config kind-calico-cluster-config.yaml -
Editing
calico.yamlis less disruptive, as it doesn’t affect the cluster’s core configuration. -
Workload Compatibility:
-
Existing workloads or configurations (e.g.,
NetworkPolicy, service IPs) may rely on10.244.0.0/16. Changing to192.168.0.0/16would break these. -
Best Practice:
- Kubernetes clusters commonly use
10.244.0.0/16(e.g., Flannel’s default). Aligning Calico with this standard ensures compatibility with tools and tutorials. -
Calico’s manifest is designed to be customized, with
CALICO_IPV4POOL_CIDRexplicitly meant to match the cluster’s--cluster-cidr. -
Future Flexibility:
- Keeping
10.244.0.0/16allows easy switching to other CNIs (e.g., Flannel, Cilium) without changingpodSubnet.
11. Additional Notes¶
- Resource Usage:
-
Calico is slightly more resource-intensive than Flannel due to features like network policies and the Felix agent. Monitor your host’s resource usage, especially with multiple nodes.
-
Documentation:
-
Document changes to
calico.yaml(e.g., in aREADME) to clarify whyCALICO_IPV4POOL_CIDRis set to10.244.0.0/16. This helps team members or your future self. -
Version Compatibility:
-
Ensure Calico v3.28 (or newer) is compatible with Kubernetes v1.32.3. Check Calico release notes for details.
-
Scalability:
-
Your config includes commented-out nodes for additional control-plane and worker nodes. To enable them for high availability or increased capacity, uncomment the relevant sections and reapply the cluster configuration.
-
Network Policies:
- Leverage Calico’s
NetworkPolicysupport to enhance security. Start with simple policies (like theallow-nginxexample) and expand as needed.
12. Summary¶
To use Calico as the CNI in your Kind cluster: 1. Update kind-cluster-config.yaml: - Set disableDefaultCNI: true to disable Flannel. - Set IPv6DualStack: false for IPv4-only. - Keep podSubnet: "10.244.0.0/16" as the --cluster-cidr. 2. Modify calico.yaml: - Set CALICO_IPV4POOL_CIDR to 10.244.0.0/16. - Keep CALICO_DISABLE_FILE_LOGGING: "true". - No IPv6 settings needed. 3. Create the cluster: kind create cluster --config kind-calico-cluster-config.yaml. 4. Apply Calico: kubectl apply -f calico.yaml. 5. Verify Calico pods, system pods, and pod networking. 6. Optionally, test network policies to leverage Calico’s features.
ONE Command Solution¶
Just copy and paste the following commands into your terminal in order:
curl -sL https://raw.githubusercontent.com/ibtisam-iq/infra-bootstrap/main/k8s-kind-calico.sh | sudo bash
This setup ensures a robust, IPv4-only Kind cluster with Calico, supporting advanced networking features while maintaining compatibility with your existing configuration. The 10.244.0.0/16 range avoids conflicts, and modifying calico.yaml is less invasive than changing podSubnet.