Kubernetes is an open-source container orchestration platform that allows you to automate running and orchestrating container workloads. It is a powerful tool that offers a huge ecosystem of tools — package managers, service meshes, source plugins, monitoring tools, and more — as an abstraction layer for deploying standardized, full-stack applications across an ever-increasing range of platforms. Kubernetes is often referred to as “K8s.”
Also: Kubernetes is hard.
Kubernetes made the simple things hard and the hard things possible, Paul Dix famously said in his 2018 essay “Will Kubernetes Collapse Under the Weight of Its Complexity?” Anyone who has ever worked with K8s is probably nodding vigorously in agreement right now. Though the dynamic duo of containers and microservices provide tremendous scalability and velocity, they also bring a complexity of scale that is difficult to grasp — much less deploy and manage. As a result, many engineers and developers love to hate K8s. But it’s the de facto standard for container orchestration on an ever-increasing range of platforms, both in the cloud and on-premises, and is widely viewed as the gateway for seamless hybrid and multi-cloud workloads.
Kubernetes is not going away, at least not any time soon. And, increasingly, developers are being required to interact with it. So let’s get the tl;dr on what devs need to know about Kubernetes:
As managers increasingly ask developers to take on cross-functional DevOps responsibilities, it is helpful to understand a little about how Kubernetes works and which situations it best suits.
Even if you’re not developing with it, if your app is ultimately deployed to Kubernetes you should still test it locally on K8s to avoid unhappy surprises in production. What exactly is container orchestration, and how does Kubernetes help deliver and support modern, containerized applications?
Containers are lightweight, standalone executable software packages that include everything required to run an application: code, runtime, system tools, libraries, and settings. They are a sort of “standard unit” of software that packages up the code with all its dependencies so it can run anywhere, in any computing environment. Container platforms such as Docker enable developers to package their applications and dependencies into a single deployable and fully standalone container. This container is separate and independent from the underlying infrastructure. In the same way, we can create and run virtual machines without having to manage bare metal servers, and we can deploy containers without managing individual servers. Containers can be spun up as workload demands and then killed when no longer needed — meaning you can scale up and down dynamically in response to your business needs.
Of course, we need something to help us manage and deploy all these containers — after all, an enterprise-level application will span multiple containers. These must be deployed across multiple server hosts that form a comprehensive container infrastructure that includes networking, storage, security, and other services. An orchestration engine deploys the containers necessary for a required workload, scheduling them across a cluster and managing communication between them while also simultaneously scaling and maintaining them — all the while integrating everything with the container infrastructure. Orchestration engines, in other words, do a lot.
Kubernetes is the most popular container orchestration engine, born out of a Google project called Borg. Borg managed clusters for hundreds of thousands of services and workloads. (A cluster is a set of node machines for running containerized applications. If you’re running Kubernetes or any other orchestrator, you’re running a cluster.) Borg eventually transformed into the open-source Kubernetes project, which grew to support multiple cloud providers and container types. (As well as a high-demand skill set on engineering resumes).
Why should we even care about Kubernetes?
Developers do not just write application code anymore. As applications increasingly adopt microservices architectures, we are also empowered to make more infrastructure decisions. This, however, means that companies also expect us to help build and maintain that infrastructure.
Kubernetes has essentially become the industry standard means of specifying infrastructure. Everything a system needs — including processes, load balancers, and GPUs — developers can now articulate in YAML and schedule via Kubernetes.
Does even that much configuration sound intimidating? Fortunately, K8s setup and management (with so many service dependencies) is becoming increasingly automated and abstracted through user-friendly (give us that good UI) products and services like Tilt, Kublr, and KontenaLens. These tools render the Kubernetes orchestration engine into a more approachable framework for managing service dependencies.
When you add an orchestration service, it removes concerns about deploying and testing to individual virtual servers. Also, it manages concerns about server scaling limits when collating application components.
However, building and managing a Kubernetes cluster can be much more complex and time-consuming than managing more traditional application environments. It imposes operational overhead and requires specialized knowledge. Also, not every application requires the power and scale Kubernetes offers. How to tell?
The question to ask yourself is, Am I using microservices?
If you have a complex application composed of many different services hosted within their own containers that needs to rapidly scale to support its users, then Kubernetes can be an ideal choice. Your application might have hundreds of these containerized components that must scale across a large number of nodes. There might also be multiple developer, ops, and DevOps teams involved at any one time. The good news is Kubernetes can easily orchestrate this sort of workload. The bad news? With applications of this size, you now also need to have enough developers to support cluster management as well.
More good news: You may not even need it!
Yes, Kubernetes is super hot tech right now. As a developer or DevOps manager, you might feel like your application development pipeline is hopelessly outdated if it doesn’t include Kubernetes. However, many applications simply do not require this level of complexity because they are scalable enough to run within a few containers or traditional servers. Common examples include smaller applications that already run within containers but do not interact much with other containers, or that have modest scaling requirements to manage the load. Sometimes, it is more efficient to run these containers in the cloud, with a few more resources allocated to managing peak loads, than deploying complex Kubernetes clusters — especially given the low cost and wide availability of cloud infrastructure.
Another example is monolithic or traditionally-hosted applications that can scale using the servers they are deployed to long before requiring Kubernetes. Scaling is usually more about an application’s internals than the high-level architecture and tooling. For instance, you can scale a monolith by deploying multiple instances with a load balancer that supports affinity flags. You can also use tools like Chef and Ansible to automatically configure new servers to ensure they are ready to run your application, instead of provisioning them manually. With these resources, a more traditional web application written in .NET or Java can still scale to easily handle a large number of requests — like how Stack Overflow used 11 IIS web servers to handle 66 million page loads a day.
Kubernetes provides far more functionality than most developers will ever need. Chances are, you simply do not care how many service replicas are running for your app, or what roles each has, and whether they are running via StatefulSets. Your main job is simply to establish an HTTP endpoint to deliver the product.
It’s tricky to strike the right balance. You do not want a black box, but you do not want full access either — it is too easy to mess things up. Small changes to a cluster can have devastating unanticipated butterfly effects, like exceeding available resources or multiplying your patching work.
Although Kubernetes is a great tool, managing distributed services can be complex. If simplified architecture suits your app just fine, you can save yourself some (a lot of) pain by leaving Kubernetes to the projects that truly need it.
Unfortunately, that decision is not always in the hands of the devs charged with actually delivering an application. So let’s look at what to do when you have no choice but to make friends with K8s.
How do you work with Kubernetes when it’s not really your job to work with Kubernetes? Here are your options: Use component architecture but skip the microservices and work with a lighter weight, simplified version of K8s. Or try to work out an agreement with your Ops team, whose job actually is to work with K8s.
In the best-case scenario, K8s developers need a simplified, actionable interface that does not restrict them from digging into the API when they need to. Lightweight container orchestration tools like Microk8s, or K3s for Internet of things (IoT) and edge workloads, reduce management requirements by simplifying Kubernetes clusters. Both tools let you keep your application’s architecture while running it on Kubernetes, albeit with some restrictions in available features. If your modular application begins to need scaling, this can be a good alternative to a full microservices architecture.
Another option for those still mostly on the developer side of the DevOps continuum is to work with your Ops equivalent to incorporate Kubernetes inside the continuous integration and continuous deployment (CI/CD) pipeline. This way, developers do not drown in Kubernetes details or risk breaking the cluster. This approach lets you simply push code to GitHub. The people who are fully fluent in Kubernetes take care of the rest, while allowing testing to remain available for development.
If modifying your CI/CD pipeline is not an option, work with Ops to create an intermediary layer, typically a separate API — thankfully, a developer comfort zone — to maintain overall control of the cluster(s) by specifying what developers can and cannot modify. This requires more knowledge of and hands-on work with K8s, but protects developers from facing the full complexity and protects the system from errors.
Kubernetes is a great tool for deploying, managing and scaling large distributed applications. If your application is simple - a single service, say – it’s smart to just keep it all in one place, Monolithic architecture is not automatically a terrible thing, no matter what the cloud native evangelists say. If your application is not large, and multiple teams are not working on different components, you probably don’t need to split it into microservices. Which means you won’t need Kubernetes to orchestrate the microservices you don’t have!
Realistically, though, many developers may not get a say in the “Should we use K8s?” discussion. The good news: You don’t need to be a deep Kubernetes expert. When traveling to the cloud native kingdom of containers and microservices and distributed application deployment, however, you do need to be able to speak some K8s. The simple truth is that Kubernetes now handles the majority of production workloads. And it is much easier to write effective application code and debug problems when you have a basic grasp of what is happening in K8s and how everything fits together.
The future is set: everything that is not already completely on the cloud now will be soon. The cloud is a distributed system, so software architecture increasingly needs to be distributed, too, to function at full potential. Software is increasingly becoming too complex to fully isolate developers from infrastructure.
To handle the complexity, we developers need to embrace K8s. Or at least become best frenemies.