Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Linux Namespaces: The Basis of Containers

By Kokil Thapa | Last reviewed: September 2026

Linux namespaces: the basis of containers is not marketing language. It is the actual kernel mechanism. Every Docker, Podman, containerd, and LXC workload you run on Ubuntu production servers relies on namespaces to give each container its own view of processes, networks, mounts, and users. Without them, a container would just be an ordinary process group on shared host resources. If you deploy Laravel apps with Docker Compose or maintain sister sites on shared EC2 infrastructure, understanding namespaces helps you debug wrong-PID, network, and permission failures faster.

What are Linux namespaces and why do containers need them?

A namespace wraps a set of global resources and presents them as private to a process tree. The Linux kernel has offered this since roughly 2002, with user namespaces arriving later. Containers are not lightweight VMs. They are ordinary processes placed inside one or more namespace boundaries.

On a real client project I maintain several Laravel applications on a single Ubuntu 24 server. Each app runs in its own container. Namespaces ensure the PHP-FPM process inside container A cannot see container B's process list or bind to its ports. That isolation is cheap compared to full KVM virtualisation documented in our KVM and QEMU guide.

Namespaces answer one question: what does this process think the system looks like? They do not limit CPU or memory. That job belongs to cgroups v2. Production container stacks combine both layers. Runtimes like containerd and Docker assemble the full set during create and start.

Linux Namespaces: Container Isolation ModelShared Linux Host KernelOne kernel, one hardware, many isolated viewsContainer APID 1 = nginxeth0 = 10.0.1.2/ = overlayfsOwn namespace setContainer BPID 1 = php-fpmeth0 = 10.0.1.3/ = overlayfsOwn namespace setHost ViewAll real PIDsdocker0 bridgeHost mount treeInitial namespace
Linux namespaces give each container its own PID, network, and mount view while sharing one host kernel.

How do the eight Linux namespace types isolate resources?

Modern kernels expose eight namespace types. Each one virtualises a different slice of the operating system. Container runtimes typically enable most of them together.

NamespaceFlagWhat it isolatesContainer impact
PIDCLONE_NEWPIDProcess IDsPID 1 inside feels like init; host PIDs hidden
NetworkCLONE_NEWNETInterfaces, routes, iptablesOwn loopback and veth; separate port space
MountCLONE_NEWNSFilesystem mount pointsContainer rootfs without altering host mounts
UTSCLONE_NEWUTSHostname and domaindocker run -h web sets isolated hostname
IPCCLONE_NEWIPCSysV IPC, POSIX mqShared memory segments stay inside container
UserCLONE_NEWUSERUID/GID mappingsRoot in container maps to unprivileged host UID
CgroupCLONE_NEWCGROUPCgroup root viewContainer sees its own cgroup subtree
TimeCLONE_NEWTIMEBoot and monotonic clocksRare in production; useful for testing

PID namespace: why container PID 1 matters

Inside a PID namespace the first process becomes PID 1. It receives orphaned child signals that would normally go to init. That is why Docker and systemd expect your image entrypoint to reap zombie processes. If PID 1 ignores SIGCHLD, zombies accumulate until the container stops.

From the host, the same process has a completely different PID. This mismatch confuses people during debugging a running container. Always check both views when tracing signals, as covered in our Linux process management guide.

Network namespace: separate stacks on one NIC

A new network namespace starts with only a loopback interface. The runtime creates a veth pair. One end sits in the container namespace, the other joins a bridge like docker0 on the host. Each namespace maintains its own routing table, ARP cache, and socket bindings.

Port 80 inside two different network namespaces can both listen simultaneously. On the host you publish ports through NAT rules managed by iptables or nftables. Our iptables vs nftables comparison explains the firewall side.

Mount namespace: container filesystem without host damage

Mount namespaces give each container its own mount tree. OverlayFS stacks a read-only image layer with a writable container layer. A umount or bind mount inside the container does not touch host paths. This is how image layers stay immutable while logs and temp files persist in the writable layer.

