Docker is convenient, but it's also a thick layer of abstraction sitting on top of a handful of Linux kernel primitives. If you strip away the daemon, the CLI, and the image registry, a "container" is really just:

a process with restricted namespaces (its own view of PIDs, mounts, network, hostname, etc.)

a root filesystem it's been chroot/pivot_root'd into

optionally, cgroups limiting what it can consume

In this post we'll build a minimal container runtime by hand — no dockerd, no containerd, just unshare, chroot, and a plain directory tree we'll call a bundle. This is roughly what runc does under the hood when Docker "runs" a container.