containerd namespaces are how you can enforce isolation between different groups of containers and their associated resources within a single containerd instance.
Let’s see this in action. Imagine you have a dev namespace for your development team and a prod namespace for your production services.
First, we need to create these namespaces.
sudo ctr ns create dev
sudo ctr ns create prod
Now, let’s run a simple busybox container in the dev namespace.
sudo ctr -n dev run docker.io/library/busybox:latest dev-container1 busybox sleep 3600
And another one in the prod namespace.
sudo ctr -n prod run docker.io/library/busybox:latest prod-container1 busybox sleep 3600
You can see that dev-container1 is only visible when you specify the dev namespace:
sudo ctr -n dev ps
Output will show dev-container1.
And prod-container1 is only visible in the prod namespace:
sudo ctr -n prod ps
Output will show prod-container1.
If you try to list all containers without specifying a namespace, you’ll see nothing, because by default, containerd operates within the default namespace, which is empty in this scenario.
sudo ctr ps
This isolation is crucial for several reasons. It prevents naming collisions – you can have a container named webserver in dev and another webserver in prod without conflict. More importantly, it allows for granular resource control and policy enforcement. Different namespaces can be configured with different resource limits (CPU, memory), network policies, and access controls, ensuring that development workloads don’t impact production stability.
Internally, containerd uses the namespace field in its API and internal data structures to segregate these resources. When you use ctr -n <namespace>, you’re telling containerd to operate only within the scope of that specific namespace’s resources. This includes not just containers, but also images, tasks, and snapshots. This separation is backed by Linux kernel features like namespaces (PID, network, mount, UTS, IPC) and cgroups, which containerd leverages to provide robust isolation.
The default namespace is a special case. When you don’t specify a namespace with ctr, you are implicitly using the default namespace. Many container runtimes and orchestrators (like older versions of Docker or Kubernetes before namespace support was fully mature) would operate solely within this default namespace. This can lead to confusion if you’re expecting to see all your containers, but are only seeing a subset.
When you pull an image, by default, it’s pulled into the default namespace. If you want to pull an image specifically for a different namespace, you’d typically do so via a higher-level orchestrator or by configuring containerd’s image service to use a specific namespace. However, the most common pattern is to pull images into the default namespace and then reference them when creating containers in other namespaces. containerd’s image service is designed to be namespace-aware, meaning an image pulled into default can be used to create containers in dev or prod. The image itself is stored in a shared location, but the reference and its lifecycle within a namespace can be managed independently.
What many users don’t realize is that containerd namespaces are not just for administrative separation; they can also be used to implement security boundaries. By assigning different namespaces to different users or applications, you can limit what each can see and manage within containerd, even on the same host. This is a fundamental building block for multi-tenancy.
The next concept you’ll likely encounter is how to manage network isolation between these namespaces.