3 minute read

Kubernetes Multi Container Pods

Multi Container Pods

As per Kubernetes documentation, The primary reason that Pods can have multiple containers is to support helper applications that assist a primary application. Typical examples of helper applications are data pullers, data pushers, and proxies. Helper and primary applications often need to communicate with each other. Typically this is done through a shared filesystem, as shown in this example.

We have not yet discussed volumes, but for now, it is sufficient to know that it is a storage component.

pradeep@learnk8s$ cat multi-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: multi-containers
spec:

  restartPolicy: Never

  volumes:
  - name: common-data
    emptyDir: {}

  containers:

  - name: nginx
    image: nginx
    volumeMounts:
    - name: common-data
      mountPath: /usr/share/nginx/html

  - name: ubuntu
    image: ubuntu
    volumeMounts:
    - name: common-data
      mountPath: /ubuntu-data
    command: ["/bin/sh"]
    args: ["-c", "echo Hello from the Ubuntu container which is visible in the nginx container as they are sharing the same storage common-data > /ubuntu-data/index.html"]
pradeep@learnk8s$ kubectl create -f multi-container-pod.yaml
pod/multi-containers created
pradeep@learnk8s$ kubectl get pods -o wide | grep multi
multi-containers            1/2     NotReady    0              8m3s   10.244.1.34   k8s-m02   <none>           <none>

If you notice, though we have defined two containers (nginx and ubuntu) in this Pod definition, there is only a single IP (10.244.1.34 in this case). This is important to understand. All containers in a pod share the same network resources.

Also, READY column shows 1/2 meaning, there are two containers but only one is Running. Let us find out more on this by describing it.

pradeep@learnk8s$ kubectl describe pods multi-containers
Name:         multi-containers
Namespace:    default
Priority:     0
Node:         k8s-m02/192.168.177.30
Start Time:   Wed, 16 Feb 2022 07:19:50 +0530
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           10.244.1.34
IPs:
  IP:  10.244.1.34
Containers:
  nginx:
    Container ID:   docker://1cb2560ba88bf7f5a100c74246f10adecf6ce026d9f6031e43947c32ba021d3c
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 16 Feb 2022 07:20:09 +0530
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /usr/share/nginx/html from common-data (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7jtgb (ro)
  ubuntu:
    Container ID:  docker://d896bd674b06da660ee2e179d104af43344628dcf49edeb90630dc33fa63197e
    Image:         ubuntu
    Image ID:      docker-pullable://ubuntu@sha256:669e010b58baf5beb2836b253c1fd5768333f0d1dbcb834f7c07a4dc93f474be
    Port:          <none>
    Host Port:     <none>
    Command:
      /bin/sh
    Args:
      -c
      echo Hello from the Ubuntu container which is visible in the nginx container as they are sharing the same storage common-data > /ubuntu-data/index.html
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Wed, 16 Feb 2022 07:20:20 +0530
      Finished:     Wed, 16 Feb 2022 07:20:20 +0530
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /ubuntu-data from common-data (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7jtgb (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  common-data:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
    SizeLimit:  <unset>
  kube-api-access-7jtgb:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  3m8s   default-scheduler  Successfully assigned default/multi-containers to k8s-m02
  Normal  Pulling    3m6s   kubelet            Pulling image "nginx"
  Normal  Pulled     2m49s  kubelet            Successfully pulled image "nginx" in 17.095268831s
  Normal  Created    2m49s  kubelet            Created container nginx
  Normal  Started    2m49s  kubelet            Started container nginx
  Normal  Pulling    2m49s  kubelet            Pulling image "ubuntu"
  Normal  Pulled     2m38s  kubelet            Successfully pulled image "ubuntu" in 10.692871602s
  Normal  Created    2m38s  kubelet            Created container ubuntu
  Normal  Started    2m38s  kubelet            Started container ubuntu

We can see that the nginx container is Running but the ubuntu container is terminated with Reason as Completed. That means, Ubuntu container has finished its task. The task that we have given to this container is to echo a message and write that to a file. That’s all.

To continue the verification, login to the nginx container. Remember the kubectl exec command?!

pradeep@learnk8s$ kubectl exec -it multi-containers -c nginx -- /bin/bash

root@multi-containers:/# curl localhost
Hello from the Ubuntu container which is visible in the nginx container as they are sharing the same storage common-data
root@multi-containers:/# exit
exit

The one difference that you might have noticed is the use of -c option here. When there are multiple containers in a pod, we need to be specific about which container we want to work with, by specifying its name. In this case , we want to login to the shell (bash) of the nginx container, and henc the -c nginx option. Also, we specify the command (/bin/bash) that we want to execute after the two dashes followed by a space (--).

We logged in to the nginx container, but the data written by the ubuntu container is visible here as both of them are using the common storage volume called common-data.

Back to Top ↑