The Kubernetes Book by Nigel Poulton & Pushkar Joglekar, chapter name Kubernetes primer

Kubernetes primer

Kubernetes primer

This chapter is split into two main sections.

• Kubernetes background – where it came from etc.

• Kubernetes as the Operating System of the cloud

Kubernetes background

Kubernetes is an application orchestrator. For the most part, it orchestrates containerized cloud-native microservices apps. How about that for a sentence full of buzzwords!

You’ll come across those terms a lot as you work with Kubernetes, so let’s take a minute to explain what each one means.

What is an orchestrator

An orchestrator is a system that deploys and manages applications. It can deploy your applications and dynamically respond to changes. For example, Kubernetes can:

• deploy your application

• scale it up and down dynamically according to demand

• self-heal it when things break

• perform zero-downtime rolling updates and rollbacks

• and more

And the best part about Kubernetes… it can do all of that without you having to supervise or get involved in decisions. Obviously you have to set things up in the first place, but once you’ve done that, you can sit back and let Kubernetes work its magic.

What is a containerised app

A containerized application is an app that runs in a container.

Before we had containers, applications ran on physical servers or in virtual machines. Containers are the next iteration of how we package and run our apps, and they’re faster, more lightweight, and more suited to modern business requirements than servers and virtual machines.

Think of it this way:

• Applications ran on physical servers in the age of open-system (roughly the 1980s and 1990s)

• Applications ran in virtual machines in the age of virtual machines (2000s and into the 2010s)

• Applications run in containers in the cloud-native era (now) While Kubernetes can orchestrate other workload types, including virtual machines and serverless functions, it’s most commonly used to orchestrate containerised apps.

What is a cloud-native app

A cloud-native application is an application that is designed to meet modern business demands (auto-scaling, self-healing, rolling updates etc.) and can run on Kubernetes.

I feel like it’s important to be clear that cloud-native apps are not applications that will only run on a public cloud. Yes, they absolutely can run on a public cloud, but they can run anywhere that you have Kubernetes –

even your on-premises data center.

What is a microservices app

A microservices app is a business application that is built from lots of small specialised parts that communicate and form a meaningful application. For example, you might have an e-commerce app that comprises all of the following small specialised components:

• web front-end

• catalog service

• shopping cart

• authentication service

• logging service

• persistent store

• more…

Each of these individual services is called a microservice. Typically, each can be coded and looked after by a different team, and each can have its own release cadence and can be scaled independently of all others.

For example, you can patch and scale the logging microservice without affecting any of the other application components.

Building applications this way is an important aspect of a cloud-native application.

With all of this in mind, let’s re-phrase that definition that was full of buzzwords…

Kubernetes deploys and manages (orchestrates) applications that are packaged and run as containers (containerized) and that are built in ways (cloud-native microservices) that allow them to scale, self-heal, and be updated inline with modern business requirements.

We’ll talk about these concepts a lot throughout the book, but for now, this should help you understand some of the main industry buzzwords.

Where did Kubernetes come from

Let’s start from the beginning…

Amazon Web Services (AWS) changed the world when it brought us modern-day cloud computing. Since then, everyone else has been trying to catch-up.

One of the companies trying to catch-up was Google. Google has its own very good cloud, and needs a way to abstract the value of AWS, and make it easier for potential customers to use the Google Cloud.





Google has boatloads of experience working with containers at scale. For example, huge Google applications, such as Search and Gmail, have been running at extreme scale on containers for a lot of years – since way before Docker brought us easy-to-use containers. To orchestrate and manage these containerised apps, Google had a couple of in-house proprietary systems. They took the lessons learned from these in-house systems, and created a new platform called Kubernetes, and donated it to the newly formed Cloud Native Computing Foundation (CNCF) in 2014 as an open-source project.

Figure 1.1

Since then, Kubernetes has become the most important cloud-native technology on the planet.

Like many of the modern cloud-native projects, it’s written in Go (Golang), it’s built in the open on GitHub (at kubernetes/kubernetes), it’s actively discussed on the IRC channels, you can follow it on Twitter (@kubernetesio), and is a pretty good slack channel. There are also regular meetups and conferences all over the planet.

Kubernetes and Docker

Kubernetes and Docker are complementary technologies. For example, it’s common to develop your applications with Docker and use Kubernetes to orchestrate them in production.

