Pause Almighty: The inaugural container
Unpacking the Pause Container: Its Unique Qualities and Contents Explained
I encountered the pause image first during my first Kubernetes node container debugging, and I had no idea what this container was. Yes, I got started with Kubernetes clusters and debugging without knowing the details of how Linux containers worked, and it’s okay for you too.
I run crictl images
command and saw output something similar to
I run crictl ps
commands and try to see which pod is using this registry.k8s.io/pause
image. And to my surprise there were none. It intrigued me and inspired me to learn about this special image. After relentless searches in Kubernetes and containerd
GitHub repositories.
Two noticeable things I encountered were the Container Runtime Interface and PodSandbox, deep dive details on them later. This article is all about the mighty Pause container.
Just to get us going, the Container Runtime Interface is an interface between kubelet and container runtimes like docker, containers and CRI-O to name a few. This interface defines functions that allow kubelet and container runtimes to talk about and manage PodSandbox and Container’s lifecycles.
service RuntimeService {
// Sandbox operations.
rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {}
rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {}
rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}
rpc PodSandboxStatus(PodSandboxStatusRequest) returns (PodSandboxStatusResponse) {}
rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse) {}
// Container operations.
rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse) {}
rpc StartContainer(StartContainerRequest) returns (StartContainerResponse) {}
rpc StopContainer(StopContainerRequest) returns (StopContainerResponse) {}
rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse) {}
rpc ListContainers(ListContainersRequest) returns (ListContainersResponse) {}
rpc ContainerStatus(ContainerStatusRequest) returns (ContainerStatusResponse) {}
...
}
If you working with Kubernetes the chances are you are aware of the Containers but what is PodSandbox? A Pod is composed of a group of application containers in an isolated environment with resource constraints. In CRI, this environment is called PodSandbox.
In the scope of Linux containers, PodSandbox is nothing but a namespace isolated process from other processes and shared namespace with other containers in the Pod.
From The Kubernetes Network Model
A pod has its own private network namespace which is shared by all of the containers within the pod. Processes running in different containers in the same pod can communicate with each other over
localhost
.
To achieve this behaviour before starting a pod, kubelet calls RuntimeService.RunPodSandbox to create the environment. This includes setting up networking for a pod (e.g., allocating an IP). Once the PodSandbox is active, individual containers can be created/started/stopped/removed independently. To delete the pod, kubelet will stop and remove containers before stopping and removing the PodSandbox.
This method requires the creation of a network namespace that can be shared across containers and a long-running process that can keep this network namespace up and prevent it from deleting by the Linux empty namespace clean-up process.
Namespace lifetime
Absent any other factors, a namespace is automatically torn down when the last process in the namespace terminates or leaves the namespace.
To keep this namespace running we use our pause container.
The pause container is a special container as it is run first in the namespace, its PID is always 1
And what does the pause container do? Well, that answer is not as interesting as you might imagine. So basically it just sleeps in a forever loop and does nothing.
Like the pause container, this pause
function is also special as mentioned in the docs
pause() causes the calling process (or thread) to sleep until a signal is delivered that either terminates the process or causes the invocation of a signal-catching function.
This pause() function allows us to have a very lightweight process that can keep running forever and keeps our namespaces available while the containers are creating or getting updated.
In the next article, we will discuss Container Runtime Interface so stay tuned.