File permission problems often involve mount propagation or wrong volume bind modes. See Linux file permissions and ACLs when UID mapping interacts with host volumes.

User namespace: root that is not host root

User namespaces map UIDs and GIDs inside the namespace to different IDs outside. Container UID 0 may map to host UID 100000. This is the core of rootless containers. An escaped process still lacks host privileges because its "root" is unprivileged on the host.

Not every runtime enables user namespaces by default. Docker requires explicit daemon configuration. Podman uses them out of the box. For production Linux system administration work, verify mapping files in /etc/subuid and /etc/subgid before relying on rootless mode.

How do you create and inspect Linux namespaces from the command line?

You do not need Docker to experiment. The unshare and nsenter utilities from the util-linux package expose namespaces directly. These commands work on Ubuntu 22.04 and 24.04 hosts I use for Deployer 7 deployments.

Spawn an isolated shell with unshare

This one-liner creates fresh PID, mount, UTS, IPC, and network namespaces:

sudo unshare --fork --pid --mount --uts --ipc --net --map-root-user bash

Inside the new shell, run ps aux. You will see only a handful of processes. Run hostname isolated-box. The name changes only inside this session. Run ip link. You get lo alone until you add interfaces.

Every process exposes its namespace memberships as symlinks:

ls -l /proc/self/ns/
readlink /proc/$(pgrep -n nginx)/ns/pid
readlink /proc/$(pgrep -n nginx)/ns/net

Processes sharing the same inode number for pid: or net: live in the same namespace. Compare a containerised nginx PID with a host PID. The numbers will differ even when both run nginx.

Enter a running container namespace with nsenter

When you need host-level debugging without exec into the container:

PID=$(docker inspect -f '{{.State.Pid}}' mycontainer)
sudo nsenter -t $PID -m -p -n -i -u bash

You now share the container's mount, PID, network, IPC, and UTS namespaces while running a host binary. This is faster than guessing from outside when diagnosing DNS or routing issues on production stacks like those in our Adventure Third Pole Trek portfolio case.

Creating and Joining NamespacesHost shellInitial nsunshareclone flagsNew ns setIsolated viewnsenterJoin targetunshare flags--pid new process tree--net new network stack--mount new mount tree--user UID/GID map--uts hostname isolatensenter targets-t PID target process-m enter mount ns-n enter network ns-p enter PID ns
Use unshare to create namespace boundaries and nsenter to attach a host process to an existing container namespace.

How do container runtimes assemble namespaces during startup?

High-level tools hide the syscall sequence, but the steps are predictable. Understanding them explains failures that occur before your application code runs.

  1. The runtime creates or joins namespaces via clone() or unshare() with the appropriate flags.
  2. It configures the root filesystem with pivot_root or chroot inside the mount namespace.
  3. It sets up network veth pairs and bridge attachment for the network namespace.
  4. It writes UID/GID maps for user namespaces when enabled.
  5. It applies cgroup limits through the cgroup namespace boundary.
  6. It execs the container entrypoint as PID 1 in the PID namespace.

containerd and runc follow the OCI runtime specification. Docker adds networking plugins and volume drivers on top. LXC and LXD use the same kernel primitives but target full system containers with systemd inside. The namespace layer is identical even when the packaging differs.

On shared EC2 hosts where I run multiple legal-tech portals via GitLab CI and Deployer 7, each deploy triggers container restarts. Stale network namespaces from crashed containers occasionally leave ghost veth interfaces. Cleaning them requires host-level inspection, not an application redeploy. Good support and maintenance practice includes monitoring orphaned interfaces after failed deploys.

Container Runtime Namespace Assemblydocker runCLI requestcontainerdCRI shimruncOCI runtimeNamespaced processPID 1 entrypointrunc create steps inside kernelunshare all nspivot_root rootfsset hostnamesetup veth netwrite uid mapsexec entrypoint
Docker and containerd delegate to runc, which creates Linux namespaces before executing the container entrypoint as PID 1.

