skip to content

How can one container be made to share another container's network or process namespace, and which command lets you inspect a running container's namespaces from the host?

level: seniorimportance: should knowfreq 45%

answer

  1. one membership per namespace type
  2. --network/--pid/--ipc container:<name> or host
  3. Pod = pause sandbox holding shared ns
  4. /proc/<pid>/ns/* inode = identity; lsns to list
  5. nsenter -t PID -n = host tools, container stack

basics

~20 s

Namespace membership is per type, so containers can share some and not others: --network container:<name>, --pid container:<name>, --ipc container:<name>, or host for the host's own. From the host, nsenter -t <pid> -n -p -m joins a running container's namespaces via /proc/<pid>/ns/.

solid answer

~50 s

Each namespace type is chosen independently at container creation, so sharing is selective: - `--network container:web` — same net namespace: shared interfaces, one IP, communication over `localhost`, one shared port space (so the two cannot both bind a port). This is exactly the Kubernetes Pod model, built around a shared sandbox. - `--pid container:web` — same process tree: the new container's `ps` shows the target's processes, enabling debug/profiling sidecars that attach by PID. - `--ipc container:web` — shared shared-memory segments, used by processes that communicate through `/dev/shm`. - `host` in place of a container name shares the **host's** namespace — powerful and a real security downgrade. To inspect from outside, take the container's host PID (`docker inspect -f '{{.State.Pid}}'`) and use **nsenter**: `nsenter -t $PID -n ip addr` runs a host binary inside the container's *network* namespace only. That is the standard trick for a distroless image with no shell or tools. Underneath, both `docker exec` and `nsenter` use `setns()` on `/proc/<pid>/ns/*`.

code

bash · 15 lines
bash
# Sidecar shares the app's network stack: same IP, talk over localhost
docker run -d --name web -p 80:8080 myapp
docker run -d --name proxy --network container:web myproxy

# Debug container sees the app's process tree
docker run --rm -it --pid container:web nicolaka/netshoot ps aux

# Prove they share the net namespace but not the pid namespace
A=$(docker inspect -f '{{.State.Pid}}' web)
B=$(docker inspect -f '{{.State.Pid}}' proxy)
readlink /proc/$A/ns/net /proc/$B/ns/net   # identical inode
readlink /proc/$A/ns/pid /proc/$B/ns/pid   # different inode

# Overview of every namespace on the host
lsns -t net -t pid

go deeper

for a junior

Know that containers can be told to share another container's network, and that docker exec runs a command inside a container.

for a middle

Name the run flags per namespace type, describe what sharing a network namespace implies (one IP, localhost, one port space), and use nsenter with a host PID.

for a senior

Explain setns and /proc/<pid>/ns identity, the distroless nsenter workflow and its --mount caveat, the Pod sandbox model, and the risks of host-namespace sharing.

for a principal

Define policy: which namespace-sharing flags are permitted, how debug access is granted without host namespaces, and how sidecar patterns should be expressed on the platform.

## Membership is per type A process holds one membership per namespace type, and a runtime picks each independently. That is what makes selective sharing possible: two containers can share a network namespace while keeping separate mount and PID namespaces, so they appear as one host on the network but with different filesystems and process trees. ## Sharing at run time - **`--network container:<name>`** — the new container skips creating a net namespace and joins the target's. Both see the same `eth0` and IP, reach each other over `127.0.0.1`, and share one port space, so identical binds now *do* conflict. Only the first container can publish ports; the second inherits that exposure. Sidecar proxies, TLS terminators and network debuggers use this. - **`--pid container:<name>`** — join the target's PID namespace. Your process sees the target's processes with their in-namespace PIDs and can signal or profile them (subject to capabilities and matching users). Because the mount namespace is *not* shared by default, `/proc` visibility works but the target's filesystem is not directly readable — a frequent surprise when a debug container tries to read `/proc/<pid>/root/...` and needs privileges. - **`--ipc container:<name>`** — share System V IPC and POSIX message queues; also required to share `/dev/shm` semantics for databases and media pipelines that use large shared-memory buffers. - **`--uts container:<name>`** — share the hostname. - **`host` variants** (`--network host`, `--pid host`, `--ipc host`) — join the *host's* namespace. `--pid host` makes the container see and potentially signal every host process; `--network host` puts it directly on the host stack. These are genuine privilege escalations in effect, and combining `--pid host` with `--privileged` is essentially host access. Mount namespaces are notably not shareable this way; sharing filesystem state between containers is done with volumes instead. ## The Kubernetes connection A Pod is the productised version of this. The kubelet creates a **sandbox** (the "pause" container) that holds the Pod's namespaces; every container in the Pod joins its network, IPC and UTS namespaces while keeping its own mount namespace. That is why containers in a Pod share one IP and talk over localhost, why two of them cannot bind the same port, and why the sandbox must exist before any workload container starts. PID namespace sharing within a Pod is opt-in via `shareProcessNamespace`, and ephemeral debug containers optionally target another container's namespaces. ## Identity and inspection `/proc/<pid>/ns/` holds one symlink per namespace type — `net`, `pid`, `mnt`, `uts`, `ipc`, `user`, `cgroup`, `time`. Each resolves to a pseudo-path like `net:[4026532008]`; the number is the namespace's inode. Two processes are in the same namespace exactly when those inode numbers match, which makes comparison trivial: - `readlink /proc/$A/ns/net` versus `readlink /proc/$B/ns/net`. - `lsns` on the host lists every namespace, its type, member count and the command of the lowest-PID member — the fastest overview of what a machine is actually isolating. A namespace exists while it has a member process, a bind mount of its ns file, or an open file descriptor to it. Holding a reference is how `ip netns` keeps an empty namespace alive after its processes exit. ## Entering: nsenter and setns `setns(fd, nstype)` moves the calling process into the namespace referenced by an open ns file descriptor. `nsenter` wraps it: `nsenter --target $PID --net --pid --mount -- <cmd>` Select only the namespaces you need. Entering just `--net` is the classic move: you run the *host's* `ip`, `ss` or `tcpdump` binaries — from the host's mount namespace — inside the container's network stack. That solves the distroless problem where `docker exec` cannot help because the image has no shell. Caveats worth stating in an interview: joining a PID namespace only affects *children*, so `nsenter --pid` needs a forked command (which it does by default with `--pid` plus a program) to actually land in the new tree; and joining `--mount` costs you the host's tooling, since you then see the container's filesystem. `docker exec` is the managed version — it uses setns to join the container's namespaces (network, PID, mount, IPC, UTS) and runs a process from the *container's* image. `unshare` is the mirror image of nsenter: it creates fresh namespaces rather than joining existing ones, and `unshare --pid --fork --mount-proc --net --uts bash` builds a container-shaped shell in one command. ## Security notes Joining namespaces is a privileged operation (`CAP_SYS_ADMIN` in the relevant user namespace), which is why nsenter needs root on the host. Sharing *host* namespaces should be treated as an exception requiring justification: `--pid host` exposes the whole host process tree including command lines that may carry secrets, `--net host` removes network isolation and lets a container bind privileged host ports, and `--ipc host` exposes host shared memory. In a hardened platform these are the flags an admission policy blocks by default.

  • You need to run tcpdump inside a container built from a distroless image with no shell. How?
    Get the container's host PID with `docker inspect -f '{{.State.Pid}}'`, then run `nsenter -t $PID -n tcpdump -i eth0` as root on the host. Because only the network namespace is joined, the tcpdump binary and libraries come from the host's filesystem while the capture happens on the container's interfaces. Adding `--mount` would defeat this by switching you into the container's empty filesystem.
  • Two containers share a network namespace via --network container:web. What now breaks that worked before?
    They share one port space, so both can no longer bind the same port — the second bind fails with address already in use. Only the first container's port publishes apply, since the second creates no namespace of its own to map into, and it must be started after the first and dies with it network-wise. In exchange they can reach each other over 127.0.0.1 with no network hop.
  • How do you verify from the host that two containers really share a namespace?
    Compare the inode in the namespace symlink: `readlink /proc/<pidA>/ns/net` and the same for pidB — identical `net:[…]` values mean the same namespace. `lsns` gives the same information as a table, listing each namespace once with its member count, which is quicker when checking many containers at once.

Namespaces are like separate utility hookups per apartment: a new tenant can be plumbed into an existing apartment's phone line while keeping their own kitchen — you pick which utilities are shared, one at a time.

saying these in an interview costs you the question

  • Believing a container shares all namespaces or none, rather than one choice per type.
  • Expecting two containers sharing a network namespace to still have independent ports.
  • Assuming `--pid container:x` also gives access to that container's filesystem — mount namespaces are separate.
  • Treating `--pid host` or `--net host` as harmless conveniences.
  • Thinking `docker exec` works by SSH or an agent inside the container rather than setns on /proc/<pid>/ns.

context