Sharing is Hard
A Linux system is a multi-user, multi-tasking environment. At any given moment, hundreds of processes are competing for finite resources like CPU cycles, system memory (RAM), and disk I/O bandwidth. The kernel schedules access to these resources, but by default it applies no hard limits — any process can attempt to consume as much as it wants.
Without rules, a single buggy or malicious program could consume all available RAM, causing the kernel's Out-of-Memory (OOM) killer to start terminating processes at random, or causing the entire system to become unresponsive. This is the noisy neighbor problem: one tenant's bad behavior degrades the experience for every other tenant sharing the same hardware.
The Linux kernel provides three complementary mechanisms to solve this problem. ulimit sets per-user, per-process boundaries enforced by the shell. Control Groups (cgroups) apply resource budgets to entire groups of processes as a unit. Namespaces isolate what a process can see — its view of other processes, the network, and the filesystem. Together, these three primitives are the complete foundation of every container runtime in existence, including Docker, containerd, and Podman.