What are the security limits of Linux namespaces?

Namespaces provide isolation of view, not complete containment. A kernel bug or misconfigured capability can still bridge the boundary. Treat namespaces as one layer in a defence stack, not a guarantee.

  • Shared kernel: All containers on a host call the same kernel. A kernel CVE affects every tenant. Patch cadence matters more than image hardening alone.
  • Capabilities and seccomp: Namespaces do not drop Linux capabilities. Runtimes add seccomp and AppArmor or SELinux profiles separately.
  • Host mounts: Bind-mounting /var/run/docker.sock or host /etc breaks filesystem isolation even with a mount namespace.
  • Side channels: Timing and cache attacks cross namespace lines because CPU caches are shared hardware.
  • Privileged containers: --privileged disables much of the isolation model. Avoid it on production Laravel or WordPress stacks.

For vulnerability scanning and supply-chain checks, pair namespace awareness with image scanning workflows described in our Trivy scanning guide. Resource limits via cgroups add the second essential wall documented when you limit Docker container resources.

Official references remain the best source for flag behaviour. The namespaces(7) man page on man7.org lists every type and syscall. The Linux kernel namespaces documentation tracks kernel-side changes. Docker's engine security overview explains how user namespaces integrate with daemon configuration.

Container Security Layers Beyond NamespacesShared Linux Kernel and Hardwarecgroups v2 — CPU, memory, IO limitsLinux Namespaces — view isolationCapabilities dropseccomp filterRead-only image + non-root userNamespaces alone do not equal full security
Linux namespaces isolate views, but production container security also requires cgroups, seccomp, dropped capabilities, and hardened images.

How do namespaces differ from cgroups and virtual machines?

Engineers new to containers often conflate the three. Each solves a different problem. Namespaces hide resources. Cgroups throttle and account for them. Virtual machines virtualise hardware with a separate kernel.

FeatureLinux namespacescgroups v2KVM virtual machine
Primary roleIsolation of viewResource limits and accountingFull hardware virtualisation
Kernel instancesOne shared kernelOne shared kernelGuest kernel per VM
Startup timeMillisecondsN/A (paired with namespaces)Seconds to minutes
Memory overheadLowLowHigh (full OS footprint)
Typical useDocker, containerd, PodmanCPU and RAM caps per containerMulti-tenant isolation, Windows guests

For most PHP and Laravel deployments I prefer containers on a well-patched host. VMs make sense when you need kernel modules the host lacks or strict regulatory separation. Flatcar Container Linux strips the host to the minimum needed for namespace-based workloads. That reduces the attack surface around the shared kernel.

When tuning production hosts, combine namespace knowledge with Linux performance tuning basics and proper systemd service management. Validate JSON config files in CI using our JSON formatter tool before they reach the runtime.

Key Takeaways

  • Linux namespaces: the basis of containers partition PID, network, mount, UTS, IPC, user, cgroup, and time views without duplicating the kernel.
  • Use ls -l /proc/PID/ns/ and nsenter to debug namespace mismatches between host and container perspectives.
  • PID 1 inside a container must handle reaping; network namespaces need veth pairs and bridge or CNI configuration.
  • User namespaces enable rootless containers by mapping container root to an unprivileged host UID.
  • Namespaces isolate views only — pair them with cgroups, seccomp, capability drops, and patched kernels for production safety.
  • Container runtimes like runc assemble all namespace types during OCI container creation before execing your entrypoint.

People Also Ask

What is the difference between a namespace and a container?

A container is a running process (or process tree) wrapped in a coordinated set of Linux namespaces plus cgroups, a root filesystem, and runtime configuration. A namespace alone is just one kernel isolation primitive. You can create a bare namespace with unshare without building a full container image or OCI bundle.

Which Linux namespace makes container PID 1 possible?

The PID namespace (CLONE_NEWPID) remaps process IDs so the first process in the namespace becomes PID 1. That process behaves like init for orphaned children inside the container. On the host the same process retains its real PID, which is why docker top and host ps show different numbers.

