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.
+------------------------------------------+| Virtual Machine || +----------------------------------+ || | Guest OS (Ubuntu, Windows, etc.) | || | Guest Kernel | || +----------------------------------+ || | Hypervisor (VMware, KVM, etc.) | |+------------------------------------------+| Host Hardware |+------------------------------------------+ +------------------------------------------+| Container || +----------------------------------+ || | Application Process | || | Isolated via namespaces/cgroups | || +----------------------------------+ || | Host Linux Kernel (shared) | |+------------------------------------------+| Host Hardware |+------------------------------------------+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:
+------------------------------------------+| Container Process || || PID namespace: || Container sees PID 1 (nginx) || Host sees PID 12345 (same process) || || NET namespace: || Container has eth0, 172.17.0.2 || Isolated from 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: prod-server-01 || || 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:
# Set a container to use at most 512MB memory and 1.5 CPU coresdocker 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# cgroups are visible in the /sys/fs/cgroup filesystemcat /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: trueContainer 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:
Docker Image = Class definition (blueprint, static, on disk)Container = Instance (running, has state, in memory) # One image can create many containers:docker run -d --name api-1 nginx:1.25docker run -d --name api-2 nginx:1.25docker 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
- Completely secure isolation — kernel vulnerabilities affect all containers
- Persistent storage — files written inside die with the container by default
- A replacement for proper application security — a compromised container process is running on the host kernel
Practical Container Commands
# Run a container and get a shell inside itdocker run -it ubuntu bash# -i = interactive (keep stdin open)# -t = pseudo-TTY (proper terminal)# You are now inside the container # See all containers (running and stopped)docker ps -a # See the actual processes on the host that containers are# Containers are just processes — you can see them from the hostps 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 containerdocker exec -it my-nginx ps aux# You see: PID 1 = nginx master# On the host you see: PID 12345 = same process# Same process, two different views (two different PID namespaces)Troubleshooting Reference
| 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 behaviour: -v /host/path:/container/path |
PLACEMENT PRO TIP**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 THIS**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 / WARNING**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 about achieving VM-level isolation.
COMMON MISTAKE / WARNING**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 the specific capabilities you need with `--cap-add`.