Two processes run on the same Linux host.
The first sees the machine's hostname as build-host. The second sees api-container. Both call the same kernel operation to read the hostname, and the same kernel answers both calls.
The difference is the namespace associated with each process. The kernel uses that membership to decide which view of the hostname to return.
The same idea applies to other resources. Two processes can receive different views of process IDs, mounted file systems, network interfaces, and interprocess communication objects even though they share one kernel.
A Linux namespace gives a task a scoped view of a particular category of kernel-managed resources.
Namespaces do not create a second kernel or duplicate every resource. They change the context the shared kernel uses when interpreting operations from a task.
Every Linux task belongs to namespaces. A task on an ordinary host with no container setup still belongs to the system's initial namespaces, created during boot.
When the task makes a relevant system call, the kernel consults its namespace membership. Reading the hostname uses the task's UTS namespace, process lookup uses its PID namespace, socket creation uses its network namespace, and path resolution uses its mount namespace.
Namespace membership acts like a lookup context. A port number such as 8080, a PID such as 1, or a pathname such as /etc/hostname can identify different kernel state when interpreted through different namespaces.
Threads in an ordinary process normally share the same namespace memberships. Linux can represent membership at the task level, but changing namespaces in a multithreaded process is restricted for several namespace types because inconsistent views inside one process would be difficult or unsafe.
A namespace is itself a kernel object. Tasks refer to it rather than containing complete private copies of all the objects visible through it.
Suppose two processes are in different PID namespaces and both see themselves as PID 1. The kernel has not created two copies of either process.
Each task has an identity in the host's broader PID view, and the kernel translates that identity for observers in different PID namespaces.
Similarly, two network namespaces can each contain a socket bound to port 8080. The sockets do not conflict because each port number is interpreted within a different network stack.
The host remains able to manage the underlying tasks and networking objects. Namespaces give less privileged processes a scoped view; they do not hide resources from the kernel or from an authorized administrator operating in a broader namespace.
This distinction is the foundation of container isolation:
One set of kernel objects can be presented through several controlled views.
Linux separates resource views by category. A process can share one namespace type with another process while differing in a different type.
For example, two processes could share a network namespace but use different mount namespaces. They would see the same interfaces and port space while seeing different file-system mount trees.
This composability is why there is no single all-or-nothing “container namespace.” A runtime chooses which namespace objects to create and which existing ones to share.
A mount namespace isolates the set of mounts and their arrangement.
When a process creates a new mount namespace, it begins with a mount view based on the caller's current view. Subsequent mount and unmount operations can change the new view without making the same change in the original namespace.
Both namespaces have a root directory called /, and they are different roots. A path is meaningful only relative to the namespace that resolves it.
The same pathname can therefore resolve through different mount trees. /etc/hostname inside one namespace need not identify the same mounted object as /etc/hostname in another.
Mount namespaces isolate mount topology, not the underlying storage automatically. Two namespaces can deliberately mount the same file system or directory and therefore reach the same data.
Mount propagation settings also matter. A mount can be configured so selected mount events propagate between related namespaces, or so changes remain private. Creating a mount namespace does not guarantee that every later mount event is disconnected from every other namespace.
A mount namespace is broader than chroot. Changing a process's root directory affects where its absolute path lookup starts. A mount namespace controls the mount table visible during that lookup and can present an independently assembled file-system tree.
A PID namespace isolates the process-ID number space and the set of processes visible through PID-oriented interfaces.
One task can have a PID in each level of a PID namespace hierarchy. A process in an ancestor namespace can see tasks in descendant namespaces, while a process in a descendant namespace cannot see tasks that exist only in an ancestor.
PID 1 inside a new PID namespace identifies the first child created in that namespace. It is not the host's PID 1.
The namespace affects interfaces such as process lookup, signal targets, and the process view exposed through a correctly mounted /proc. The same task can therefore appear under a host PID in host tools and a different PID inside the namespace.
PID namespaces are hierarchical rather than peer-only. A host supervisor needs to see and manage its descendant container processes, while those processes should not enumerate unrelated host tasks.
Creating a PID namespace has a special API behavior: the calling task does not move into the new PID namespace. Instead, the namespace becomes the PID namespace for children created afterward. A process cannot change the PID by which its existing parent relationships already know it.
Loading simulation...
A network namespace isolates a Linux network stack.
It has its own:
Two processes in different network namespaces can both bind 0.0.0.0:8080 because the sockets belong to different port spaces.
A newly created network namespace does not automatically have external connectivity. It may contain only a loopback device, and that interface may initially be down.
Containers are commonly connected using virtual interfaces. A virtual Ethernet pair can place one endpoint in the container's network namespace and leave the other in a host-side namespace. Host routing, bridging, address translation, or policy can then connect the isolated stack to other networks.
The pair spans the namespace boundary, with one end in each. Traffic leaving the container has to pass through the host end before any routing decision applies.
A network namespace does not imply a separate physical network adapter. It creates a distinct software networking context that the host can connect deliberately.
A UTS namespace isolates the system hostname and NIS domain name returned by kernel interfaces.
UTS comes from the historical name Unix Time-sharing System. In container use, the hostname is the important part.
Processes in two UTS namespaces can receive different results from the hostname command or the uname() system interface.
Changing the hostname in one UTS namespace does not change the hostname stored in another.
This is useful for giving a container an identity that is meaningful inside its own environment. It does not provide DNS registration, network connectivity, or authentication by itself. A hostname is one scoped string, not a complete service-discovery system.
An IPC namespace isolates specific System V IPC objects and POSIX message queues.
The isolated System V objects include message queues, semaphore sets, and shared-memory segments created through System V interfaces. POSIX message queues are also associated with the IPC namespace.
The name can be misleading: an IPC namespace does not isolate every possible way processes communicate.
Processes can still communicate through an inherited pipe, a deliberately shared file, a shared memory mapping backed by the same file, or a network connection allowed by the surrounding configuration. System V IPC objects and POSIX message queues are isolated by this namespace; pipes, files, sockets, signals, and every possible shared mapping are not.
Each communication mechanism follows the namespace and permission rules relevant to that particular kernel object.
A user namespace isolates user and group ID numbers and the capabilities associated with them.
It can map UID 0 inside the namespace to an unprivileged UID such as 100000 outside on the host.
The process can appear as root inside while being represented by an unprivileged UID in the parent namespace.
Capabilities are also scoped. A task may have administrative capabilities over resources owned by its user namespace without having those capabilities in the host's initial user namespace.
This makes user namespaces important for rootless containers. An ordinary host user can create an environment in which it has namespace-scoped authority needed to configure other isolated resources, subject to kernel policy.
UID and GID mappings are visible through /proc/<pid>/uid_map and /proc/<pid>/gid_map.
User namespaces are hierarchical, and other namespace objects have an owning user namespace. That ownership helps the kernel decide whether a task has the required capability to manage or join them.
Namespace root is not automatically host root. The authority depends on the user namespace in which a capability is held and the namespace that owns the target resource.
A cgroup namespace virtualizes the process's view of the cgroup hierarchy.
It can make the process's current cgroup appear as the root of its visible cgroup tree. Paths reported through /proc then become relative to that namespace root instead of exposing the full host hierarchy.
A cgroup namespace does not create resource limits and does not move a process into a different cgroup. It changes the view of cgroup membership and paths. The cgroup namespace determines what part of the hierarchy the process sees; actual cgroup membership determines where it is accounted and controlled.
The host configures the real hierarchy and constraints. The scoped view avoids exposing host-specific placement details inside the container.
A time namespace gives processes offsets for selected system clocks.
Linux time namespaces can virtualize the values observed from monotonic and boot-time clocks. This can help a restored or migrated environment preserve a suitable view of time since boot.
They do not provide a completely independent wall clock. In particular, they do not simply let each container set an unrelated CLOCK_REALTIME value.
Time namespaces are less visible in everyday container use than PID, mount, network, and UTS namespaces, but they follow the same design principle: scope one category of kernel-visible state without creating another kernel.
A container does not have to receive a new namespace of every type.
It might:
Sharing changes the boundary. A container using the host network namespace sees the host's interfaces and competes in the host's port space. Two containers sharing a PID namespace can see one another's processes within that view.
The word container therefore does not tell you the exact isolation configuration. You must inspect which namespace objects the process actually joins.
Loading simulation...
Linux exposes three central namespace operations.
The clone() and clone3() interfaces can create a child directly in new namespaces using CLONE_NEW* flags. Container runtimes use this when they need task creation and namespace setup as one coordinated operation.
The unshare() interface lets a task stop sharing selected namespace contexts and create new ones. The unshare command-line utility exposes this behavior for experiments and administrative work.
The setns() interface lets a task join an existing namespace referenced by a file descriptor. The nsenter command is a convenient command-line wrapper.
In short, clone-family operations create a child in selected new namespaces, unshare() creates new namespace context for the caller or its children, and setns() joins an existing namespace.
These operations require appropriate capabilities in the user namespace that owns the target namespace. User namespaces can make some experiments possible without host root, but systems may restrict unprivileged user-namespace creation.
Joining a namespace changes future kernel operations; it does not copy the target process's ordinary state. Joining its network namespace gives access to that network view, for example, but does not copy its address space or file-descriptor table.
unshare --pid Needs --forkMost namespace changes can affect the calling process directly. PID namespaces are different.
After unshare(CLONE_NEWPID), the caller remains in its current PID namespace. The next child it creates enters the new namespace and becomes PID 1 there.
The command-line consequence is:
--fork makes the utility create a child after establishing the new PID namespace.
For useful process inspection, the new PID namespace should normally receive a matching /proc mount:
Inside the new shell:
The shell should see itself as PID 1, and ps should show only processes visible in the new namespace.
The user-namespace options make the shell namespace-root for this experiment on systems that allow unprivileged user namespaces. If the kernel or system policy disables that feature, the command will fail with an operation-not-permitted error; an administrator must enable the feature or run an appropriately privileged experiment.
/procLinux exposes namespace membership under /proc/<pid>/ns/.
Inspect the current shell:
Example links look like:
The numbers are namespace object identifiers represented through special links. Their exact values vary.
If two processes show the same identifier for the same namespace type, they refer to the same namespace object:
Equal output means the processes share a network namespace. Different output means they do not.
Modern systems can also show entries such as cgroup, time, pid_for_children, and time_for_children. The *_for_children links identify the namespace that newly created children will enter, which can differ from the caller's current membership.
Access to another process's namespace links is subject to /proc visibility and permission checks.
A namespace usually remains alive while at least one task belongs to it.
It can also remain alive without a running member when another reference exists. Opening a /proc/<pid>/ns/<type> link produces a file descriptor that refers to the namespace object. Administrators can also bind-mount such a link to keep a persistent reference. A running member, open descriptor, or bind-mounted reference is enough to keep the object alive.
This behavior lets a manager create a namespace, preserve it, and later start new processes inside it.
If the final task and final external reference disappear, the kernel can destroy the namespace object and release its namespace-specific state.
The /proc namespace entry is therefore more than a descriptive number. It is an interface through which software can hold and join the kernel object.
On a Linux system that permits unprivileged user namespaces, run:
The background command prints api-demo.
The host shell retains its original hostname:
Compare namespace membership:
The identifiers should differ. The sleep process is using the new UTS namespace even though it remains an ordinary host task.
The host can still see it:
Stop the demonstration process:
The experiment changes only the scoped hostname view and user context needed to perform the setup. It does not create a mount namespace, network namespace, resource limit, or complete container.
Create a temporary user and network namespace:
Inside it, inspect the interfaces:
The output normally contains only the namespace's loopback interface:
The host's physical interfaces are absent because they belong to another network namespace. The loopback interface is initially down, so even local networking may require:
No external route appears automatically. A runtime or administrator must create interfaces and connect the namespace to a host networking path.
This is a view-and-configuration boundary, not an automatic network:
A network namespace provides an isolated network stack; connectivity must be built between that stack and the outside world.
On a native Linux Docker host, obtain the host PID of a running container:
Inspect its namespace links:
Compare one with the current shell:
Different identifiers show that the container process uses a separate network namespace. Repeat the comparison for pid, mnt, uts, ipc, user, or cgroup.
Do not assume every identifier will differ. A runtime can intentionally share a namespace, and rootful containers often run without a separate user namespace unless user-namespace mapping is configured.
The lsns utility provides a system-wide namespace-oriented view:
It can filter by type:
Its output is limited by the caller's permissions and /proc visibility. Namespace inspection tells you which views are shared; it does not reveal every cgroup limit, mount detail, or security policy applied to the process.
Changing one namespace view does not sever every relationship with the original environment.
A process can inherit an open file descriptor before entering a new namespace. That descriptor continues to reference the same underlying file, pipe, socket, or other kernel object unless a mechanism specifically prevents its use.
Two mount namespaces can reach the same file system. Two network namespaces can be connected by virtual interfaces. A process in an ancestor PID namespace can observe descendants. User-namespace mappings intentionally connect inside and outside identities.
These are not necessarily isolation failures. A useful container needs controlled paths to storage, networking, logs, and management services.
The real questions are which views are separate, which objects are intentionally shared, and which communication paths cross the boundary.
Namespace isolation is precise and category-specific. Treating it as a universal wall hides both intended sharing and accidental exposure.
A process in a separate PID namespace can still consume every available CPU cycle. A process in a separate mount namespace can still allocate host memory. A distinct hostname does not reserve network bandwidth.
Namespaces primarily answer what resources and identifiers a process can see. Resource controllers answer how much the process group can consume.
A container runtime commonly configures both. Namespace isolation without resource control can provide distinct views while allowing one workload to exhaust shared capacity.
The cgroup namespace does not change this distinction. It scopes the visible cgroup tree; the actual cgroup hierarchy performs accounting and control.
Namespaces reduce exposure by removing resources from a process's normal view, but invisibility is not sufficient protection by itself.
All namespaced processes still call the shared kernel. The kernel must enforce boundaries even when a process supplies malicious system-call arguments or holds namespace-scoped administrative capabilities.
A secure container configuration also considers credentials, capabilities, system-call access, file permissions, mandatory access controls, resource limits, inherited descriptors, mounted host paths, and runtime management authority.
User namespaces can reduce the host authority represented by container root, but a mapping does not make every kernel interface safe. Conversely, a container without a user namespace may run UID 0 in the host's initial user namespace while other controls restrict its operations.
Namespaces are powerful isolation mechanisms. They are building blocks of a protection boundary, not proof that the complete boundary is correctly configured.
Suppose two instances of an API run as containers on one Linux host.
Each instance can receive:
1/8080The host still sees both as ordinary process trees. It schedules their threads, services their system calls, and can inspect their host PIDs.
The two instances can both listen on port 8080 inside their respective network namespaces. Host networking then decides how external traffic reaches each one.
They can both open /etc/config.yaml while their mount namespaces direct that pathname to different mounted files. They can both see a PID 1 even though the host assigns different PIDs to their main processes.
Nothing in these separate views guarantees a CPU share or memory ceiling. Nothing automatically prevents an inherited descriptor or intentionally shared mount from crossing the boundary. Those properties must be configured through the mechanisms that own them.
The practical mental model is not “the container has its own Linux.” It is:
The host Linux kernel interprets each operation through the namespaces attached to the calling task.
Linux namespaces give tasks scoped views of kernel-managed resources while all tasks continue to share one kernel. Namespace membership is part of the context the kernel uses to interpret identifiers and operations.
Mount, PID, network, UTS, IPC, user, cgroup, and time namespaces isolate different categories. They are independent dimensions, so a runtime can create new views for some resources and intentionally share others.
Linux creates and joins namespaces through clone-family operations, unshare(), and setns(). Namespace objects are visible under /proc/<pid>/ns, can outlive their final member when another reference pins them, and can be inspected with tools such as readlink, nsenter, and lsns.
Namespaces do not impose CPU or memory limits, isolate every communication channel, or form a complete security policy by themselves. They answer a precise question:
Which view of this kernel-managed resource should the calling task use?
5 quizzes