In this tutorial we will learn how a pod is created from multiple containers and how they work together.

For Docker, the container is the smallest deployment unit. But other runtimes implement the concept of a pod which is a collection of one or more containers. Pods have a few special properties:

  1. All containers of a pod are scheduled on the same host
  2. All containers of a pod share the network namespace

This tutorial will demonstrate this by creating an isolated environment with a registry and Docker-in-Docker.

Launch the pod

The first container in the pod is created by launching a container mypod with a long-running process. Usually this is an infinite loop but in our case, the primary container will run for one hour (3600 seconds):

docker container run -d --name mypod alpine sleep 3600

Launch registry

When launching the Docker registry as the first service, the new container will share the network namespace with te primary container called mypod:

docker container run -d --name registry --network container:mypod registry

Launch Docker-in-Docker

The second container also shares the network namespace with the primary container mypod - and at the same time with the Docker registry:

docker container run -d --name dind --privileged --network container:mypod docker:stable-dind \
    dockerd --host=127.0.0.1:2375

Sidenote: The parameters dockerd --host=127.0.0.1:2375 force the Docker daemon to listen on port 2375 of localhost without using certificate authentication. This is for demonstration purposes only. In production environments, always use authenticated and encrypted network connections to your Docker daemon.

Launch work env

To start interacting with the isolated environment, we join another container to the pod. This one is based on the official Docker image:

docker container run -it --network container:mypod docker:stable sh

As the containers in the pod are only sharing the network namespace, the process list does not show the registry as well as the Docker daemon running in the pod:

ps

But when checking the listen ports, we can see the registry listening on port 5000 and the Docker daemon listening on port 2375:

netstat -tuna

To check the connection with the Docker daemon, we first need to configure the connection:

export DOCKER_HOST=tcp://127.0.0.1:2375

Then we can retrieve the version of client and server:

docker version

The commands above demonstrated that the processes running in the separate containers share a network namespace (see output of netstat) but are unable to see each other in the process list (see output of ps).

Use work env

As the final test, we can check if registry and Docker daemon are working correctly together.

Pull an image from Docker Hub:

docker image pull alpine

Apply a new tag for pushing to the local registry:

docker image tag alpine localhost:5000/alpine

Push the image to the local registry:

docker image push localhost:5000/alpine

Reset Docker daemon:

docker system prune --all --force

Pull the image from the local registry:

docker image pull localhost:5000/alpine

Quiz

What does a pod offer? Select all that apply

  • Keeps the network layer isolated
  • Composes containers to a single network environment
  • Keeps process lists isolated
  • Runs multiple processes in a single container

Which namespaces are shared in a pod? Select all that apply

  • mount namespace
  • uts
  • network
  • pid