Can containers communicate if they share a network namespace?

Yes. Processes in the same network namespace share interfaces, IP addresses, and port space. Kubernetes pods use this pattern: containers in one pod share a network namespace and communicate via localhost. Separate pods get separate network namespaces connected through the CNI overlay.

Do Windows containers use Linux namespaces?

No. Windows containers rely on Windows kernel isolation constructs such as silos and job objects. Linux namespaces are specific to the Linux kernel. Hybrid shops running WSL2 use Linux namespaces inside the WSL2 VM while native Windows containers follow a different model, as described in our WSL2 for developers article.

Build safer container deployments on Linux

Linux namespaces: the basis of containers explain why your app sees its own PID table, network stack, and filesystem while sharing one kernel with neighbours. That mental model turns cryptic production errors into solvable namespace mismatches. Whether you run WooCommerce on Docker, Laravel queues in Podman, or legal-tech portals on shared EC2, the kernel primitives stay the same.

If you want help hardening container hosts, debugging namespace issues after deploy, or designing multi-container stacks for a Nepal or international project, review our enterprise application development services or browse the full project portfolio. For hands-on server work — patch cadence, rootless setup, cgroup tuning — see Linux system administration in Nepal. Ready to talk through your stack? Contact us with your current runtime and host OS details.

Frequently Asked Questions

Kernel features that partition global system resources so each process group sees an isolated PID table, network stack, mount tree, hostname, IPC objects, user IDs, cgroup hierarchy, and optionally separate clocks — all without duplicating the kernel.

Without namespaces, a container would be an ordinary process group sharing the host PID list, network ports, and mount tree. Namespaces answer one question: what does this process think the system looks like? On production Ubuntu servers where I run multiple Laravel apps in separate containers, namespaces ensure PHP-FPM in container A cannot see container B's processes or bind to its ports. That view isolation is cheap compared to full KVM virtualisation. Namespaces hide resources; they do not limit CPU or memory — cgroups handle that second job.

Modern kernels expose eight namespace types, and container runtimes typically enable most together. PID (CLONE_NEWPID) hides host process IDs so PID 1 inside feels like init. Network (CLONE_NEWNET) gives separate interfaces, routes, and port space. Mount (CLONE_NEWNS) isolates filesystem mount points. UTS (CLONE_NEWUTS) sets hostname and domain independently. IPC (CLONE_NEWIPC) keeps SysV IPC and POSIX message queues private. User (CLONE_NEWUSER) maps container UIDs to different host IDs. Cgroup (CLONE_NEWCGROUP) shows a container-local cgroup subtree. Time (CLONE_NEWTIME) separates boot and monotonic clocks, though it is rare in production.

The PID namespace (CLONE_NEWPID). The first process entered into it becomes PID 1 and receives orphaned child signals that would normally go to init.

Inside a PID namespace, the first process becomes PID 1 and behaves like init for orphaned children. Docker and systemd expect your image entrypoint to reap zombie processes. If PID 1 ignores SIGCHLD, zombies accumulate until the container stops. From the host, the same process has a completely different PID, which confuses debugging. Always check both the container view with docker top and the host view with ps when tracing signals or process state on production stacks.

A new network namespace starts with only a loopback interface. The runtime creates a veth pair: one end sits inside the container namespace, the other joins a host bridge like docker0. Each namespace maintains its own routing table, ARP cache, and socket bindings, so port 80 inside two different network namespaces can listen simultaneously. On the host you publish ports through NAT rules managed by iptables or nftables. This is how multiple containers on one NIC get separate network stacks without duplicating hardware.

Mount namespaces give each container its own mount tree. OverlayFS stacks a read-only image layer with a writable container layer, so a umount or bind mount inside the container does not touch host paths. Image layers stay immutable while logs and temp files persist in the writable layer. File permission problems in production often involve mount propagation or wrong volume bind modes, especially when user namespace UID mapping interacts with host-mounted volumes. The mount namespace is what lets containers use their own rootfs without altering the host filesystem.

