Containers Communication

Containers Communication

In this tutorial, we are going to discuss about how containers communication will working via localhost in a Kubernetes Pod. In our Kubernetes Core Concepts: Pod tutorial, we stated that containers in the same Pod can access each other via localhost.

Containers Communication

When you create two containers on Docker, these containers cannot communicate via localhost. Because they run in different network namespaces.

Let’s verify this statement:

root@ashok:~# docker run -d --name web1 -e PORT=1111 webratio/nodejs-http-server
c13eb161bfdeb50cf347ac7d6157964b620fbd6a2def37c31e7cc35ba72eb785

root@ashok:~# docker run -d --name web2 -e PORT=2222 webratio/nodejs-http-server
7161b09e1ebf74a16086a59f003f60c882e7fc4b0a9d32be60c8bd90ac824ef2

root@ashok:~# docker exec -it web1 bash
root@c13eb161bfde:/# curl -I localhost:1111
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "585308-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 14:48:08 GMT
Connection: keep-alive

root@c13eb161bfde:/# curl -I localhost:2222
curl: (7) Failed to connect to localhost port 2222: Connection refused
root@c13eb161bfde:/# 

I can access port 1111 from web1 container. Because the process listening on port 1111 is already running on web1 container. But I can’t access port 2222 from web1 container. Because the process listening on port 2222 is running on web2.

Since containers are isolated from each other, they cannot communicate with each other via localhost.

I’ll try running these two containers in a Kubernetes cluster (I am using Rancher K3s distribution) with the same configuration:

root@ashok:~# cat multi-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-app
spec:
  containers:
  - image: webratio/nodejs-http-server
    name: web1
    env:
    - name: PORT
      value: "1111"
  - image: webratio/nodejs-http-server
    name: web2
    env:
    - name: PORT
      value: "2222"

Now I am deploying POD using above YAML configuration

root@ashok:~# kubectl apply -f multi-container-pod.yaml 
pod/demo-app created

root@ashok:~# kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
demo-app   2/2     Running   0          2m5s

Once POD is up and running, I am checking the connectivity between containers:

root@ashok:~# kubectl exec -it demo-app --container web1 -- /bin/bash
root@demo-app:/# curl -I localhost:1111
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "819562-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 14:57:30 GMT
Connection: keep-alive

root@demo-app:/# curl -I localhost:2222
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "819562-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 14:57:35 GMT
Connection: keep-alive

If we observe above result, curl localhost:2222 works fine in web1 container on Kubernetes. But why? Let’s ssh into the Kubernetes node and see what’s going on.

List containers:

root@ashok:~# k3s ctr c list
CONTAINER                                                           IMAGE                                                RUNTIME                  
1e589bea180d65a04301a33ee2212e1a6cd78f3c9639f88a0b370394493055f7    docker.io/webratio/nodejs-http-server:latest         io.containerd.runc.v2    
61ca69ef9912fe2aefd22bc3acb0452567b042191cbf545bdbdae423b2eae8c9    docker.io/rancher/mirrored-pause:3.6                 io.containerd.runc.v2    
8a034a18ea4c7e70ac9dc63394f8d538b2fe63f4935df54e3a74c9f8e1710639    docker.io/rancher/local-path-provisioner:v0.0.26     io.containerd.runc.v2    
903284ee3174900c48f83ace916ff299bd3d52adec5fc94b9c02c1673fb05a6f    docker.io/rancher/mirrored-coredns-coredns:1.10.1    io.containerd.runc.v2    
a6675f05c39e8721d69fc74bca14d3a6d10bc1e421e0df20151696d7398d29ee    docker.io/rancher/mirrored-pause:3.6                 io.containerd.runc.v2    
b6591be2a891ba04ccaf3ec86e5fdaf5b801783f62f467ec124c25787de46b84    docker.io/rancher/mirrored-pause:3.6                 io.containerd.runc.v2    
d15608299cb06109ebe9e9fbac6e142b0fb6c24f434d1e149a4cd6b047993247    docker.io/rancher/mirrored-metrics-server:v0.7.0     io.containerd.runc.v2    
d696f8a652dd3efa6f33b11a369c1b82911599b6680b75d888733d7117cdfb4c    docker.io/webratio/nodejs-http-server:latest         io.containerd.runc.v2    
e6497ffea5a21c088cf40702d35fe98070dfb7ce626c4747747141c8cdedf52f    docker.io/rancher/mirrored-pause:3.6                 io.containerd.runc.v2    
root@ashok:~# 

