Crisp answer: Containers are not a kernel feature — they're a combination of kernel namespaces (isolation) and cgroups (resource limits) applied to regular processes. The container runtime sets these up; the kernel enforces them.
The two pillars:
1. Namespaces — what you can see
A namespace restricts a process's view of the system. Linux has 8 namespace types:
| Namespace | Flag | Isolates |
|---|---|---|
pid |
CLONE_NEWPID |
Process IDs — container sees its own PID 1 |
net |
CLONE_NEWNET |
Network interfaces, routes, iptables rules |
mnt |
CLONE_NEWNS |
Mount points — container has its own filesystem tree |
uts |
CLONE_NEWUTS |
Hostname and domainname |
ipc |
CLONE_NEWIPC |
System V IPC, POSIX message queues |
user |
CLONE_NEWUSER |
UIDs/GIDs — allows rootless containers |
cgroup |
CLONE_NEWCGROUP |
cgroup root — container sees its own cgroup tree |
time |
CLONE_NEWTIME |
System clocks (Linux 5.6+) |
Example — a container process thinks it's PID 1, but on the host it has a different PID:
# Inside the container:
ps aux
# PID CMD
# 1 /app/server
# On the host:
ps aux | grep server
# 29847 /app/server ← real PID
docker inspect --format '{{.State.Pid}}' my-container
# 29847
2. cgroups — what you can use
Control groups limit and account for resource usage. cgroups v2 (unified hierarchy, default on modern kernels) enforces:
| Controller | What it limits |
|---|---|
cpu |
CPU time allocation (shares, quota) |
memory |
Memory limit; triggers OOM kill when exceeded |
io |
Block I/O bandwidth and IOPS |
pids |
Number of processes (prevents fork bombs) |
net_cls |
Network packet classification for tc/iptables |
When a container exceeds its memory limit, the kernel's OOM killer kills
processes in that cgroup. In Kubernetes, this shows as OOMKilled.
# Inspect cgroup limits for a container:
cat /sys/fs/cgroup/memory/docker/<container-id>/memory.limit_in_bytes
cat /sys/fs/cgroup/cpu/docker/<container-id>/cpu.cfs_quota_us
# On cgroups v2 (unified):
cat /sys/fs/cgroup/system.slice/docker-<id>.scope/memory.max
3. Seccomp — what syscalls you can make
Containers run with a seccomp (secure computing) profile that restricts
which syscalls the process can make. Docker's default profile blocks ~44
dangerous syscalls (e.g. reboot, ptrace, mount). Kubernetes uses the
same mechanism via securityContext.seccompProfile.
4. Capabilities — which kernel privileges
Root in a container doesn't have all root capabilities. Docker drops many by
default (e.g. CAP_SYS_ADMIN, CAP_NET_ADMIN). You can add them back
(--cap-add) but that weakens isolation.
capsh --print # Show capabilities for the current process
grep Cap /proc/<pid>/status # Capability bitmask for a process
capsh --decode=<hex> # Decode the bitmask
The container runtime's job:
containerd (used by Docker and Kubernetes) calls clone() with namespace
flags, sets up cgroup limits, applies the seccomp profile, sets up the
overlay filesystem mount, then execve()s the container entrypoint. The
kernel enforces all of this.
What to say in the interview:
"Containers aren't a kernel primitive — they're regular processes isolated using namespaces and cgroups. Namespaces restrict what the process can see: its own PID space, network stack, filesystem. cgroups restrict what it can use: CPU, memory, I/O. When a container hits its memory limit, the kernel's OOM killer fires — that's the OOMKilled status in Kubernetes. The container runtime sets all this up using clone() with the right flags; the kernel enforces it. There's no separate guest kernel, which is why containers are so lightweight."