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 the clusterIP/Service CIDR ( –service-cluster-ip-range). Reason being, we need to cover the concept of endpoints and services first.
While pods in cluster can all communicate with each other via unique pod IP addresses, it isn’t ideal for pod-to-pod communication. 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 to change it. K8s does not automatically create DNS records for pods and their corresponding IP addresses because DNS and DNS resolvers are not designed to deal with frequent changes of an A record. Finally, we often replicate pods, complicating how a replicaset of pods would be rationalized by a requesting pod. Enter the service object.
A service provides an IP address that load balances to a back-end set of pod endpoint addresses. It is cluster based and will exist so long as the the service exists, irrespective of pod life. A service address is created as an A record in K8s DNS and enables requests to connect to a back-end ReplicaSet of pods (i.e. endpoints) without needing be concerned with the endpoints’ addresses.. By directing pods and external ingress traffic to a service address, we avoid the 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 expose it with a service and connect to the service IP via the service DNS name. There are three service types commonly in use: clusterIP, NodePort, and LoadBalancer. HostNetowrk and HostPort are two other types you might encounter, but are not recommended unless absolutely required (I’ll cover those two in another post).
ClusterIP is the base form of a service in K8s, any and all services will have a clusterIP assigned. 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 for other pods in the cluster to address. For any pod-to-pod communication requirement, we should expose a pod/deployment/ReplicaSet via a clusterIP.
Here’s an example of creating a clusterIP for a replica set 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:
- Services front-end and load balance pods with a stable IP address.
- A pod is considered an endpoint by relation when it’s load balanced behind a 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 type is for pod-to-pod communication and does not expose its address outside the cluster.
- If a pod needs to accept requests from within the cluster only, it should be exposed as a ClusterIP type of service.
Next up, I’ll cover NodePort, LoadBalancer, HostPort, and HostNetwork as methods to expose a pod to the outside world.