There are two containers with the webratio/nodejs-http-server image. This is expected.

Let’s examine the namespaces of these webratio/nodejs-http-server containers.

root@ashok:~# k3s ctr c info 1e589bea180d65a04301a33ee2212e1a6cd78f3c9639f88a0b370394493055f7
"cgroupsPath": "kubepods-besteffort-pod9b5ee104_6b47_4825_b063_92375f48c7ac.slice:cri-containerd:d696f8a652dd3efa6f33b11a369c1b82911599b6680b75d888733d7117cdfb4c",
"namespaces": [
                {
                    "type": "pid"
                },
                {
                    "type": "ipc",
                    "path": "/proc/12362/ns/ipc"
                },
                {
                    "type": "uts",
                    "path": "/proc/12362/ns/uts"
                },
                {
                    "type": "mount"
                },
                {
                    "type": "network",
                    "path": "/proc/12362/ns/net"
                },
                {
                    "type": "cgroup"
                }
            ],
root@ashok:~# k3s ctr c info d696f8a652dd3efa6f33b11a369c1b82911599b6680b75d888733d7117cdfb4c
"cgroupsPath": "kubepods-besteffort-pod9b5ee104_6b47_4825_b063_92375f48c7ac.slice:cri-containerd:d696f8a652dd3efa6f33b11a369c1b82911599b6680b75d888733d7117cdfb4c",
            "namespaces": [
                {
                    "type": "pid"
                },
                {
                    "type": "ipc",
                    "path": "/proc/12362/ns/ipc"
                },
                {
                    "type": "uts",
                    "path": "/proc/12362/ns/uts"
                },
                {
                    "type": "mount"
                },
                {
                    "type": "network",
                    "path": "/proc/12362/ns/net"
                },
                {
                    "type": "cgroup"
                }
            ],

Containers using pid 12362’s namespaces : ipc , uts , network

What is the PID 12362?

root@ashok:~# ps aux | grep 12362
65535      12362  0.0  0.0    972   512 ?        Ss   14:55   0:00 /pause

Pid 12362 belongs to the Pause container.

Since we have multiple Pause containers, here’s how we can tell which Pause container is being used by our containers:

root@ashok:~# k3s ctr c info d696f8a652dd3efa6f33b11a369c1b82911599b6680b75d888733d7117cdfb4c | grep sandbox-id
            "io.kubernetes.cri.sandbox-id": "e6497ffea5a21c088cf40702d35fe98070dfb7ce626c4747747141c8cdedf52f",

root@ashok:~# k3s ctr c info e6497ffea5a21c088cf40702d35fe98070dfb7ce626c4747747141c8cdedf52f | grep Image
    "Image": "docker.io/rancher/mirrored-pause:3.6",
What is Pause container in Kubernetes?

The “pause container” is a special, internal container created and managed by Kubernetes within each pod. Its primary purpose is to serve as a placeholder for the network namespace and IPC (Inter-Process Communication) namespace for all other containers within the same pod. It is a critical component of Kubernetes’ container orchestration mechanism, providing the foundation for container-to-container communication and network isolation within a pod.

The pause container is a special type of container that is used to create a network namespace for each Pod in Kubernetes. It is responsible for routing traffic between the Pod and the outside world.

The pause container is automatically created by containerd when you start a Pod. It is not visible to kubectl, but you can see it using the ctr command. For example, the following command will list all pause containers on the node:

Here are some key characteristics and functions of the pause container:

  1. Network Namespace: The pause container shares its network namespace with all other containers in the pod. This means that all containers in the pod can communicate with each other over the same network stack, including sharing the same IP address and port space. This enables containers within the same pod to easily communicate with each other as if they were running on the same host.
  2. IPC Namespace: Similar to the network namespace, the pause container also shares its IPC namespace with other containers in the pod. This allows containers within the pod to use inter-process communication mechanisms like System V IPC and POSIX message queues to communicate with each other.
  3. Lifetime Management: The pause container is responsible for managing the lifecycle of the pod. When all other containers within the pod have completed their tasks and exited, the pause container remains running, effectively keeping the pod alive. This ensures that the resources allocated to the pod, such as network namespaces, are not prematurely released.
  4. Minimal Resource Usage: The pause container is typically minimal in terms of resource usage. It usually doesn’t run any application code or perform any specific functions other than serving as a placeholder for namespaces. Because of its minimal nature, it consumes very few system resources.
  5. Automatically Managed: Kubernetes automatically creates and manages the pause container, and it is not directly visible or configurable by users or administrators. It is created when the pod is started and terminated when the pod is deleted.

