containerd Namespaces
containerd namespaces provide resource isolation for multi-tenancy. Learn how Docker uses the 'moby' namespace, Kubernetes uses 'k8s.io', and how to create your own isolated environments.
Namespaces in containerd are a way to isolate resources within a single containerd daemon. They provide logical separation of containers, images, snapshots, and other resources. Different namespaces are completely independent — containers in one namespace cannot see containers in another namespace.
This is different from Linux kernel namespaces (which isolate processes). containerd namespaces are a higher-level concept for resource organization and multi-tenancy.
images
snapshots
images
snapshots
images
snapshots
moby
Used by Docker Engine. When you run `docker run`, containers are created in the `moby` namespace. Docker Desktop also uses this namespace.
k8s.io
Used by Kubernetes. All pods and containers managed by kubelet run in the `k8s.io` namespace. This isolates Kubernetes workloads from Docker containers.
default (ctr)
The `ctr` CLI uses a namespace called `default` when no namespace is specified. This is separate from Docker and Kubernetes.
# List all namespaces
ctr namespace ls
# Output example:
NAME LABELS
moby
k8s.io
default
When you run Docker commands, Docker Engine uses the `moby` namespace. This isolates Docker containers from other containerd users.
# Run a Docker container
docker run -d --name nginx nginx:alpine
# View Docker containers from containerd perspective
ctr -n moby container ls
ctr -n moby task ls
# View images pulled by Docker
ctr -n moby image ls
# Inspect Docker container details
ctr -n moby container info nginx
# Note: Container names in containerd may differ from Docker names
Kubernetes uses the `k8s.io` namespace for all container operations. This allows K8s to run alongside Docker without interference.
# On a Kubernetes node, list pods from containerd
ctr -n k8s.io container ls
# List all containers (including pause containers)
ctr -n k8s.io container ls -q
# View images cached for Kubernetes
ctr -n k8s.io image ls
# Inspect a pod's pause container
ctr -n k8s.io container info k8s.gcr.io/pause:3.9
# Use crictl for Kubernetes-specific commands (easier)
crictl pods
crictl ps
# Create a new namespace
ctr namespace create myapp-prod
ctr namespace create myapp-staging
ctr namespace create myapp-dev
# List namespaces to verify
ctr namespace ls
# Create a namespace with labels
ctr namespace create --label environment=production myapp-prod
ctr namespace create --label team=backend backend-team
# Describe a namespace
ctr namespace ls -l
# Delete a namespace (removes all resources inside)
ctr namespace rm myapp-dev
# Pull image into specific namespace
ctr -n myapp-prod image pull docker.io/library/nginx:alpine
# List images in namespace
ctr -n myapp-prod image ls
# Run container in namespace
ctr -n myapp-prod run --rm docker.io/library/nginx:alpine test echo "Hello"
# List containers in namespace
ctr -n myapp-prod container ls
# Run interactive shell in namespace
ctr -n myapp-prod run --rm -t docker.io/library/alpine:latest test sh
# Set default namespace for ctr (via environment)
export CONTAINERD_NAMESPACE=myapp-prod
ctr image ls # now uses myapp-prod
This example shows how to create isolated environments for different teams or applications.
# Create namespaces for different teams
ctr namespace create team-alpha
ctr namespace create team-beta
ctr namespace create team-gamma
# Team Alpha deploys their app
ctr -n team-alpha image pull docker.io/library/nginx:alpine
ctr -n team-alpha run -d docker.io/library/nginx:alpine alpha-web
# Team Beta deploys their app (same image name, no conflict)
ctr -n team-beta image pull docker.io/library/nginx:alpine
ctr -n team-beta run -d docker.io/library/nginx:alpine beta-web
# Team Gamma runs different image
ctr -n team-gamma image pull docker.io/library/redis:alpine
ctr -n team-gamma run -d docker.io/library/redis:alpine gamma-cache
# Verify isolation - containers only visible within their namespace
ctr -n team-alpha container ls
ctr -n team-beta container ls
ctr -n team-gamma container ls
# Namespaces are completely isolated - no resource sharing by default
Namespaces and their resources persist across containerd restarts. Storage is isolated per namespace.
# Check storage location (Linux)
ls /var/lib/containerd/io.containerd.content.v1.content/
ls /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db
# Each namespace's metadata is stored in the same BoltDB database
# But entries are keyed by namespace
# Namespace labels can be viewed
ctr namespace ls -l
# Add labels to existing namespace
ctr namespace label myapp-prod environment=production
ctr namespace label myapp-prod owner=platform-team
# Find which namespace a container belongs to
# First, list all containers across all namespaces
for ns in $(ctr namespace ls -q); do
echo "=== Namespace: $ns ==="
ctr -n $ns container ls
done
# Check Docker containers via containerd
ctr -n moby container ls
# Check Kubernetes containers
ctr -n k8s.io container ls
# Check if a specific image exists across namespaces
for ns in $(ctr namespace ls -q); do
if ctr -n $ns image ls | grep -q nginx; then
echo "Found nginx in namespace: $ns"
fi
done
- containerd Namespaces: Logical separation within the containerd daemon for resource organization (images, containers, snapshots). Higher-level, API-level isolation.
- Linux Namespaces: Kernel-level isolation for processes (PID, NET, MNT, UTS, IPC, USER, CGROUP). Used by containers for process isolation.
Namespaces are a powerful feature for multi-tenancy in containerd. Use them to isolate workloads, separate environments, and organize resources efficiently.