That virtualized portion of the Operating System (not the hardware) is containerization.
In this article, youʼll learn about where containerization and orchestration can help you today in your application stack regardless of whether youʼre running on-prem, in the cloud, or a little bit of both (hybrid or multi-cloud).
Letʼs think about a brief timeline of how containerization and orchestration came to be:
Around these three dates, engineers also saw platforms like Linux Orchestration (LXD), Docker Swarm, and Apache Mesos come out. The key thing to remember is from the start of 2008 to the present, the realm of technology has seen a significant change in how application stacks are interacted with.
Taking a step back, there was a key reason for this evolution – VMs gave engineers the ability to virtualize hardware, but not the Operating System. Although engineers could virtualize a server, which meant you didnʼt need an entire application stack dedicated to one server (which as we see it now would be an extraordinary amount of resource waste), Operating Systems still needed to be managed one-for-one much like servers and mainframes needed to be before virtualization. This is where Linux Namespaces and Cgroups come into play.
Linux Namespaces allow application stacks to run on a single Operating System without touching each other. From a security perspective, this is important because there are many cases where you donʼt want applications to have the ability to communicate with each other from an ingress (inbound) and egress (outbound) perspective. Segregation of workloads is incredibly important to separate concerns.
Cgroups allow you to take the step of segregation a step further to monitor and isolate resources like CPU and Memory. This ensures that the application stacks running have the proper resources they need from a performance perspective.
💡 Resource and Cost Optimization are huge focus areas in the realm of cloud-native today. Although Cgroups give engineers the ability to isolate resources, that doesnʼt mean it always happens. Thereʼs a ton of overspending in the cloud because itʼs incredibly simple to spin up new resources and not think about/realize the consequences.
With Linux Namespaces and Cgroups combined, engineers have the ability to separate application stacks and ensure proper resource optimization all on the same Operating System. This is where the idea and conception of Containers were born. LXC hit the ground running with this.
LXC was and still is great, but there was a big problem - it wasnʼt commercialized. It existed and was usable, but people found it confusing, very low-level, and not scalable. Thatʼs when Docker was released in 2013. Docker made containers accessible and usable in a much easier way in comparison to LCX, which is why Docker went “commercialˮ.
There was a big problem though - containers were great and ran workloads very quickly, but by default, they didnʼt scale. There was nothing that could orchestrate them. Containers would come up, die/go down, and that was it. Hence, the beginning of orchestration needs was imminent.
The orchestration wars then began. It was a big back-and-forth between Kubernetes, Apache Mesos, and Docker Swarm. Ultimately, Kubernetes won. No one can actually say why it won, but there are a lot of theories from ease of use to simply put, better marketing and adoption.
Fast forwarding to 2024, you canʼt really mention cloud-native workloads without thinking about Kubernetes and Containers. It truly is the new “defaultˮ, and a very long default at that. With Kubernetes being released in 2014/2015, itʼs been around for a decade and thereʼs nothing in currently in hindsight to take its place.
With a bit of history out of the way, letʼs dive into Docker, Kubernetes, and how they work together along with how they are different.
As alluded to in the previous section, Docker and Kubernetes, or Kubernetes and a container runtime must coexist. You canʼt have one without the other. Kubernetes doesnʼt know, natively, how to run a container without a container runtime. Docker and other container runtimes donʼt know how to scale, self-heal, and manage containers without an orchestration system like Kubernetes. With that being said, there isnʼt a true “Docker vs Kubernetesˮ because both are necessary.
Docker has two pieces to the puzzle - the Docker Engine and the Docker Runtime.
The Docker Engine is comprised of all the Docker tools from the ability to create container images with Dockerfiles to the CLI to the Docker Runtime itself. The Docker Runtime is what actually has the ability to run the containers. When thinking about the Docker Engine, think about the entire toolset. A great example of this is Docker Desktop, which continues to be the primary way to run containers on a local computer/laptop/desktop. A few of the other popular container runtimes are:
Overall, youʼll most likely see CRI-O and Containerd used the most. In the realm of Kubernetes, youʼll typically see CRI-O or Containerd. Locally, or standalone, youʼll typically see Docker used.
In the previous section, you learned about a few different container runtimes along with the most mainstream runtime, Docker (which uses Containerd). You also learned that Kubernetes doesnʼt know how to natively run a container. Thatʼs true for the majority of what engineers run in Kubernetes. For example, Kubernetes doesnʼt know how to manage networking or storage natively either. Thatʼs where plugins come into play.
Kubernetes is like a house that just got built. It has carveouts for rooms, the bathroom, light fixtures, etc, but none of that exists yet. Plugins are the way to get those rooms filled out in Kubernetes.
There are several plugins, but from a containerization perspective, the one youʼll want to understand is the Container Runtime Interface (CRI). Without the CRI, Kubernetes has no idea how to run, manage, stop, or start containers. The CRI consists of a container runtime, and in Kubernetes, itʼs most likely CRI-O or
Containerd. The reason why you need a runtime is because by default,
Kubernetes doesnʼt know how to “speak containersˮ. It needs a “shimˮ of sorts to plug in (probably hence the name) a container runtime.
Once the CRI is equipped within a Kubernetes cluster, it can start/manage/run/stop containers.
Kubernetes comes into play from an orchestration perspective. By default, container engines/runtimes donʼt know how to do things like:
Containtainers need an orchestrator to do that, and as you learned about in this article, Kubernetes won the “orchestration warsˮ many years ago.
When thinking about Docker and Kubernetes, split it up in your head this way; Docker/container runtimes is to run a container. Kubernetes/orchestration systems are to manage the container.
Although Kubernetes is still on the top when it comes to orchestrators in production, there are a few others that are readily available. Some notable ones to talk about are:
AWS Elastic Container Service
Azure Container Instances (ACI)
GCP Cloud Run
All of these orchestration platforms give you the ability to orchestrate containers without Kubernetes, which is the appeal. It removes the complexity of Kubernetes.
The problem is that thereʼs so much tooling built around Kubernetes now (GitOps solutions, running virtualized platforms like Kubevirt, IaC solutions like Crossplane, and Service Mesh) that because of the ecosystem, if you donʼt use it, youʼre missing out on a lot. The biggest thing to ask yourself is “Do we need all of that?ˮ. In many cases, it may be yes. In some, it may be no. For example, a startup may have an easier time using one of the other orchestration options.
As always, it depends on your circumstances. The good news is you have plenty of options.
Before wrapping up this article, it makes sense to chat about perhaps the next evolution after containers, Web Assembly (Wasm).
The Founder of Docker, Solomon Hykes, said publicly that if Wasm and Wasi existed in 2008, containers as a whole most likely wouldnʼt have been created. Thatʼs a pretty bit statement coming from the person that made adopting containers possible for almost everyone.
In short, Wasm gives you the ability to create a binary that works crossarchitecture, cross-programming language, and can potentially be 20-160% faster than a standard container.
At the time of writing this, containers and Kubernetes seem to still be the most popular and workable solution to running cloud-native application stacks. The upand-comer, which has a big chance of surpassing Docker, is Web Assembly (Wasm), but that certainly wonʼt happen overnight.