Skip to main content

Container

A lightweight, isolated process running on a shared Linux kernel using namespaces and cgroups — providing filesystem, network, and process isolation without the overhead of a full virtual machine.

Container — The Fundamental Unit of Modern Infrastructure

What Is a Container in Simple Terms?

A container is a running process on a Linux host that has been given its own private view of the world. It thinks it has its own filesystem, its own network interface, its own process tree starting at PID 1, and its own hostname. In reality, it is sharing the host's Linux kernel with every other container on that machine.

The analogy that makes this click: a container is like a private office in a shared office building. Every office has its own lock, its own phone number, and its own nameplate. The people inside cannot see or hear the people in the other offices. But everyone is in the same building, using the same shared elevator, same electricity, and same internet connection. Containers share the host kernel the same way offices share the building's infrastructure.

This is fundamentally different from a virtual machine, which has its own complete operating system, its own kernel, and its own hardware emulation layer. That is like renting an entire separate building.

graph TD A[Virtual Machine] --> B[Guest OS and Kernel] B --> C[Hypervisor Layer] C --> D[Host Hardware] E[Container] --> F[App Process Only] F --> G[Shared Host Kernel] G --> D

Why Containers Start in Milliseconds

When you start a VM, the hypervisor has to boot a complete operating system — BIOS initialization, kernel boot, init system startup, service initialization. This takes 30-60 seconds minimum.

When you start a container, there is no OS to boot. The Linux kernel is already running. Docker just creates a new set of namespaces (microseconds), sets up cgroup limits (microseconds), copies the container filesystem view using OverlayFS (milliseconds), and starts the application process. Total: under 1 second for most containers.

At Swiggy, when traffic spikes at 7pm during dinner rush, the autoscaler spins up new container instances in under 5 seconds. With VMs, that same scale-out takes 2-3 minutes. This speed difference changes how you design for capacity.

The Six Linux Namespaces That Make Containers Possible

Namespaces are a Linux kernel feature that creates isolated views of system resources. Docker uses six of them together:

TEXT
PID namespace:
Container sees PID 1 (nginx)
Host sees PID 12345 (same process)
NET namespace:
Container has eth0, 172.17.0.2
Isolated from the host's network
MNT namespace:
Container sees /etc/nginx/nginx.conf
That file does not exist on the host
UTS namespace:
Container hostname: payment-api-xyz
Host hostname: mumbai-prod-node-1
IPC namespace:
Container has its own shared memory
Cannot access host's IPC resources
USER namespace:
Container root (UID 0) maps to
unprivileged host UID 65534

cgroups — Resource Limits That Actually Work

Namespaces provide isolation. cgroups (control groups) provide resource limits. Without cgroups, a container could use all the CPU and memory on the host. With cgroups, Docker enforces hard limits:

Bash
# Set a container to use at most 512MB memory and 1.5 CPU cores
docker run -d \
--name payment-api \
--memory=512m \
--cpus=1.5 \
registry.razorpay.in/payment-api:v3.1.0
# Verify the cgroup limits are set on the host
cat /sys/fs/cgroup/memory/docker/$(docker inspect --format '{{.Id}}' payment-api)/memory.limit_in_bytes
# 536870912 = 512MB in bytes
# If the container tries to use more than 512MB:
# Kernel sends SIGKILL to the container process
# Exit code: 137 (OOMKilled)
# docker inspect shows OOMKilled: true

Container vs Image — The Class and Instance Analogy

A container is a running instance of an image. An image is the template. This is exactly like the class/instance relationship in object-oriented programming:

TEXT
Docker Image = Class definition (blueprint, static, on disk)
Container = Instance (running, has state, in memory)
Bash
# One image can create many containers:
docker run -d --name api-1 nginx:1.25
docker run -d --name api-2 nginx:1.25
docker run -d --name api-3 nginx:1.25
# Three separate containers, all running from the same nginx:1.25 image
# Each container has its own read-write layer
# Changes in api-1 do not affect api-2 or api-3
# All three share the read-only image layers (no duplication on disk)

What Containers Are NOT

Containers are not a full virtual machine — they share the host kernel. They are not completely secure isolation — kernel vulnerabilities affect all containers. They are not persistent storage — files written inside die with the container by default. And they are not a replacement for proper application security, since a compromised container process is still running on the host kernel.

Practical Container Commands

Bash
# Run a container and get a shell inside it
docker run -it ubuntu bash
# -i = interactive (keep stdin open)
# -t = pseudo-TTY (proper terminal)
# See all containers (running and stopped)
docker ps -a
# See the actual processes on the host that containers are
ps aux | grep nginx
# The container's nginx process has a real PID on the host
# See that it is isolated by checking from inside the container
docker exec -it my-nginx ps aux
# You see: PID 1 = nginx master
# On the host you see a different PID for the same process

Quick Reference & Troubleshooting Commands

Problem Cause Fix
Container exits immediately Process inside container exited docker logs container-name to see why
Container uses too much memory No memory limit set Add --memory=512m to docker run
Cannot see container from host network No port published Add -p 8080:80 to docker run
Container filesystem changes lost Wrote to container filesystem, not a volume Mount a volume: -v mydata:/app/data
Container and host share a file Using bind mount Normal: -v /host/path:/container/path
Tip

Run docker run --rm alpine cat /proc/1/cgroup and then run cat /proc/1/cgroup on your host. You will see different cgroup paths — this is the cgroup isolation that limits the container's resources. This is the same Linux feature Kubernetes uses for pod resource limits.

Remember

Containers share the host kernel. A vulnerability in the Linux kernel affects all containers on that host. This is why privileged containers (--privileged) are dangerous — they have access to most of the host's kernel features and can break out of their namespace isolation under certain conditions.

Common Mistake

Thinking containers are completely isolated from each other. They are isolated from each other's filesystems, networks, and processes — but they share the host kernel. A kernel exploit that works inside one container can potentially affect the entire host and all other containers. Container security is about reducing the attack surface, not achieving VM-level isolation.

Security

Never run containers with --privileged unless absolutely necessary. A privileged container disables most of the namespace and capability isolation that makes containers safe. It can access host devices, load kernel modules, and modify network interfaces. If you think you need --privileged, first investigate whether you can achieve the same result by adding only specific capabilities with --cap-add.

Frequently Asked Questions

How is a container actually different from a lightweight VM under the hood?

A VM virtualizes hardware and runs its own full kernel via a hypervisor; a container is just a regular Linux process that the kernel makes think it's isolated, using namespaces (for filesystem, network, PID, and user isolation) and cgroups (for resource limits). Because there's no second kernel or hardware emulation layer, containers start in milliseconds instead of the tens of seconds a VM boot takes, and have near-zero memory/CPU overhead beyond the process itself.

What's a common misconception engineers have about container isolation?

Treating a container as an equivalent security boundary to a VM. Because all containers on a host share the same kernel, a kernel-level exploit or a serious misconfiguration (like running as root with `--privileged`) can potentially escape a container and affect the host or sibling containers — something not possible with proper VM isolation. Don't rely on containers alone as a hard multi-tenant security boundary for genuinely untrusted workloads without extra layers like gVisor or Kata Containers.