Skip to content

Volume ITechnology

14.0 — The Whole Picture ​

A customer on shop.example.com taps Pay. About 80 milliseconds later the page says "Order confirmed".

In those 80 milliseconds, the request passed through a virtual network inside a virtual machine inside a physical server, was rewritten by firewall rules it never saw, crossed a virtual cable into a sealed-off copy of the network, and was read by a program that believes it is the only process on its machine. That program reads files from a stack of read-only layers downloaded from a registry, and it is allowed to use exactly half a gigabyte of memory and not a byte more. None of the people who built that program configured any of this by hand. They wrote a few short files, and a cluster made it so.

Every layer in that sentence is a chapter of this Part. This page follows the one request all the way down, layer by layer, so that you have the map in your head before any single layer is taken apart. Each layer below names the chapter that explains it, and the chapters it depends on from earlier in the book.

1. One request, from the top to the bottom ​

The figure is the whole Part on one page. The request travels down the left; the right says which chapter explains each step.

① Browser asks DNS for shop.example.com, connects over HTTPSPart 5 (5.5, 5.7)② Azure load balancer → the cluster's gateway pods14.4.1, 14.3.6③ HTTPRoute picks web; nginx proxies /api/ to checkout-api14.3.6, 14.4.3④ Service address rewritten to one ready pod's address14.3.6, 14.3.2⑤ Packet crosses to the pod's node, through a veth into its netns14.3.4, 14.1.4⑥ A normal Linux process, PID 1 in its own namespaces, reads it14.1.3⑦ Its files: image layers stacked by OverlayFS; its limits: a cgroup14.2.2, 14.1.4⑧ One Linux kernel shared by every container on this nodePart 2, 14.1.3⑨ That kernel is a guest: the node is a VM on Hyper-V14.1.2⑩ A physical server; the code runs natively on its processorPart 1 (1.5, 1.6)Purple: the cluster's front door · Blue: Kubernetes networking · Green: the container · Amber, red: what it runs on
Figure 1 — One tap on "Pay", ten layers deep. Read top to bottom. Every layer is software pretending to be something simpler for the layer above, and every one of them is something you will be able to explain by the end of this Part.

Walk through it once, slowly, with the question "what is this layer pretending, and for whom?" in mind. That question is the thread through the whole Part.

① The browser and the internet. The name shop.example.com is turned into an address by DNS (5.5), and the connection is encrypted with TLS (5.7). Nothing here knows Kubernetes exists. The address belongs to an Azure load balancer.

② The front door. The load balancer passes the connection to one of the cluster's gateway pods, which hold the certificate and end the encryption (Chapters 14.3.6 and 14.4.1). This is the only part of the cluster with a public address. Everything below it is reachable only from inside.

③ Routing by rule. A small object called an HTTPRoute, written by the shop's team, says "this hostname goes to the web service". nginx in a web pod sees the path starts with /api/ and passes the request on to checkout-api (Chapter 14.4.3 builds this exact arrangement).

④ A name that is not a machine. nginx sends the request to the address of the checkout-api Service. No machine has that address. Rules written into the node's kernel by kube-proxy catch the packet and rewrite its destination to the address of one of the ready checkout-api pods, chosen at random for this connection (Chapter 14.3.6). The Service pretends to be one server, for the benefit of callers who should not have to know there are three. You watched this spreading happen in Chapter 14.3.2.

⑤ Into the pod. The chosen pod may be on another node, so the packet crosses the cluster's pod network to that node (Chapter 14.3.4), then goes through a veth pair, a virtual network cable, into the pod's own network namespace: a private copy of the network stack with its own interfaces and its own port numbers. You build exactly this with four commands in Chapter 14.1.4.

⑥ An ordinary process that thinks it is alone. The packet reaches a socket held by a Node.js process. That process is PID 1 in its own process list, has its own hostname, and sees only its own network. To the host's kernel it is a perfectly ordinary process with an ordinary process ID, running at full speed with no layer in between (Chapter 14.1.3). The kernel simply keeps separate books for it.

⑦ Its files and its limits. The program's code, its Node runtime and its libraries come from image layers: read-only directories downloaded from the registry by their digest (Chapter 14.2.2) and stacked by OverlayFS into one view of / (Chapter 14.1.4). The layers were produced by a Dockerfile (Chapter 14.2.3). How much memory and processor it may use is written in its cgroup, and going over the memory limit gets it killed on the spot (Chapters 14.1.4 and 14.3.7).

⑧ One shared kernel. Every container on this node, from every team, uses this one Linux kernel. That sharing is the whole reason containers are small and start in milliseconds, and it is also the reason they are a weaker wall than a virtual machine (Chapter 14.1.1). The kernel itself is the subject of Part 2.

