interview-prep

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."


My notes