In this model, you write your code in your favourite languages, then use Docker to package it, test it, and ship it. But the final steps of deploying and running it is handled by Kubernetes.

At a high-level, you might have a Kubernetes cluster with 10 nodes to run your production applications. Behind the scenes, each node is running Docker as its container runtime. This means that Docker is the low-level technology that starts and stops the containerised applications. Kubernetes is the higher-level technology that looks after the bigger picture, such as; deciding which nodes to run containers on, deciding when to scale up or down, and executing updates.

Figure 1.2 shows a simple Kubernetes cluster with some nodes using Docker as the container runtime.

Figure 1.2

As can be seen in Figure 1.2, Docker isn’t the only container runtime that Kubernetes supports. In fact, Kubernetes has a couple of features that abstract the container runtime (make it interchangeable):



1. The Container Runtime Interface (CRI) is an abstraction layer that standardizes the way 3rd-party container runtimes interface with Kubernetes. It allows the container runtime code to exist outside of Kubernetes, but interface with it in a supported and standardized way.

2. Runtime Classes is a new feature that was introduced in Kubernetes 1.12 and promoted to beta in 1.14.

It allows for different classes of runtimes. For example, the gVisor or Kata Containers runtimes might provide better workload isolation than the Docker and containerd runtimes.

At the time of writing, containerd is catching up to Docker as the most commonly used container runtime in Kubernetes. It is a stripped-down version of Docker with just the stuff that Kubernetes needs. It’s pronounced container dee.

While all of this is interesting, it’s low-level stuff that shouldn’t impact your Kubernetes learning experience. For example, whichever container runtime you use, the regular Kubernetes commands and patterns will continue to work as normal.

What about Kubernetes vs Docker Swarm

In 2016 and 2017 we had the orchestrator wars where Docker Swarm, Mesosphere DCOS, and Kubernetes competed to become the de-facto container orchestrator. To cut a long story short, Kubernetes won.

It’s true that Docker Swarm and other container orchestrators still exist, but their development and market-share are small compared to Kubernetes.

Kubernetes and Borg: Resistance is futile!

There’s a good chance you’ll hear people talk about how Kubernetes relates to Google’s Borg and Omega systems.

As previously mentioned, Google has been running containers at scale for a long time – apparently crunching through billions of containers a week. So yes, Google has been running things like search, Gmail, and GFS on lots of containers for a very long time.

Orchestrating these containerised apps was the job of a couple of in-house Google technologies called Borg and Omega. So, it’s not a huge stretch to make the connection with Kubernetes – all three are in the game of orchestrating containers at scale, and they’re all related to Google.

However, it’s important to understand that Kubernetes is not an open-sourced version of Borg or Omega. It’s more like Kubernetes shares its DNA and family history with Borg and Omega. A bit like this… In the beginning was Borg, and Borg begat Omega. Omega knew the open-source community and begat her Kubernetes ;-) Figure 1.3 - Shared DNA



The point is, all three are separate, but all three are related. In fact, some of the people who built Borg and Omega are involved in building Kubernetes. So, although Kubernetes was built from scratch, it leverages much of what was learned at Google with Borg and Omega.

As things stand, Kubernetes is an open-source project donated to the CNCF in 2014, it’s licensed under the Apache 2.0 license, version 1.0 shipped way back in July 2015, and at-the-time-of-writing, we’ve already passed version 1.16.

Kubernetes – what’s in the name

The name Kubernetes (koo-ber-net-eez) comes from the Greek word meaning Helmsman – the person who steers a seafaring ship. This theme is reflected in the logo.

Figure 1.4 - The Kubernetes logo

Apparently, some of the people involved in the creation of Kubernetes wanted to call it Seven of Nine. If you know your Star Trek, you’ll know that Seven of Nine is a female Borg rescued by the crew of the USS Voyager under the command of Captain Kathryn Janeway. Sadly, copyright laws prevented it from being called Seven of Nine. However, the seven spokes on the logo are a tip-of-the-hat to Seven of Nine.

One last thing about the name before moving on. You’ll often see Kubernetes shortened to K8s (pronounced

“Kates”). The number 8 replaces the 8 characters between the K and the s – great for tweets and lazy typists like me ;-)

The operating system of the cloud

Kubernetes has emerged as the de facto platform for deploying and managing cloud-native applications. In many ways, it’s like an operating system (OS) for the cloud. Consider this:

