$RodHat_

Topic · 10 articles

Namespaces & Containers

A container is not a thing. It's a process with its own view of mounts, PIDs, the network, and the hostname, fenced in by a cgroup that caps what it can eat. The runtime is a convenience wrapper around a handful of syscalls and some files under /sys/fs/cgroup.

Learn the primitives and you can debug a container from the host when the vendor tooling is broken, which is exactly when you'll need to. Then look at jails, which FreeBSD shipped thirteen years before Docker, and decide how much of the stack you actually need.

Start here

Read these first, in this order.

  1. 01

    Tip · 2026-08-12

    Your container is six clone(2) flags. nsenter gets you back in.

    Containers are six kernel namespaces and nothing else. nsenter gets you inside from the host without docker exec, without touching the image, and without whatever tooling the vendor decided to ship.

  2. 02

    Tip · 2026-10-12

    setns and unshare: moving between Linux namespaces

    Every container runtime in existence calls setns(2) and unshare(2). These two syscalls are how Linux carves off namespaced views of mounts, PIDs, networking, and hostnames. Here is what they actually do and where they will surprise you.

  3. 03

    Tip · 2026-08-17

    ip netns is what container networking actually is. No daemon required.

    Network namespaces give a process its own routing table, its own interfaces, and its own firewall rules, in milliseconds. Docker creates them. Kubernetes creates them. You can too, from ip, without touching a container runtime.

  4. 04

    Tip · 2026-08-23

    cgroups v2 is just files. Here's how to use them without touching systemd.

    Linux cgroups v2 exposes memory, CPU, and I/O limits through a plain filesystem interface under /sys/fs/cgroup/. No systemd, no container runtime, just write to files and read the results. Here's the real workflow for memory.max, cpu.max, freezer, and io.max.

  5. 05

    Tip · 2026-10-10

    clone3: fork a process and get a stable handle in the same syscall

    clone(2) is 30 years old and its calling convention is different on every architecture. clone3(2) landed in Linux 5.3 with a struct-based API and CLONE_PIDFD, which hands you a race-free process handle at fork time. Here is how to use it.

  6. 06

    Tip · 2026-07-23

    ZFS boot environments + jails will do 90% of what you're using Docker for, and the other 10% is the part you don't actually need

    A real walkthrough of FreeBSD jails on ZFS datasets as a lighter, more honest isolation model than a container runtime for a lot of workloads.

The syscalls underneath

Version introduced, sourced from the man page. Full cards in the syscall reference, or check your kernel.

InterfaceSinceWhat it does
setns(2)Linux 3.0Move the calling thread into an existing namespace, given an fd for it (or a pidfd).
unshare(2)Linux 2.6.16Create new namespaces and move the calling process into them without forking.
clone3(2)Linux 5.3Fork a child process using a struct-based API; write a pidfd atomically with CLONE_PIDFD.
pidfd_open(2)Linux 5.3Get a file descriptor that refers to a process, immune to PID reuse.
jail(2)FreeBSD 4.0Create a FreeBSD jail and lock the current process into it (jail_set/jail_attach for more).

More console tips (1)

Rod's tales (1)

MOTD (2)

Other topics