Most content in this document comes from "Learn Kubernetes in a Month of Lunches".
Pods can communicate via IP address and they just use the standard protocols(TCP/UDP). However, it is not a good approach to solely rely on an IP address for communication. Because Pods are managed by Deployment controllers, it is hard to keep track of a new IP address whenever the Pod is replaced. The ideal solution would be to assign a static IP address to the ever-chaning Pod, which is why the concept of Service is invented and come to play in Kubernetes.
Like the internet, Kubernetes have its own DNS(Domain Name System, called kube-dns
), mapping friendly names to IP addresses. Creating a Service effectively registers it with the DNS server, using its Service name and IP address. When a DNS receives Service name it returns the Service’s IP address, which is static for the life of the Service. With the selector label that bonds the Service to the Pod(e.g. app: sleep-2
), Kubernetes routes the traffic to the Service and then toss it to the Pod.
There are roughly three types of services, depending on scenarios :
This is the default type of Service and it is called ClusterIP. The assigned IP address works only within the cluster, so ClusterIP Services are useful only for communicating between Pods. Below is the basic YAML spec for ClusterIP Service.
After deploying a Service called numbers-api
, the Service has its own IP address. However, an external IP is not yet assigned because the ClusterIP Service is available only within the cluster.
A LoadBalancer Service integrates with an exteranl load balancer, which sends traffic to the cluster. The Service sends the traffic to a Pod, using the same label-selector mechanism to identify a target Pod. You might have many Pods that match the label selector for the Service, so the cluster needs to choose a node to send the traffic to and then choose a Pod on that node. But this issue is taken care of by Kubernetes. All you need to do is deploy a LoadBalancer Service. Below is the basic LoadBalancer Service YAML spec.
Once setting this Service up, the external IP is assigned so you are no longer required to do port forward.
When you want to integerate some resources(e.g. database) running outside your cluster with any nodes running within the cluster, you need to use an ExternalName Service. ExternalName Services create a domain name alias and register it in the DNS server. When the Pod makes a lookup request using the local name, the DNS server resolves it to a fully qualified external name. Below is an example of the Service YAML spec.
Check the Service configuration.
If you want to route to an IP address rather than a domain name, you can use another option called headless Services, which are the ClusterIP type of Service but without a label selector so they will never match any Pods. Instead, the service is deployed with an endpoint resource that explicitly lists the IP addresses the Service should resolve. Please refer to an YAML spec example below.
Replace the ExternalName Service with the headless Service, check the Service and endpoints, and verify the DNS lookup.
If you look the DNS lookup output above, you will find the two interesting facts. First, the resolved IP address(10.108.78.48
) is not the endpoint but the ClusterIP address. Second, the domain name ends with .default.svc.cluster.local
. We will get answers below.
To answer the first question, we need to keep in mind that Services have the up-to-date endpoint list. Therefore, clients need to visit the Service first to get the latest endpoint, and this is why the numbers-api
resolves to its Service IP address.
Pods access the network through the a network proxy called kube-proxy
, another internal Kubernetes component, and that uses packet filtering to send the Service’s ClusterIP to the real endpoint. The reason kube-proxy
has the up-to-date endpoint list is that Services have a controller that keeps the endpoint list updated whenever there are changes to Pods. Thus, kube-proxy
is able to refresh the endpoint list whenever clients visits the static ClusterIP address.
For the second question, we need to understand a new Kubernetes resource - namespace. Every Kubernetes resource lives inside a namespace, which is a resource you can use to group other resources. Namespaces are a way to logically partition a Kubernetes cluster. In the above example, because the Service is in the default
namespace, the suffix of the domain name begins with .default.svc.cluster.local
. In the same manner, the full domain name for kube-dns
in the kube-system
namespace is kube-dns.kube-system.svc.cluster.local
, as described below.