⑨ The kernel is itself a guest. The node is an Azure virtual machine. Its kernel believes it owns a processor and memory; in fact it is one of several guests on a physical server, run by the Hyper-V hypervisor (Chapter 14.1.2). The VM wall separates you from Azure's other customers. The container wall separates your services from each other. Two walls, two jobs.

⑩ Real hardware. At the bottom, the program's instructions run directly on a real processor (1.5), using real memory through two levels of address translation (1.6, Chapter 14.1.2), and they run at nearly full speed, because every layer above managed to stay out of the way of ordinary instructions.

2. The second timeline: how all of that got there ​

The request took 80 milliseconds. Setting up the layers it passed through took minutes, and happened earlier, without any person running a container by hand. Here is that second timeline, from a developer's commit to the running process in step ⑥:

  1. A commit is merged. A pipeline builds the image from the Dockerfile with BuildKit (Chapters 14.2.1 and 14.2.3), and pushes its layers to Azure Container Registry. The registry names the image by digest (Chapter 14.2.2).
  2. The pipeline changes one line in a Kustomize overlay, the digest, and runs kubectl apply (Chapter 14.4.3).
  3. The API server checks the request and writes the new desired state into etcd, the cluster's database. That is all apply does (Chapter 14.3.3).
  4. The Deployment's controller notices the change and creates a new ReplicaSet, which creates new pod objects (Chapter 14.3.5).
  5. The scheduler picks a node for each pod, using the requests in the manifest (Chapters 14.3.3 and 14.3.7).
  6. The kubelet on that node asks containerd to pull the image and start the container; containerd hands the job to runc, which creates the namespaces, places the process in its cgroup, swaps its root filesystem and runs the program (Chapters 14.3.4, 14.2.1, and the version you write yourself in 14.1.4).
  7. The readiness probe passes, and only then does the Service start sending requests like ours to it. An old pod is told to shut down, and the rollout moves on to the next pod (Chapters 14.3.2 and 14.3.5).

Notice who did what. People wrote files: a Dockerfile, a few manifests, an overlay. Programs did everything else, and they keep doing it. If the node in step 5 dies tonight, steps 4 to 7 happen again on another node with nobody involved. That self-repair is the reason Kubernetes exists, and Chapter 14.3.1 starts from it.

3. What this Part relies on from earlier in the book ​

Containers are built entirely from operating-system and networking features you may already have met. If a word below is unfamiliar, the linked chapter is short to revisit, and each later chapter in this Part links back again at the point it needs it.

IdeaUsed forChapter
Kernel mode and user modeHow a VM traps, what a system call is2.1
Processes, PIDs, signalsPID 1, SIGTERM, zombies2.2
SchedulingCPU limits as throttling2.3
Virtual memory, page tablesMemory limits, nested paging2.5
File systems, mountsOverlayFS, volumes2.6
Linux basicsEvery command in the labs2.8
VMs vs containers, the overviewChapter 14.1.2 goes deeper2.9
IP addresses, subnetsPod and Service addresses5.3.1
NATHow containers reach out, how ports publish5.3.3
PortsPort mapping, Services5.4.1
DNSService names, CoreDNS5.5
Cloud networking, AzureAKS networking, identity13.2, 13.5

4. The order of the pages, and why it goes this way ​

The pages climb the stack from the bottom, because each layer only makes sense once the one under it is solid.

  • 14.1 Foundations starts with the problem containers solve (14.1.1), then the alternative they are measured against, virtual machines (14.1.2), then what a container is made of (14.1.3), and then you build one from nothing (14.1.4). After 14.1, the word "container" holds no mystery.
  • 14.2 Docker is the tool on one machine: its parts (14.2.1), images and registries (14.2.2), the Dockerfile (14.2.3), running containers (14.2.4), several at once with Compose (14.2.5), and what changes on a Mac or Windows laptop (14.2.6).
  • 14.3 Kubernetes is many machines: why one machine is not enough (14.3.1), a real cluster at your keyboard (14.3.2), then its parts one by one (14.3.3 to 14.3.8), and the field guide for when things fail (14.3.9).
  • 14.4 Kubernetes on Azure is the managed version, AKS (14.4.1), wired to the rest of Azure (14.4.2), and one application across three environments (14.4.3).
  • 14.5 is how to explain all of it to someone else.

Two pages are labs you do at a keyboard rather than read: 14.1.4 on any Linux machine, and 14.3.2 on any laptop with Docker. They are the two pages that turn the rest from something you have read into something you have seen.

Next: 14.1.1 begins at the beginning, with a deployment that fails at 11 p.m. because of one shared library, and the forty-five years of attempts to make sure that never happens again.