• You install a traditional OS (Linux or Windows) on a server, and the OS abstracts the physical server’s resources and schedules processes etc.

• You install Kubernetes on a cloud, and it abstracts the cloud’s resources and schedules the various microservices of cloud-native applications

In the same way that Linux abstracts the hardware differences of different server platforms, Kubernetes abstracts the differences between different private and public clouds. Net result… as long as you’re running Kubernetes, it doesn’t matter if the underlying systems are on premises in your own data center, edge clusters, or in the public cloud.

With this in mind, Kubernetes enables a true hybrid cloud, allowing you to seamlessly move and balance workloads across multiple different public and private cloud infrastructures. You can also migrate to and from different clouds, meaning you can choose a cloud today and not have to stick with that decision for the rest of your life.


Cloud scale

Generally speaking, cloud-native microservices applications make our previous scalability challenges look easy

– we’ve just said that Google goes through billions of containers per week!

That’s great, but most of us aren’t the size of Google. What about the rest of us?

Well… as a general rule, if your legacy apps have hundreds of VMs, there’s a good chance your containerized cloud-native apps will have thousands of containers. With this in mind, we desperately need help managing them.

Say hello to Kubernetes.

Also, we live in a business and technology world that is increasingly fragmented and in a constant state of disruption. With this in mind, we desperately need a framework and platform that is widely accepted and hides the complexity.

Again, say hello to Kubernetes.

Application scheduling

A typical computer is a collection of CPU, memory, storage, and networking. But modern operating systems have done a great job abstracting most of that. For example, how many developers care which CPU core or exact memory address their application uses? Not many, we let the OS take care of things like that. And it’s a good thing, it’s made the world of application development a far friendlier place.

Kubernetes does a similar thing with cloud and data center resources. At a high-level, a cloud or data center is a pool of compute, network and storage. Kubernetes abstracts it. This means we don’t have hard code which node or storage volume our applications run on, we don’t even have to care which cloud they run on – we let Kubernetes take care of that. Gone are the days of naming your servers, mapping storage volumes in a spreadsheet, and otherwise treating your infrastructure assets like pets. Systems like Kubernetes don’t care. Gone are the days of taking your app and saying “Run this part of the app on this exact node, with this IP, on this specific volume…“. In the cloud-native Kubernetes world, we just say “Hey Kubernetes, here’s an app. Please deploy it and make sure it keeps running…“.

A quick analogy…

Consider the process of sending goods via a courier service.

You package the goods in the courier’s standard packaging, put a label on it, and hand it over to the courier. The courier is responsible for everything. This includes; all the complex logistics of which planes and trucks it goes on, which highways to use, and who the drivers should be etc. They also provide services that let you do things like track your package and make delivery changes. The point is, the only thing that you have to do is package and label the goods, and the courier abstracts everything else and takes care of scheduling and other logistics.

It’s the same for apps on Kubernetes. You package the app as a container, give it a declarative manifest, and let Kubernetes take care of deploying it and keeping it running. You also get a rich set of tools and APIs that let you introspect (observe and examine) your app. It’s a beautiful thing.


Chapter summary

Kubernetes was created by Google based on lessons learned running containers at scale for many years. It was donated to the community as an open-source project and is now the industry standard API for deploying and managing cloud-native applications. It runs on any cloud or on-premises data center and abstracts the underlying infrastructure. This allows you to build hybrid clouds, as well as migrate easily between cloud platforms. It’s open-sourced under the Apache 2.0 license and lives within the Cloud Native Computing Foundation (CNCF).


Kubernetes is a fast-moving project under active development. But don’t let this put you off – embrace it. Change is the new normal.

To help you keep up-to-date, I suggest you subscribe to a couple of my YouTube channels:

• #KubernetesMoment: a short weekly video discussing or explaining something about Kubernetes

• Kubernetes this Month: A monthly roundup of all the important things going on in the Kubernetes world You should also check out:

• My website at

• My video training courses at and

