Kubernetes
Google is known for running Linux containers at scale. In fact, “everything” running at Google runs in Linux containers and is managed by their Borg cluster management platform. Former Google engineer Joe Beda said the company starts over two billion containers per week. Google even had a hand in creating the underlying Linux technology that makes containers possible. In 2006 they started working on “process containers,” which eventually became cgroups and was merged into the Linux kernel code base and released in 2008. With its breadth and background of operating containers at scale, it’s not a surprise Google has had such an influence on platforms built around containers. For example, some popular container management projects that preceded Kubernetes were influenced by Google:
- The original Cloud Foundry creators (Derek Collison and Vadim Spivak) worked at Google and spent several years using Google’s Borg cluster management solution.
- Apache Mesos was created for a PhD thesis, and its creator (Ben Hindman) interned at Google and had many conversations with Google engineers around container clustering, scheduling, and management.
- Kubernetes, an open source container cluster management platform and community, was originally created by the same engineers who built Borg at Google.
Back in 2013 when Docker rocked the technology industry, Google decided it was time to open source their next-generation successor to Borg, which they named Kubernetes. Today, Kubernetes is a large, open, and rapidly growing community with contributions from Google, Red Hat, CoreOS, and many others (including lots of inde‐
Kubernetes
pendent individuals!). Kubernetes brings a lot of functionality for running clusters of microservices inside Linux containers at scale. Google has packaged over a decade of experience into Kubernetes, so being able to leverage this knowledge and functionality for our own microservices deployments is game changing. The web-scale companies have been doing this for years, and a lot of them (Netflix, Amazon, etc.) had to hand build a lot of the primitives that Kubernetes now has baked in. Kubernetes has a handful of simple primitives that you should understand before we dig into examples. In this chapter, we’ll introduce you to these concepts; and in the following chapter, we’ll make use of them for managing a cluster of microservices.
Pods
A pod is a grouping of one or more Docker containers (like a pod of whales?). A typical deployment of a pod, however, will often be oneto-one with a Docker container. If you have sidecar, ambassador, or adapter deployments that must always be co-located with the application, a pod is the way to group them. This abstraction is also a way to guarantee container affinity (i.e., Docker container A will always be deployed alongside Docker container B on the same host).
Kubernetes orchestrates, schedules, and manages pods. When we refer to an application running inside of Kubernetes, it’s running within a Docker container inside of a pod. A pod is given its own IP address, and all containers within the pod share this IP (which is different from plain Docker, where each container gets an IP address). When volumes are mounted to the pod, they are also shared between the individual Docker containers running in the pod.
One last thing to know about pods: they are fungible. This means they can disappear at any time (either because the service crashed or the cluster killed it). They are not like a VM, which you care for and nurture. Pods can be destroyed at any point. This falls within our expectation in a microservice world that things will (and do) fail, so we are strongly encouraged to write our microservices with this premise in mind. This is an important distinction as we talk about some of the other concepts in the following sections.
Labels
Labels are simple key/value pairs that we can assign to pods like release=stable or tier=backend. Pods (and other resources, but we’ll focus on pods) can have multiple labels that group and categorize in a loosely coupled fashion, which becomes quite apparent the more you use Kubernetes. It’s not a surprise that Google has identified such simple constructs from which we can build powerful clusters at scale. After we’ve labeled our pods, we can use label selectors to find which pods belong in which group. For example, if we had some pods labeled tier=backend and others labeled tier=fron tend, using a label selector expression of tier != frontend. We can select all of the pods that are not labeled “frontend.” Label selectors are used under the covers for the next two concepts: replication controllers and services.
Replication Controllers
When talking about running microservices at scale, we will probably be talking about multiple instances of any given microservice. Kubernetes has a concept called ReplicationController that manages the number of replicas for a given set of microservices. For example, let’s say we wanted to manage the number of pods labeled with tier=backend and release=stable. We could create a replication controller with the appropriate label selector and then be able to control the number of those pods in the cluster with the value of replica on our ReplicationController. If we set the replica count equal to 10, then Kubernetes will reconcile its current state to reflect 10 pods running for a given ReplicationController. If there are only five running at the moment, Kubernetes will spin up five more. If there are 20 running, Kubernetes will kill 10 (which 10 it kills is nondeterministic, as far as your app is concerned). Kubernetes will do whatever it needs to converge with the desired state of 10 replicas. You can imagine controlling the size of a cluster very easily with a ReplicationController. We will see examples of Rep licationController in action in the next chapter. Services
The last Kubernetes concept we should understand is the Kubernetes Service. ReplicationControllers can control the number of replicas of a service we have. We also saw that pods can be killed (either
Kubernetes
crash on their own, or be killed, maybe as part of a ReplicationController scale-down event). Therefore, when we try to communicate with a group of pods, we should not rely on their direct IP addresses (each pod will have its own IP address) as pods can come and go. What we need is a way to group pods to discover where they are, how to communicate with them, and possibly load balance against them. That’s exactly what the Kubernetes Service does. It allows us to use a label selector to group our pods and abstract them with a single virtual (cluster) IP that we can then use to discover them and interact with them. We’ll show concrete examples in the next chapter.
With these simple concepts, pods, labels, ReplicationControllers, and services, we can manage and scale our microservices the way Google has learned to (or learned not to). It takes many years and many failures to identify simple solutions to complex problems, so we highly encourage you to learn these concepts and experience the power of managing containers with Kubernetes for your microservices.