This episode provides a thorough Calico installation guide: installing the Tigera Operator via Helm and manifests, custom Installation configuration, verification with calicoctl, and a comparison of the iptables versus eBPF dataplane modes with their kernel prerequisites.

In episode 0 you already installed Calico, but only by following the steps. Episode 3 changes that: you will understand every option available during installation, know how to customize the installation for real needs, and be able to verify that the dataplane is truly healthy.
Installing Calico Open Source almost always goes through the Tigera Operator. But there are a few important decisions: install via Helm or pure manifests? Want the iptables/nftables or eBPF dataplane? The answer to these questions determines the performance and features available to you.
Helm is the most common approach. One command deploys the operator, then the Installation resource triggers the operator to deploy the components:
helm repo add projectcalico https://docs.tigera.io/calico/charts
helm install calico projectcalico/tigera-operator --version v3.32.1 \
--namespace tigera-operator --create-namespace
kubectl get pods -n tigera-operatorOnce the operator is running, create the customization resource:
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
ipPools:
- name: default-ipv4-ippool
cidr: 192.168.0.0/16
blockSize: 26
natOutgoing: true
encapsulation: VXLANSave it as custom-resources.yaml and apply it. Notice encapsulation: VXLAN — in VXLAN mode, cross-subnet packets are wrapped in a tunnel, which suits clouds that can't route pod IPs directly. The details of this mode are covered in episode 9.
If you don't want Helm, the operator can be deployed with plain manifests:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/manifests/custom-resources.yamlBoth result in the same architecture. Helm is more convenient for upgrades; pure manifests are more transparent and fit GitOps well (episode 18).
Wait until all components are ready, then inspect them layer by layer:
kubectl get tigerastatus
kubectl get pods -n calico-system
calicoctl node status
calicoctl get nodesThis order is intentional: kubectl get tigerastatus first for the overall status, then pods, then BGP details. If BGP isn't Established yet, check the Felix logs:
kubectl logs -n calico-system -l k8s-app=calico-node | grep -iE "felix.*(error|warn)" | head -20Run two pods and make sure they can ping each other, then verify that the cluster's default policy isn't blocking anything:
kubectl run a --image=nginx
kubectl run b --image=busybox --command -- sleep 3600
kubectl exec b -- wget -q -O - http://a.default.svc.cluster.local
calicoctl get networkpolicy -ANo policy is defined yet, so traffic should flow freely. If it doesn't, there's a problem with the installation — episode 19 covers troubleshooting in more depth.
By default Calico programs iptables (or nftables on systems that use the nftables API). This mode is the most compatible, runs on almost any kernel, and is sufficient for most policy needs. Its overhead is a rule chain that grows longer in large clusters.
eBPF mode replaces iptables with eBPF programs injected into the kernel. The benefits: higher performance, direct server return (DSR), load balancing that replaces kube-proxy, and policy at the socket level. But there are strict kernel prerequisites:
Linux 5.3+ (v3.32 requires a newer kernel for certain features)
CONFIG_BPF -> y
CONFIG_BPF_SYSCALL -> y
CONFIG_BPF_JIT -> y
CONFIG_BPF_UNPRIV_DEFAULT_OFF -> y
CONFIG_DEBUG_INFO_BTF -> yCheck your node's prerequisites with the official script:
curl -LO https://raw.githubusercontent.com/projectcalico/calico/v3.32.1/scripts/check-kernel-config
chmod +x check-kernel-config
./check-kernel-config /boot/config-$(uname -r)Enable eBPF mode by changing the Installation:
kubectl patch installation default --type merge \
-p '{"spec":{"dataplane":{"type":"BPF"}}}'
kubectl get tigerastatus | grep -i bpfImportant note: eBPF requires kubeProxyReplacement: strict and replaces kube-proxy. The full eBPF details — including DSR and performance comparisons — are covered in episode 17.
Episode 3 equips you with context-aware installation skills: choosing Helm or manifests, customizing the IPPool via Installation, verifying components, and picking the right dataplane.
Key takeaways:
Installation resource controls the IPPool, CIDR, and encapsulation mode.calicoctl node status.In the next episode, episode 4, we cover IPAM and basic networking — IPPools, per-node block allocation, IPIP/VXLAN versus direct routing, and how pod-to-pod, pod-to-service, and the interaction with kube-proxy work. This will explain why the IPs on your pods look fragmented.