In Kubernetes, a Pod is the concept of a container group, and a Pod can contain multiple containers. These containers share resources such as network and storage, providing a more flexible environment for applications to run in.

A container is essentially a special process, created with a NameSpace to isolate the runtime environment, Cgroups to control resource overheads and some Linux network virtualisation techniques to solve network communication problems.

What Pods do is allow multiple containers to join the same NameSpace for resource sharing.

Visual representation of the Pod

Next, we can use Docker to restore the principles of Pod implementation.

Shared NameSpace for containers

We will now deploy a Pod with two containers, nginx and busybox, the former as the main application providing web services and the latter as the Sidecar debugging container.

First start the nginx container:

1
docker run -d --name nginx --ipc="shareable" -v $PWD/log:/var/log/nginx -v $PWD/html:/usr/share/nginx/html nginx

By default, Docker’s IPC Namespace is private, and we can use --ipc="shareable" to specify that sharing is allowed. The -v parameter needs no further explanation.

Next, we start the busybox container and join it to the NET, IPC, PID NameSpace of the nginx container, and we share the Volume of the nginx container so that we can access the nginx log files.

1
docker run -d --name busybox --net=container:nginx --ipc=container:nginx --pid=container:nginx -v $PWD/log:/var/log/nginx yauritux/busybox-curl /bin/sh -c 'while true; do sleep 1h; done;'

Once both containers are started, you can debug the resources of the nginx container directly in the busybox container.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[root@vm ~]# echo "hello pod" > $PWD/html/index.html
[root@vm ~]# docker exec -it busybox ps
PID   USER     TIME  COMMAND
    1 root      0:00 nginx: master process nginx -g daemon off;
   29 101       0:00 nginx: worker process
   30 101       0:00 nginx: worker process
   31 root      0:00 /bin/sh -c while true; do sleep 1h; done;
   37 root      0:00 sleep 1h
   38 root      0:00 ps
[root@vm ~]# docker exec -it busybox curl localhost
hello pod
[root@vm ~]# docker exec -it busybox tail /var/log/nginx/access.log
127.0.0.1 - - [30/Mar/2023:08:07:58 +0000] "GET / HTTP/1.1" 200 10 "-" "curl/7.81.0" "-"
[root@vm ~]#

In the busybox container, not only can you see the processes of the nginx container, but you can also directly access the nginx services and shared log file directories.

However, as the Namespace is created by the nginx container, if nginx crashes unexpectedly, all Namespaces will be deleted together and the busybox container will be terminated.

1
2
3
4
5
[root@vm ~]# docker stop nginx
nginx
[root@vm ~]# docker exec -it busybox ps
Error response from daemon: Container fca6ea0fe9f177f62d4b2d5d7db5bf64766d605f0414a8995c8d93159efeed4a is not running
[root@vm ~]#

Clearly, it is not desirable to have business containers acting as shared base containers; each container must be guaranteed a peer-to-peer relationship, not a parent-child relationship. kubernetes also takes this into account.

Pause containers

The Pause container, also known as the Infra container. To resolve the security issue of sharing base containers, Kubernetes starts an additional Infra container in each Pod to share the entire Pod’s Namespace.

The Pause container is started when the Pod is created and creates the Namespace, configures the network IP address, routes and other relevant information. The lifecycle of the Pause container is the lifecycle of the Pod, so to speak.

Once the Pause container has been started, other containers are started and share the Namespace with the Pause container, so that each container can access the resources of the other containers in the Pod.

The creation process can be found in the kubelet source code: pkg/kubelet/kuberuntime/kuberuntime_manager.go#L678

the kubelet source code

The creation of the Sandbox container in step 4 is actually the creation of the Pause container. Only after that does the creation of the init container and the normal container continue.

The Pause container, which plays such an important role, also has its own characteristics.

  1. the image is very small: gcr.io/google_containers/pause-amd64

    pause-amd64 image

  2. The performance overhead is almost negligible: pause.c

    pause.c source code

Having understood the Pause container, let’s start our experiments with Pod principles again.

Starting with a new environment, the first thing we should start this time is the Pause container.

1
docker run -d --name pause --ipc="shareable" gcr.io/google_containers/pause-amd64:3.2

Then start the nginx container again and add it to the Namespace of the Pause container.

1
docker run -d --name nginx --net=container:pause --ipc=container:pause --pid=container:pause -v $PWD/log:/var/log/nginx -v $PWD/html:/usr/share/nginx/html nginx

Ditto for the busybox container.

1
docker run -d --name busybox --net=container:pause --ipc=container:pause --pid=container:pause -v $PWD/log:/var/log/nginx yauritux/busybox-curl /bin/sh -c 'while true; do sleep 1h; done;'

You will now see both the pause and nginx container processes in the busybox container.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[root@vm ~]# echo "hello pod" > $PWD/html/index.html
[root@vm ~]# docker exec -it busybox ps
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    8 root      0:00 nginx: master process nginx -g daemon off;
   36 101       0:00 nginx: worker process
   37 101       0:00 nginx: worker process
   38 root      0:00 /bin/sh -c while true; do sleep 1h; done;
   45 root      0:00 sleep 1h
   46 root      0:00 ps
[root@vm ~]# docker exec -it busybox curl localhost
hello pod
[root@vm ~]# docker exec -it busybox tail /var/log/nginx/access.log
127.0.0.1 - - [30/Mar/2023:08:49:49 +0000] "GET / HTTP/1.1" 200 10 "-" "curl/7.81.0" "-"
[root@vm ~]#

And even if nginx unexpectedly crashes, it won’t affect the busybox container.

1
2
3
4
5
6
7
8
9
[root@vm ~]# docker stop nginx
nginx
[root@vm ~]# docker exec -it busybox ps
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
   38 root      0:00 /bin/sh -c while true; do sleep 1h; done;
   45 root      0:00 sleep 1h
   66 root      0:00 ps
[root@vm ~]#

Back to Kubernetes

I’m sure you now understand what happens when you execute the kubectl apply -f nginx-busybox-pod.yaml command in a Kubernetes cluster.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: v1
kind: Pod
metadata:
  name: nginx-busybox-pod
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: nginx-log
      mountPath: /var/log/nginx
    - name: nginx-html
      mountPath: /usr/share/nginx/html
    ports:
    - containerPort: 80
  - name: busybox
    image: yauritux/busybox-curl
    command: ["/bin/sh", "-c", "while true; do sleep 1h; done;"]
    volumeMounts:
    - name: nginx-log
      mountPath: /var/log/nginx
  volumes:
  - name: nginx-log
    emptyDir: {}
  - name: nginx-html
    emptyDir: {}

pause

The principle is as simple as that.