One kernel
A container is not a second computer. Its programs are ordinary processes on the same Linux kernel as every other process. The kernel only gives them two extras: a smaller view of the system, and a budget.
A namespace wraps one global thing, such as the process list or the hostname, so processes inside see their own copy. Linux has 8 kinds: cgroup, ipc, net, mnt, pid, time, user, uts.
Namespaces: what it sees
As root we type unshare -upf --mount-proc bash. unshare asks the kernel for three new namespaces: UTS (‑u), PID (‑p) and mount (‑‑mount‑proc). ‑f forks bash so it starts inside them.
bash is the first process in the new PID namespace, so inside it is PID 1, just like systemd on the host. The host still sees it under its own number, here 4242. One process, two PIDs.
hostname box renames the computer, but only inside the new UTS namespace. Processes in the box now see box; the host and every other process still see lab.
ps lists processes by reading /proc. --mount-proc mounted a fresh /proc for the new PID namespace, so ps finds just two: bash (1) and itself (3; hostname used 2). The host's processes are hidden, not gone.
cgroups: what it uses
Namespaces limit what a process can see, not what it can use: bash could still fill all the memory. A control group (cgroup) is a set of processes whose CPU, memory and I/O the kernel counts and can limit.
In a second root terminal on the host we make a folder in /sys/fs/cgroup, the cgroup v2 tree. That folder is a new cgroup: the kernel fills it with control files at once, such as memory.max and cgroup.procs.
Writing 100M to memory.max sets a hard limit of 100 MiB. Reading it back shows bytes: 100 × 1024 × 1024 = 104857600. The limit line appears on the memory gauge.
Writing bash's PID to cgroup.procs moves it into the cgroup, and every process it starts from now on joins too. The host shell writes 4242, not 1: it lives in the host's PID namespace.
A program in the box asks for more and more memory. At 100 MiB the kernel first tries to free some. If it cannot, its OOM killer stops a process inside this cgroup. The host carries on untouched.
Docker and Podman do these same steps for you, plus more namespaces (network, user) and a ready-made filesystem from an image. A container is processes plus namespaces plus cgroups, on one shared kernel.
What happens
;; step 1/12 · one-kernel
container = ordinary processes
+ namespaces (what they can see)
+ cgroups (what they can use)
kernel one, shared by the host and every container
host systemd is PID 1, the first process
Run these as root (sudo -i) in a throwaway virtual machine, not on a server you care about. To clean up: type exit in the box shell, then rmdir /sys/fs/cgroup/box in the host terminal (it must be empty). The host PID 4242 and the hostname lab are examples. Find bash's real host PID with lsns -t pid or ps -ef on the host. Inside the box, PIDs count up from 1: hostname ran as PID 2, so ps got 3 (checked on Debian 12). If your shell's start-up files run programs, ps gets a higher number. Column spacing differs between ps versions.