Part of the reason why Kubernetes is so popular is because of the ease of networking between thousands of microservices. Every Pod receives its own IP address, while every Service receives a stable virtual IP used for service discovery and load balancing. The Pod network is an internal private subnet in Kubernetes, in which the whole workload deployed on the Kubernetes cluster runs.
But Kubernetes is not capable of implementing the networking for Pods and Services by itself.
Luckily, there is something that does all the work for us, and that is the CNI (short for Container Network Interface). All I have to do is deploy the CNI, and that is it. The CNI is essential for a working Kubernetes cluster, as it handles the important networking functionality within Kubernetes mentioned below.
- creating Pod network interfaces
- assigning IP addresses
- configuring routes
- connecting Pods to the network
To be exact, CNIs are so important to Kubernetes that without them, the cluster could not deploy Pods at all. One of the responsibilities of the CNI is providing the kubelet with the ability to configure the network interface of the Pod. When the kube-apiserver sends an instruction to the kubelet, the kubelet calls the CNI for network provisioning of the Pod. So if there is no CNI, the kubelet cannot configure the network settings for the Pod, and the Pods will stay in a ContainerCreating state.
But this is not where it ends. The CNI is also responsible for assigning an internal IP address to every Pod. This IP address is part of the Pod network, which is the Kubernetes internal subnet, also managed by the CNI. The IP address of each Pod is essential for communication between the microservices. Without it, the microservices cannot communicate either with the Pods or with the Services in Kubernetes.
And because the CNI assigns each Pod an address from the Pod network, DNS for Services and Pods is also made possible with the CNI. Calling a Pod or Service from within the cluster does not have to happen with the IPv4 address. Each Pod and Service has a unique DNS name that resolves to its IP address. The concept is similar to Docker networking, where you can call each container by the container name from another container.
The same applies to Kubernetes as well. The Pods don’t talk to each other via the IP address, but with the DNS name of the corresponding Service. Generally speaking, the structure of DNS names resembles the following:
my-svc.my-namespace.svc.cluster.local
The DNS resolution is what makes deploying a microservice architecture possible with ease. Although technically speaking, the DNS resolution is happening directly in Kubernetes instead of the CNI. To be even more specific, the service handling DNS resolution is CoreDNS.
There are several possibilities on which CNI to use. Each comes with its own pros and cons, and every CNI can be deployed with either Helm charts or directly with the manifest files.
The three most used CNIs are Cilium, Calico, and Flannel. Cilium is known for its advanced eBPF-based networking and observability features. However, Calico has added many of the advanced capabilities traditionally associated with Cilium, including eBPF dataplanes. I like to use Calico because it has modern and well-written documentation. It supports both network policies and eBPF—everything you need to build a secure and performant Kubernetes cluster.