Benefits of Kubernetes
Kubernetes is an open source orchestrator for deploying and managing containerized applications at scale. Kubernetes was originally developed by Google, based on their learnings from Borg and Omega Projects, which Google uses to deploy and scale their internal applications (e.g: GMail, YouTube etc).
So what does Kubernetes do? Well to put it simply, it provides tools necessary to build and deploy reliable, scalable distributed applications. To elaborate further, in modern architectures, huge number of services are delivered over the network via APIs. These are delivered via distribution systems running on multiple servers and configurations in various locations all coordinating their actions via network communication. Gone are the days we used to simply deploy an application in one VM and used to point a DNS to it. Load is balanced and horizontal scalability is achieved by making systems distributed like these. We are using these exposed APIs on a daily basis, all around the globe, these systems should be highly reliable and available, ie; they cannot fail and should not have any downtime. Since these services are accessed from all around the world, they should be scalable as well, without a radical redesign of the existing system. Kubernetes provides relevant services to achieve all of this for your containerized application.
Let‘s discuss the major benefits of using containers and a container orchestration platform like Kubernetes.
The speed at which you constantly update your application and deploy it’s new features to the users. Back in the day, to update a software or when pushing a new deployment, there was a lot of a downtime and was usually done in the midnight or over the weekend where the user traffic was at a minimum. However, you should note that when continuously deploying new features with downtime does not increase velocity. The goal is it update the application without a downtime as users expect a constant uptime. Therefore velocity is measure through the number of features you could ship per hour while maintaining a highly available service.
The core concepts of Kubernetes which enables high velocity are immutability, declarative configuration and self healing systems which are discussed below.
Containers and Kubernetes encourage developers to build distributed systems that adhere to the principles of immutable infrastructure. In immutable infrastructure an artifact created, will not be changed upon user modifications.
Traditional way of doing things with mutable infrastructure was, allowing changes to happen on top of existing objects as incremental updates. Therefore, the current state of the infrastructure cannot be represented as one single artifact, but rather an accumulation of incremental updates and changes of that artifact.
When it comes to updating an application in traditional way, what you would do is either log into a VM or existing container and download the latest software binaries of your application, kill the server and restart it. If something goes wrong, with multiple updates, you don’t have any record of how many updates you deployed and at which point the errors started to occur.
In immutable infrastructure, if you want to update your application, you simply build a new container image with a new tag, and you deploy it, killing the old container with the old image version. This way, you always have an artifact record of what you did and if there was an error in your new image, you could easily rollback to the previous image.
Everything in kubernetes is a declarative configuration object that represents the desired state of the system. This is an alternative to the traditional imperative configuration, where the state of system is defined by the execution of a series of instructions rather than a declaration of desired state of the system.
An example to explain the above simply is, consider a task of running 3 replicas of a piece of software. With imperative configuration, it would be, “run A, run B, run C” whereas with declarative configuration, it would simply be, “replicas = 3”
Declarative configuration enables the user to describe exactly what state the system should be in and is far less error prone. Traditional tools of development such as source control, unit tests etc can be used with declarative configurations in ways that are impossible with imperative configurations. This makes rollbacks fairly easy for kubernetes which is impossible with imperative configurations. Imperative systems basically describe how to get from point A to B, but rarely include reverse instructions to get you back.
Self Healing Systems
When kubernetes receive a desired state configuration, it does not simply take actions to make the current state match the desired state at a single time, but it will continuously take actions to ensure it stays that way as time passes by.
Example for this is, if you assert a desired state of 3 replicas of a certain application, kubernetes would not only create 3 replicas, but it will continuously ensure that there are exactly 3 replicas. If you manually destroy one, kubernetes will bring one back up to match the desired state.
As the product grows, you have to scale both your software and teams working on it. Kubernetes achieves scalability by favoring decoupled architectures.
In a decoupled architecture, each component is separated from other components by defined APIs and service load balancers. APIs provide a buffer between implementer and consumer, and load balancers provide a buffer between running instances of each service. Decoupling components via load balancers makes it easier to scale the programs that make up your service, because increasing the size of the program can be done without adjusting or reconfiguring any of the other layers of your service.
Scaling Applications and Clusters
Scaling is fairly easy due to the immutable, declarative nature of kubernetes which was explained earlier. Because the containers are immutable, the number of replicas is simply a number in the declarative config which could be changed whenever required. Of course you can set up auto scaling as well with kubernetes which will take care of everything for you.
However, with autoscaling, it assumes that there are enough resources available. If not, you will have to scale up the cluster itself. Kubernetes makes this task easier as well because every machine in the cluster is identical to every other machine and the applications themselves are decoupled from the machine by containers, adding additional resources is simply a matter of creating a new machine with required binaries using a pre-baked image and joining it to the new cluster.
Building decoupled microservice architectures
When building microservice architectures, multiple teams work on a single service each which would be consumed by other teams for their service implementation. The aggregation of all of these services ultimately provides the implementation of overall product’s surface area.
Kubernetes provides numerous abstractions and APIs to enable this.
- Pods, or groups of containers can group together container images developed by different teams into a single deployable unit.
- Kubernetes services provide load balancing, naming and discovery to isolate one microservice from another.
- Namespaces provide isolation and access control so that each microservice can control the degree to which other services interact with it.
This means that decoupling the application container image and machine allows different microservices to colocate on the same machine without interfering the other, reducing the overhead and the cost of microservice architectures.
The health checking and rollout features of Kubernetes guarantee a consistent approach to application rollout and reliability as well.
Separation of Concerns
To explain this simply, The application developer relies on the SLA (Service level Agreement) delivered by the container orchestration API, without worrying about how it is achieved and likewise, the orchestration API reliability engineer focuses on delivering the orchestration API’s SLA without worrying about the applications that run on top of it.
This separation of concerns or decoupling means that a small team running a Kubernetes cluster can be responsible for supporting thousands of teams running their applications within that cluster.
Abstraction of Infrastructure
Kubernetes separates developers from specific machines. In context of the cloud, this enables a high degree of portability since developers are consuming a higher level API that is implemented in terms of the specific cloud infrastructure APIs.
This allows developers to transfer their applications between environments which is a matter of sending the declarative configuration to the new cluster. Kubernetes has a number of plugins that can abstract you from a particular cloud. For example, kubernetes knows how to create load balancers on all major public clouds as well as several different private and physical infrastructures.
In Kubernetes, applications can be colocated on the same machines without impacting each other. This means that tasks from multiple users can be packed tightly onto fewer machines. This in turn provides greater efficiency and also reduces the cost on hardware as less machines are used.
Kubernetes was built to radically change the way applications are built and deployed in the cloud as it was designed to give developers more velocity, efficiency and agility.
This blog post is inspired by the contents of the book ‘Kubernetes Up & Running’ by Kelsey Hightower, Brendan Burns and Joe Beda.
Thank you for reading.