kubernetes_5
kubernetes_5
that applications A and B read some of the same files. In addition, they also
share the underlying layer with container C. But if all three containers have
access to the same files, how can they be completely isolated from each
other? Are changes that application A makes to a file stored in the shared
layer not visible to application B? They aren’t. Here’s why.
When you delete a file, it is only marked as deleted in the read/write layer,
but it’s still present in one or more of the layers below. What follows is that
deleting files never reduces the size of the image.
WARNING
Figure 2.9 If a container requires specific kernel features or modules, it may not work
everywhere
Container B requires a specific kernel module to run properly. This module is
loaded in the kernel in the first computer, but not in the second. You can run
the container image on the second computer, but it will break when it tries to
use the missing module.
And it’s not just about the kernel and its modules. It should also be clear that
a containerized app built for a specific hardware architecture can only run on
computers with the same architecture. You can’t put an application compiled
for the x86 CPU architecture into a container and expect to run it on an
ARM-based computer just because Docker is available there. For this you
would need a VM to emulate the x86 architecture.
Installing Docker
The Docker Platform consists of many components, but you only need to
install Docker Engine to run containers. If you use macOS or Windows,
install Docker Desktop. For details, follow the instructions at
http://docs.docker.com/install.
Note
Docker Desktop for Windows can run either Windows or Linux containers.
Make sure that you configure it to use Linux containers, as all the examples
in this book assume that’s the case.
After the installation is complete, you use the docker CLI tool to run Docker
commands. Let’s try pulling and running an existing image from Docker
Hub, the public image registry that contains ready-to-use container images
for many well-known software packages. One of them is the busybox image,
which you’ll use to run a simple echo "Hello world" command in your first
container.
If you’re unfamiliar with busybox, it’s a single executable file that combines
many of the standard UNIX command-line tools, such as echo, ls, gzip, and
so on. Instead of the busybox image, you could also use any other full-
fledged OS container image like Fedora, Ubuntu, or any other image that
contains the echo executable file.
Once you’ve got Docker installed, you don’t need to download or install
anything else to run the busybox image. You can do everything with a single
docker run command, by specifying the image to download and the
command to run in it. To run the Hello World container, the command and its
output are as follows:
$ docker run busybox echo "Hello World"
Unable to find image 'busybox:latest' locally #A
latest: Pulling from library/busybox #A
7c9d20b9b6cd: Pull complete #A
Digest: sha256:fe301db49df08c384001ed752dff6d52b4... #A
Status: Downloaded newer image for busybox:latest #A
Hello World #B
With this single command, you told Docker what image to create the
container from and what command to run in the container. This may not look
so impressive, but keep in mind that the entire “application” was downloaded
and executed with a single command, without you having to install the
application or any of its dependencies.
In this example, the application was just a single executable file, but it could
also have been a complex application with dozens of libraries and additional
files. The entire process of setting up and running the application would be
the same. What isn’t obvious is that it ran in a container, isolated from the
other processes on the computer. You’ll see that this is true in the remaining
exercises in this chapter.
Figure 2.10 shows exactly what happens when you execute the docker run
command.
Figure 2.10 Running echo “Hello world” in a container based on the busybox container image
The docker CLI tool sends an instruction to run the container to the Docker
daemon, which checks whether the busybox image is already present in its
local image cache. If it isn’t, the daemon pulls it from the Docker Hub
registry.
After downloading the image to your computer, the Docker daemon creates a
container from that image and executes the echo command in it. The
command prints the text to the standard output, the process then terminates
and the container stops.
If your local computer runs a Linux OS, the Docker CLI tool and the daemon
both run in this OS. If it runs macOS or Windows, the daemon and the
containers run in the Linux VM.
Running other existing container images is much the same as running the
busybox image. In fact, it’s often even simpler, since you don’t normally
need to specify what command to execute, as with the echo command in the
previous example. The command that should be executed is usually written in
the image itself, but you can override it when you run it.
For example, if you want to run the Redis datastore, you can find the image
name on http://hub.docker.com or another public registry. In the case of
Redis, one of the images is called redis:alpine, so you’d run it like this:
$ docker run redis:alpine
Note
If you want to run an image from a different registry, you must specify the
registry along with the image name. For example, if you want to run an
image from the Quay.io registry, which is another publicly accessible image
registry, run it as follows: docker run quay.io/some/image.
If you’ve searched for the Redis image on Docker Hub, you’ve noticed that
there are many image tags you can choose from. For Redis, the tags are
latest, buster, alpine, but also 5.0.7-buster, 5.0.7-alpine, and so on.
Docker allows you to have multiple versions or variants of the same image
under the same name. Each variant has a unique tag. If you refer to images
without explicitly specifying the tag, Docker assumes that you’re referring to
the special latest tag. When uploading a new version of an image, image
authors usually tag it with both the actual version number and with latest.
When you want to run the latest version of an image, use the latest tag
instead of specifying the version.
Note
The docker run command only pulls the image if it hasn’t already pulled it
before. Using the latest tag ensures that you get the latest version when you
first run the image. The locally cached image is used from that point on.
Even for a single version, there are usually several variants of an image. For
Redis I mentioned 5.0.7-buster and 5.0.7-alpine. They both contain the
same version of Redis, but differ in the base image they are built on. 5.0.7-
buster is based on Debian version “Buster”, while 5.0.7-alpine is based on
the Alpine Linux base image, a very stripped-down image that is only 5MB
in total – it contains only a small set of the installed binaries you see in a
typical Linux distribution.
To run a specific version and/or variant of the image, specify the tag in the
image name. For example, to run the 5.0.7-alpine tag, you’d execute the
following command:
$ docker run redis:5.0.7-alpine
These days, you can find container images for virtually all popular
applications. You can use Docker to run those images using the simple
docker run single-line command.
After the success of Docker, the Open Container Initiative (OCI) was born to
create open industry standards around container formats and runtime. Docker
is part of this initiative, as are other container runtimes and a number of
organizations with interest in container technologies.
OCI members created the OCI Image Format Specification, which prescribes
a standard format for container images, and the OCI Runtime Specification,
which defines a standard interface for container runtimes with the aim of
standardizing the creation, configuration and execution of containers.
Introducing the Container Runtime Interface (CRI) and its
implementation (CRI-O)
This book focuses on using Docker as the container runtime for Kubernetes,
as it was initially the only one supported by Kubernetes and is still the most
widely used. But Kubernetes now supports many other container runtimes
through the Container Runtime Interface (CRI).
In this chapter, you’ll use Docker to run this application. In the next and
remaining chapters, you’ll run the application in Kubernetes. Over the course
of this book, you’ll iteratively expand it and learn about individual
Kubernetes features that help you solve the typical problems you face when
running applications.
The architecture of the Kiada application is shown in the next figure. The
HTML is served by a web application running in a Node.js server. The client-
side JavaScript code then retrieves the quote and question from the Quote and
the Quiz RESTful services. The Node.js application and the services
comprise the complete Kiada Suite.
You’ll spend a lot of time interacting with Kubernetes via a terminal, so you
may not want to go back and forth between it and a web browser when you
perform the exercises. For this reason, the application can also be used in
plain-text mode.
The plain-text mode allows you to use the application directly from the
terminal using a tool such as curl. In that case, the response sent by the
application looks like the following:
==== TIP OF THE MINUTE
Liveness probes can only be used in the pod’s regular containers.
They can’t be defined in init containers.
==== POP QUIZ
Third question
0) First answer
1) Second answer
2) Third answer
The HTML version is accessible at the request URI /html, whereas the text
version is at /text. If the client requests the root URI path /, the application
inspects the Accept request header to guess whether the client is a graphical
web browser, in which case it redirects it to /html, or a text-based tool like
curl, in which case it sends the plain-text response.
In this mode of operation, it’s the Node.js application that calls the Quote and
the Quiz services, as shown in the next figure.
Figure 2.13 The operation when the client requests the text version