• My hands-on learning at MSB (

• KubeCon and your local Kubernetes and cloud-native meetups

2: Kubernetes principles of operation

In this chapter, you’ll learn about the major components required to build a Kubernetes cluster and deploy an app. The aim is to give you an overview of the major concepts. So don’t worry if you don’t understand everything straight away, we’ll cover most things again as we progress through the book.

We’ll divide the chapter as follows:

• Kubernetes from 40K feet

• Masters and nodes

• Packaging apps

• Declarative configuration and desired state

• Pods

• Deployments

• Services

Kubernetes from 40K feet

At the highest level, Kubernetes is two things:

• A cluster for running applications

• An orchestrator of cloud-native microservices apps

Kubernetes as a cluster

Kubernetes is like any other cluster – a bunch of nodes and a control plane. The control plane exposes an API, has a scheduler for assigning work to nodes, and state is recorded in a persistent store. Nodes are where application services run.

It can be useful to think of the control plane as the brains of the cluster, and the nodes as the muscle. In this analogy, the control plane is the brains because it implements all of the important features such as auto-scaling and zero-downtime rolling updates. The nodes are the muscle because they do the every-day hard work of executing application code.

Kubernetes as an orchestrator

Orchestrator is just a fancy word for a system that takes care of deploying and managing applications.

Let’s look at a quick analogy.

In the real world, a football (soccer) team is made of individuals. No two individuals are the same, and each has a different role to play in the team – some defend, some attack, some are great at passing, some tackle, some





shoot… Along comes the coach, and he or she gives everyone a position and organizes them into a team with a purpose. We go from Figure 2.1 to Figure 2.2.

Figure 2.1

Figure 2.2

The coach also makes sure the team maintains its formation, sticks to the game-plan, and deals with any injuries and other changes in circumstance.

Well guess what… microservices apps on Kubernetes are the same.

Stick with me on this…

We start out with lots of individual specialised services. Some serve web pages, some do authentication, some perform searches, others persist data. Kubernetes comes along – a bit like the coach in the football analogy –-

organizes everything into a useful app and keeps things running smoothly. It even responds to events and other changes.

In the sports world we call this coaching. In the application world we call it orchestration. Kubernetes orchestrates cloud-native microservices applications.


How it works

To make this happen, you start out with an app, package it up and give it to the cluster (Kubernetes). The cluster is made up of one or more masters and a bunch of nodes.

The masters, sometimes called heads or head nodes, are in-charge of the cluster. This means they make the scheduling decisions, perform monitoring, implement changes, respond to events, and more. For these reasons, we often refer to the masters as the control plane.

The nodes are where application services run, and we sometimes call them the data plane. Each node has a reporting line back to the masters, and constantly watches for new work assignments.

To run applications on a Kubernetes cluster we follow this simple pattern: 1. Write the application as small independent microservices in our favourite languages.

2. Package each microservice in its own container.

3. Wrap each container in its own Pod.

4. Deploy Pods to the cluster via higher-level controllers such as; Deployments, DaemonSets, StatefulSets, CronJobs etc.

Now then… we’re still near the beginning of the book and you’re not expected to know what all of this means yet. However, at a high-level, Deployments offer scalability and rolling updates, DaemonSets run one instance of a service on every node in the cluster, StatefulSets are for stateful application components, and CronJobs are for short-lived tasks that need to run at set times. There are more than these, but these will do for now.

Kubernetes likes to manage applications declaratively. This is a pattern where you describe how you want your application to look and feel in a set of YAML files. You POST these files to Kubernetes, then sit back while Kubernetes makes it all happen.

But it doesn’t stop there. Because the declarative pattern tells Kubernetes how an application should look, Kubernetes can watch it and make sure things don’t stray from what you asked for. If something isn’t as it should be, Kubernetes tries to fix it.

That’s the big picture. Let’s dig a bit deeper.

Masters and nodes

A Kubernetes cluster is made of masters and nodes. These are Linux hosts that can be virtual machines (VM), bare metal servers in your data center, or instances in a private or public cloud.

Masters (control plane)

A Kubernetes master is a collection of system services that make up the control plane of the cluster.

The simplest setups run all the master services on a single host. However, this is only suitable for labs and test environments. For production environments, multi-master high availability (HA) is a must have. This is why the major cloud providers implement HA masters as part of their hosted Kubernetes platforms such as Azure Kubernetes Service (AKS), AWS Elastic Kubernetes Service (EKS), and Google Kubernetes Engine (GKE).

Generally speaking, running 3 or 5 replicated masters in an HA configuration is recommended.


It’s also considered a good practice not to run user applications on masters. This allows masters to concentrate entirely on managing the cluster.

Let’s take a quick look at the different master services that make up the control plane.

The API server

The API server is the Grand Central Station of Kubernetes. All communication, between all components, must go through the API server. We’ll get into the detail later in the book, but it’s important to understand that internal system components, as well as external user components, all communicate via the same API.

It exposes a RESTful API that you POST YAML configuration files to over HTTPS. These YAML files, which we sometimes call manifests, contain the desired state of your application. This desired state includes things like; which container image to use, which ports to expose, and how many Pod replicas to run.

All requests to the API Server are subject to authentication and authorization checks, but once these are done, the config in the YAML file is validated, persisted to the cluster store, and deployed to the cluster.

The cluster store

The cluster store is the only stateful part of the control plane, and it persistently stores the entire configuration and state of the cluster. As such, it’s a vital component of the cluster – no cluster store, no cluster.

The cluster store is currently based on etcd, a popular distributed database. As it’s the single source of truth for the cluster, you should run between 3-5 etcd replicas for high-availability, and you should provide adequate ways to recover when things go wrong.

On the topic of availability, etcd prefers consistency over availability. This means that it will not tolerate a split-brain situation and will halt updates to the cluster in order to maintain consistency. However, if etcd becomes unavailable, applications running on the cluster should continue to work, you just won’t be able to update anything.

As with all distributed databases, consistency of writes to the database is vital. For example, multiple writes to the same value originating from different nodes needs to be handled. etcd uses the popular RAFT consensus algorithm to accomplish this.

The controller manager

The controller manager implements all of the background control loops that monitor the cluster and respond to events.

It’s a controller of controllers, meaning it spawns all of the independent control loops and monitors them.

Some of the control loops include; the node controller, the endpoints controller, and the replicaset controller. Each one runs as a background watch-loop that is constantly watching the API Server for changes -– the aim of the game is to ensure the current state of the cluster matches the desired state (more on this shortly).

The logic implemented by each control loop is effectively this: 1. Obtain desired state

2. Observe current state

3. Determine differences


4. Reconcile differences

This logic is at the heart of Kubernetes and declarative design patterns.

Each control loop is also extremely specialized and only interested in its own little corner of the Kubernetes cluster. No attempt is made to over-complicate things by implementing awareness of other parts of the system

– each control loop takes care of its own business and leaves everything else alone. This is key to the distributed design of Kubernetes and adheres to the Unix philosophy of building complex systems from small specialized parts.

Note: Throughout the book we’ll use terms like control loop, watch loop, and reconciliation loop to mean the same thing.

The scheduler

At a high level, the scheduler watches the API server for new work tasks and assigns them to appropriate healthy nodes. Behind the scenes, it implements complex logic that filters out nodes incapable of running the task, and then ranks the nodes that are capable. The ranking system is complex, but the node with the highest-ranking score is selected to run the task.

When identifying nodes that are capable of running a task, the scheduler performs various predicate checks. These include; is the node tainted, are there any affinity or anti-affinity rules, is the required network port available on the node, does the node have sufficient free resources etc. Any node incapable of running the task is ignored, and the remaining nodes are ranked according to things such as; does the node already have the required image, how much free resource does the node have, how many tasks is the node already running. Each criterion is worth points, and the node with the most points is selected to run the task.

If the scheduler cannot find a suitable node, the task cannot be scheduled and is marked as pending.

The scheduler isn’t responsible for running tasks, just picking the nodes a task will run on.

The cloud controller manager

If you’re running your cluster on a supported public cloud platform, such as AWS, Azure, GCP, DO, IBM

Cloud etc. your control plane will be running a cloud controller manager. Its job is to manage integrations with underlying cloud technologies and services such as, instances, load-balancers, and storage. For example, if your application asks for an internet facing load-balancer, the cloud controller manager is involved in provisioning an appropriate load-balancer on your cloud platform.

Control Plane summary

Kubernetes masters run all of the cluster’s control plane services. Think of it as the brains of the cluster where all the control and scheduling decisions are made. Behind the scenes, a master is made up of lots of small specialized control loops and services. These include the API server, the cluster store, the controller manager, and the scheduler.

The API Server is the front-end into the control plane and all instructions and communication must go through it. By default, it exposes a RESTful endpoint on port 443.

Figure 2.3 shows a high-level view of a Kubernetes master (control plane).





Figure 2.3 - Kubernetes Master


Nodes are the workers of a Kubernetes cluster. At a high-level they do three things: 1. Watch the API Server for new work assignments

2. Execute new work assignments

3. Report back to the control plane (via the API server)

As we can see from Figure 2.4, they’re a bit simpler than masters.

Figure 2.4 - Kubernetes Node (formerly Minion)

Let’s look at the three major components of a node.


The Kubelet is the star of the show on every node. It’s the main Kubernetes agent, and it runs on every node in the cluster. In fact, it’s common to use the terms node and kubelet interchangeably.


When you join a new node to a cluster, the process installs kubelet onto the node. The kubelet is then responsible for registering the node with the cluster. Registration effectively pools the node’s CPU, memory, and storage into the wider cluster pool.

One of the main jobs of the kubelet is to watch the API server for new work assignments. Any time it sees one, it executes the task and maintains a reporting channel back to the control plane.

If a kubelet can’t run a particular task, it reports back to the master and lets the control plane decide what actions to take. For example, if a Kubelet cannot execute a task, it is not responsible for finding another node to run it on. It simply reports back to the control plane and the control plane decides what to do.

Container runtime

The Kubelet needs a container runtime to perform container-related tasks -– things like pulling images and starting and stopping containers.

In the early days, Kubernetes had native support for a few container runtimes such as Docker. More recently, it has moved to a plugin model called the Container Runtime Interface (CRI). At a high-level, the CRI masks the internal machinery of Kubernetes and exposes a clean documented interface for 3rd-party container runtimes to plug into.

There are lots of container runtimes available for Kubernetes. One popular example is cri-containerd. This is a community-based open-source project porting the CNCF containerd runtime to the CRI interface. It has a lot of support and is replacing Docker as the most popular container runtime used in Kubernetes.

Note: containerd (pronounced “container-dee”) is the container supervisor and runtime logic stripped out from the Docker Engine. It was donated to the CNCF by Docker, Inc. and has a lot of community support. Other CRI-compliant container runtimes exist.


The last piece of the node puzzle is the kube-proxy. This runs on every node in the cluster and is responsible for local cluster networking. For example, it makes sure each node gets its own unique IP address, and implements local IPTABLES or IPVS rules to handle routing and load-balancing of traffic on the Pod network.

Kubernetes DNS

As well as the various control plane and node components, every Kubernetes cluster has an internal DNS service that is vital to operations.

The cluster’s DNS service has a static IP address that is hard-coded into every Pod on the cluster, meaning all containers and Pods know how to find it. Every new service is automatically registered with the cluster’s DNS

so that all components in the cluster can find every Service by name. Some other components that are registered with the cluster DNS are StatefulSets and the individual Pods that a StatefulSet manages.

Cluster DNS is based on CoreDNS (

Now that we understand the fundamentals of masters and nodes, let’s switch gears and look at how we package applications to run on Kubernetes.



Packaging apps for Kubernetes

For an application to run on a Kubernetes cluster it needs to tick a few boxes. These include: 1. Packaged as a container

2. Wrapped in a Pod

3. Deployed via a declarative manifest file

It goes like this… You write an application service in a language of your choice. You build it into a container image and store it in a registry. At this point, the application service is containerized.

Next, you define a Kubernetes Pod to run the containerized application. At the kind of high level we’re at, a Pod is just a wrapper that allows a container to run on a Kubernetes cluster. Once you’ve defined the Pod, you’re ready to deploy it on the cluster.

It is possible to run a standalone Pod on a Kubernetes cluster. But the preferred model is to deploy all Pods via higher-level controllers. The most common controller is the Deployment. It offers scalability, self-healing, and rolling updates. You define Deployments in YAML manifest files that specifies things like; which image to use and how many replicas to deploy.

Figure 2.5 shows application code packaged as a container, running inside a Pod, managed by a Deployment controller.

Figure 2.5

Once everything is defined in the Deployment YAML file, you POST it to the API Server as the desired state of the application and let Kubernetes implement it.

Speaking of desired state…

The declarative model and desired state

The declarative model and the concept of desired state are at the very heart of Kubernetes.

In Kubernetes, the declarative model works like this:

1. Declare the desired state of an application (microservice) in a manifest file 2. POST it to the API server