User namespaces map UIDs and GIDs inside the namespace to different IDs outside. Container UID 0 may map to host UID 100000, so an escaped process still lacks host privileges because its root is unprivileged on the host. Podman uses user namespaces out of the box. Docker requires explicit daemon configuration. Before relying on rootless mode in production, verify mapping files in /etc/subuid and /etc/subgid. Not every runtime enables user namespaces by default, so check your configuration rather than assuming root inside a container equals host root.

Every process exposes its namespace memberships as symlinks under /proc. Run ls -l /proc/self/ns/ to see your current namespaces, or readlink /proc/PID/ns/pid and readlink /proc/PID/ns/net for a specific process. Processes sharing the same inode number for pid: or net: live in the same namespace. Compare a containerised nginx PID with a host PID — the inode numbers will match within the same namespace even though the actual PID numbers differ. These commands work on Ubuntu 22.04 and 24.04 hosts without needing Docker installed.

The unshare and nsenter utilities from the util-linux package expose namespaces directly without Docker. unshare creates fresh namespace boundaries — for example, a shell with new PID, mount, UTS, IPC, and network namespaces where ps aux shows only a handful of processes. nsenter attaches a host process to an existing container namespace: get the container PID from docker inspect, then nsenter into its mount, PID, network, IPC, and UTS namespaces while running a host binary. This is faster than guessing from outside when diagnosing DNS or routing issues on production container stacks.

The runtime creates or joins namespaces via clone() or unshare() with the appropriate CLONE_NEW flags. It configures the root filesystem with pivot_root or chroot inside the mount namespace, sets up network veth pairs and bridge attachment, writes UID and GID maps for user namespaces when enabled, applies cgroup limits through the cgroup namespace boundary, then execs the container entrypoint as PID 1 in the PID namespace. containerd and runc follow the OCI runtime specification. Docker adds networking plugins and volume drivers on top. LXC and LXD use the same kernel primitives but target full system containers with systemd inside.

Namespaces provide isolation of view, not complete containment. All containers on a host share one kernel, so a kernel CVE affects every tenant and patch cadence matters. Namespaces do not drop Linux capabilities — runtimes add seccomp and AppArmor or SELinux profiles separately. Bind-mounting /var/run/docker.sock or host /etc breaks filesystem isolation even with a mount namespace. Timing and cache side channels cross namespace lines because CPU caches are shared hardware. Avoid --privileged on production Laravel or WordPress stacks. Pair namespace awareness with cgroups, seccomp, capability drops, and hardened images.

Each solves a different problem. Namespaces hide resources — a process sees its own PID table and network stack while sharing one kernel. Cgroups throttle and account for CPU, memory, and I/O without changing what the process sees. Virtual machines virtualise hardware with a separate guest kernel per VM, giving full isolation at the cost of seconds-to-minutes startup and high memory overhead. For most PHP and Laravel deployments I prefer containers on a well-patched host. VMs make sense when you need kernel modules the host lacks or strict regulatory separation requiring a separate kernel instance per tenant.

A namespace alone is one kernel isolation primitive — you can create a bare namespace with unshare without building a full container image or OCI bundle. A container is a running process tree wrapped in a coordinated set of Linux namespaces plus cgroups, a root filesystem, and runtime configuration assembled by tools like Docker, Podman, or containerd. The namespace layer is identical across runtimes even when packaging differs. Understanding that distinction helps when debugging failures that occur at the kernel boundary before your application code even runs.

Yes. Processes in the same network namespace share interfaces, IP addresses, and port space, so they can communicate via localhost. Kubernetes uses this pattern: containers in one pod share a network namespace and talk to each other on 127.0.0.1. Separate pods get separate network namespaces connected through the CNI overlay network. If two containers need isolated port bindings, they must be in different network namespaces. Sharing a network namespace is intentional co-location, not a security boundary between workloads.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: