In the previous two posts, I went over the basic networking components of K8s, and how a packet flows within the cluster. I discussed the node and pod CIDRs, but purposely avoided getting deeper into the ClusterIP/Service CIDR ( –service-cluster-ip-range). Reason being, we need to cover the concept of endpoints and services first.
While pods in a cluster can all communicate with each other directly via their unique pod IP addresses, it isn’t an ideal practice to initiate communication directly to a pod IP. As we know, a pod is ephemeral and potentially short lived. There is no guarantee the IP address will remain the same across recreation. In fact, K8s will always attempt change it.We also wouldn’t achieve the benefits of load balancing across pod replicas if we initiated communication by specific pod IP.
To initiate communication to a pod, K8s implements the abstraction of a service. A service has its own IP address and serves as the entry point to a pod or set of pod replicas. K8s does not automatically create DNS A records for pod names with their corresponding IP addresses. (It will create an A record for each pod, but the name will be based on the pod IP, so not useful for resolving pod name to IP.). The clusterIP service address receives an A record in DNS, we direct traffic to that IP via DNS name resolution and K8s takes care of balancing across the endpoint pod addresses.
Note: There are a couple of exceptions to the above. If we define the ‘hostname’ field within a pod spec, a corresponding A record will be created. If we expose a StatefulSet via a Headless service, we will also be able to resolve by pod name. More on that in a future post. For now, think of pods as being either stateless or stateful oriented. A stateless pod is immutable and does not persist any changes on restart. When we create stateless pods, we prefer to use the Deployment resource for operational benefits. As we discuss clusterIP in this post, it’s focused on this stateless.mode. Think of a web server being stateless (Deployment w/ clusterIP) and a database server being stateful (StatefulSet w/ Headless)
By service directing traffic, we avoid the potential issue of pods/endpoints IPs changing.. K8s typically utilizes NAT and iptables to redirect and load balance a service address to the endpoint pod address(es). The process that orchestrates all of this is kube-proxy, which runs as a daemonset in the cluster (A daemonset is simply a deployment that is automatically added to every worker node in a cluster by the scheduler.). If a pod dies and is recreated with a new IP address, kube proxy updates the service endpoints table.
So, if you want something to connect to a pod, you can expose it with a clusterIP service and connect to the service IP via the service’s DNS A record value. There are four service types available: ClusterIP, Headless, NodePort, and LoadBalancer.. HostNetowrk and HostPort are two ways you can expose a pod outside of the cluster, but they are not services.. I’ll cover the others in another post.
ClusterIP is the base form of a stateless service in K8s, and is the default service type if a service is created without explicitly defining the service type. It is only advertised within the cluster (i.e Only nodes and pods in the cluster can access the address) and provides a stable IP with DNS record for others to address. For any stateless pod communication requirement, we should expose a pod/Deployment/ReplicaSet via a clusterIP.
Here’s an example of creating a clusterIP for a deployment and then accessing it via its service address. You’ll see that I’m creating a ReplicaSet via the deployment controller object. A deployment is the preferred way to create a ReplicaSet, due to the controllers ability to manage updates and rollbacks of ReplicaSets. First, I’ll create the deployment and access it via one of the pod addresses and demonstrate why accessing via pod IP is not advisable. Then I’ll expose it via a clusterIP, access it via the service address, and demonstrate how that abstraction prevents issues created by pod life cycle events.
Ok, so that’s the first service type We know:
- clusterIP service front-ends and load balance pods with a stable IP address backed by a DNS A record.
- A pod is considered an endpoint by relation when it’s load balanced behind a clusterIP service IP.
- K8s uses a process called kube-proxy, by default, that configures iptables/netfilter and serves as a cluster load balancer to endpoints.
- clusterIP service is for pod communication and does not expose its address outside the cluster.
- If a stateless pod needs to accept requests from within the cluster only, it should be exposed as a clusterIP service.
Next up, I’ll cover nodePort, LoadBalancer, Ingress Controller, hostPort, and hostNetwork as methods to expose a pod to the outside world. As well as additional information on the headless service.