Here are some of the key benefits of using the pause container in Kubernetes:

  • Improved network isolation: The pause container creates a separate network namespace for each Pod, which helps to isolate Pods from each other. This can improve security and performance by reducing the amount of traffic that can flow between Pods.
  • Simplified network configuration: The pause container takes care of all the low-level details of networking for Pods. This makes it easier to configure and manage networks in Kubernetes.
  • Portability: The pause container is a standard component of Kubernetes, so it is available on all Kubernetes platforms. This means that you can deploy your applications to any Kubernetes cluster without having to worry about configuring networking.
What is the purpose of the ipc, uts, and network namespaces?

IPC namespace

The IPC namespace provides a layer to enable Inter-Process Communication between containers.

UTS namespace

The UTS namespace provides a layer for using the same hostname between containers.

Network namespace

The network namespace provides a layer for using the same network stack between containers.

Thanks to the network namespace, containers in the same Pod can communicate with each other via localhost

Relationship between the Pause container and our containers (web1, web2)

When you try to deploy a container or multiple containers in a Pod, Kubernetes creates a Pause container in the Pod. The containers you deploy will be attached to the Pause container’s namespaces.

How Can Two Containers Communicate Via localhost on Docker?

We will create a Pause container on Docker. We will attach two more containers to the namespace of the Pause container.

root@ashok:~# docker run -d --name pause --ipc=shareable google/pause
Status: Downloaded newer image for google/pause:latest
2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0


# attach web1 & web2 to the Pause container's network namespace
root@ashok:~# docker run -d --name web1 --net=container:pause -e PORT=1111 webratio/nodejs-http-server
3f87705f2cd53fec4fc0ca69e474893d3ce8ef7204676cdf092260dd28ff8852

root@ashok:~# docker run -d --name web2 --net=container:pause -e PORT=2222 webratio/nodejs-http-server
8e2aa3bb2084b986c0af4f5b119266eb2db4ba52873fef633e7b9202f9490491

Make sure the web1 and web2 containers are added to the Pause container’s namespace:

root@ashok:~# pause_container_id=$(docker ps -aqf name=pause)

root@ashok:~# docker inspect web1 | grep $pause_container_id
        "ResolvConfPath": "/var/lib/docker/containers/2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0/hostname",
        "HostsPath": "/var/lib/docker/containers/2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0/hosts",
            "NetworkMode": "container:2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0",
            "Hostname": "2dfef30d52b3",

root@ashok:~# docker inspect web2 | grep $pause_container_id
        "ResolvConfPath": "/var/lib/docker/containers/2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0/hostname",
        "HostsPath": "/var/lib/docker/containers/2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0/hosts",
            "NetworkMode": "container:2dfef30d52b300031d7383718a21e36b2e46da0d9db7b322d55fbb5ca4bee3c0",
            "Hostname": "2dfef30d52b3",
root@ashok:~# 

Test connectivity between web1 and web2:

root@ashok:~# docker exec -it web1 bash
root@2dfef30d52b3:/# curl -I localhost:1111
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "585308-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 15:20:54 GMT
Connection: keep-alive

root@2dfef30d52b3:/# curl -I localhost:2222
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "585308-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 15:20:59 GMT
Connection: keep-alive

root@2dfef30d52b3:/# exit
exit

root@ashok:~# docker exec -it web2 bash
root@2dfef30d52b3:/# curl -I localhost:1111
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "585308-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 15:21:20 GMT
Connection: keep-alive

root@2dfef30d52b3:/# curl -I localhost:2222
HTTP/1.1 200 OK
server: ecstatic-1.4.1
Content-Type: text/html
etag: "585308-4096-"2017-01-02T10:18:20.000Z""
last-modified: Mon, 02 Jan 2017 10:18:20 GMT
cache-control: max-age=3600
Date: Wed, 05 Jun 2024 15:21:24 GMT
Connection: keep-alive

root@2dfef30d52b3:/# 

How do Containers Communicate via localhost in a Kubernetes Pod?

When you try to deploy a container or multiple containers in a Pod, Kubernetes creates a Pause container in the Pod.

That’s all about the how Containers Communicate via localhost in a Kubernetes. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Kubernetes.!!

Containers Communication
Scroll to top