In the previous article, I discussed the general aspects of Kubernetes, why adopting microservices as a development standard is beneficial, and how Kubernetes facilitates this process. In this article, we will go a bit beyond the basics and address everything surrounding an application deployed in Kubernetes. That is, since we have already defined how the cluster works at a physical level, it is necessary to understand what the internal moving parts are that the nodes interact with.
Pods
The main and most important component of the system is the pod. It is important to mention that Kubernetes does not deal directly with containers—it uses the concept of multiple co-located containers. A group of containers can be grouped in a pod, although generally, a pod only runs a single container. The pod has its own private IP address and hostname.
A pod, as explained earlier, is a group of tightly coupled containers that always run on the same worker node and in the same namespace. Each pod is like a separate logical machine with its own processes, IP, hostname, etc., running an application. All containers in a pod will appear to be running on the same logical machine, while other containers in other pods, even if they run on the same worker node, will appear to be running on a different one.
To better understand the relationship between containers, pods, and nodes:
Here, you can see that each pod has its own IP address and hosts one or more containers. This example shows a single node, but pods can be distributed across different worker nodes. On the other hand, to store non-volatile data for applications, you can see volumes in the figure, which we will discuss later.
Exposing Pods Outside the Cluster
It has been mentioned that each pod has its private IP address, which does not enable the possibility of accessing applications from outside the cluster. To make pods accessible from outside, they need to be exposed through a Service object that allows this task.
A Service in Kubernetes is a resource created to obtain a single and constant access point to a group of pods that provide the same application. Each service has an IP address and a port that do not vary while it exists. This way, clients can establish communication with that IP address and port, and those connections are then directed to the pods that support that service.
There are several types of services:
- NodePorts: For each of these service types, the cluster opens the same dedicated socket on all nodes (this means it assigns the same port to all the cluster's public IP addresses) and redirects all traffic received on those ports to the underlying service.
- LoadBalancers: These are an extension of NodePorts—these make the underlying services accessible from a dedicated load balancer provisioned by the cloud infrastructure. Essentially, a load balancer gets a dedicated public IP for its service where clients can send their requests. This type of service is not always enabled because it depends on the cloud provider and the ability to create public IP addresses.
- Ingress: This is a radically different mechanism to expose multiple services through a single IP address. It operates at the HTTP level (network layer) and thus offers more features than layer 4 services can. When a client sends an HTTP request to the ingress, the host and the path in the request define which application it is directed to.
There is another type of service called ClusterIP which, although it does not expose pods outside the cluster, is very useful when exposing groups of pods to others through a static internal IP or a fixed hostname that other pods can resolve and point to. It is very useful when implementing databases within the cluster.
Deployments
There are multiple ways to group and manage pods, but the simplest and most efficient way is through high-level resources called deployments. These are intended for deploying applications with their respective configurations through a declarative file where everything related to that deployment is specified. There are other ways to do this, such as using ReplicationControllers or pure ReplicaSets, but since these are quite obsolete, they will not be addressed.
When a Deployment is created, a ReplicaSet resource is created underneath (ReplicaSets replicate and manage pods) but allows updating the definitions of this deployment in a better way. For now, a Deployment resource should be seen as a way to deploy generally replicated pods and create a logical space for a higher-level service to access them through a unique application selector, but they also serve as a tool to incorporate changes into the application without downtime.
Volumes
A volume in Kubernetes is the way to store useful data for containers and applications. It is constructed when a pod is started and destroyed when that pod is deleted—and they are components of the pods. These are accessible by all containers within the pod but must be "mounted" to be accessed.
There are many types of volumes in Kubernetes (you can find many of them here). At Darien Technology, we use LongHorn types, which are basically a highly available (HA) distributed storage system developed by Rancher—and we use this type because they are the best way to maintain on-premises storage very securely and cost-effectively.
In the next article, we will discuss the different types of Kubernetes implementations and how to set up a local environment that emulates a production cluster. See you there!