Skip to content
docktionary

Clusters & cloud

Cluster networking & CNI

Kubernetes defines the networking model it expects; a CNI plugin is what actually implements it. Which plugin you run decides what's possible for Pod IPs and traffic policy.

The model Kubernetes assumes

  • Every Pod gets its own IP, cluster-wide.
  • Pods can reach every other Pod's IP directly, on any node, without NAT.
  • A node can reach every Pod on that node directly.

Kubernetes itself doesn't implement any of this — it just assumes it holds, and calls out to whatever CNI plugin is installed to make it true.

Common CNI plugins

  • Calico — L3 routing with BGP or IP-in-IP encapsulation, and one of the most widely used implementations of NetworkPolicy.
  • Cilium — built on eBPF rather than iptables, which enables very granular L3–L7 policy and strong observability (Hubble) with less overhead at scale.
  • Flannel — simple overlay networking; minimal feature set, and notably does not implement NetworkPolicy on its own.
  • Cloud-native CNIs (Amazon VPC CNI, Azure CNI) — assign Pods real IPs from the VPC/VNet address space directly, which simplifies some things (Pods are visible to other VPC resources) and constrains others (IP exhaustion becomes a real planning concern).

NetworkPolicy: default-allow until you say otherwise

Out of the box, any Pod can talk to any other Pod. A NetworkPolicy selects Pods by label and declares what's allowed; as soon as one policy selects a Pod, everything not explicitly allowed to it is denied.

network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-from-app
spec:
  podSelector:
    matchLabels:
      app: db
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: docktionary
      ports:
        - protocol: TCP
          port: 5432

This allows only Pods labeled app: docktionary to reach db on port 5432 — everything else, including other namespaces by default, is denied.

A default-deny baseline

A common starting point for a namespace: deny everything, then add policies that open exactly what's needed.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]

Remember: the plugin has to support it

A NetworkPolicy manifest applies cleanly on any cluster, but it's silently a no-op if the CNI plugin doesn't enforce NetworkPolicy (Flannel without an add-on, for instance). Check what's actually running before trusting a policy is doing anything.

terminal
kubectl get pods -n kube-system -o wide   # look for calico-node, cilium, etc.
kubectl get networkpolicy -A