A container is a running, isolated set of processes that packages an application together with its libraries, runtime and configuration, while sharing the kernel of the host operating system. In cloud computing and the Containers topic, the container is the standard unit for building, shipping and running software, because the same packaged workload behaves the same way on a laptop, a test server and a production cluster.
A container is not a lightweight virtual machine. It contains no kernel of its own and boots nothing; it is an ordinary process that the kernel isolates with namespaces, limits with control groups and starts from a read-only container image. That design explains its main advantages, fast startup and high density, and its main weakness, a thinner isolation boundary.
How containers isolate processes on a shared kernel
A container is built from Linux kernel features, not from a separate product. Namespaces give a process its own view of system resources, so it sees only its own process tree, network stack and file system. Control groups (cgroups) cap and account for CPU, memory and I/O, and security layers such as seccomp, capabilities and SELinux or AppArmor restrict what the process may ask the kernel to do.
The table below summarizes the kernel mechanisms that together form a container.
| Mechanism | What it isolates or limits | Practical effect |
|---|---|---|
| PID namespace | Process IDs | The application sees itself as PID 1 |
| Network namespace | Interfaces, routes, ports | Each container has its own IP and port space |
| Mount namespace | File system view | The container sees only its image and volumes |
| User namespace | User and group IDs | Root inside can map to an unprivileged host user |
| cgroups v2 | CPU, memory, I/O, process count | A memory limit triggers an out-of-memory kill |
| seccomp filter | System calls | Blocks rarely needed, risky kernel calls |
The file system comes from a layered container image mounted through a union file system such as OverlayFS. Image layers are read-only and shared between all containers that use them, and each container adds a thin writable layer that disappears when the container is removed. Data that must survive therefore belongs in volumes, not in the container itself.
Container standards, runtimes and lifecycle
Containers are portable because the industry agreed on Open Container Initiative (OCI) specifications: the image specification defines how layers and metadata are packaged, the runtime specification defines how a bundle is started, and the distribution specification defines how registries serve images. Any compliant tool can run an image built by any other compliant tool.
Several layers of software cooperate to run a single container, each with a distinct responsibility.
| Layer | Examples | Responsibility |
|---|---|---|
| Build tool | Docker build, BuildKit, Buildah | Turns a Dockerfile into an OCI image |
| Registry | Public or private OCI registries | Stores and distributes image layers |
| High-level runtime | containerd, CRI-O | Pulls images, manages container lifecycle |
| Low-level runtime | runc, crun | Creates namespaces and cgroups, starts the process |
| Sandboxed runtime | gVisor, Kata Containers | Adds a user-space kernel or a microVM boundary |
| Orchestrator | Kubernetes, Nomad | Schedules containers across many hosts |
The lifecycle is short and predictable: a container is created from an image, started, stopped and removed. Because a new container can replace an old one in seconds, teams treat containers as immutable and disposable: they rebuild the image and redeploy instead of patching a running container.
Containers compared with virtual machines
The essential difference is the level of virtualization: a virtual machine emulates hardware and runs its own kernel, while a container shares the host kernel and isolates only the user space. The comparison below shows how this affects everyday operations.
| Property | Container | Virtual machine |
|---|---|---|
| Kernel | Shared with the host | Own guest kernel |
| Startup time | Typically under one second | Tens of seconds to minutes |
| Typical image size | Tens to hundreds of megabytes | Several gigabytes |
| Isolation strength | Process-level, kernel attack surface shared | Hardware-enforced by the hypervisor |
| OS flexibility | Linux containers need a Linux kernel | Any guest OS for the architecture |
| Best fit | Microservices, CI jobs, scalable stateless apps | Mixed operating systems, strong tenant isolation |
The two technologies are complementary. In public clouds, containers usually run inside virtual machines, which provide the tenant boundary, while containers provide packaging and density. Where untrusted code must run in containers, sandboxed runtimes such as gVisor or Kata Containers restore much of the VM-level isolation.
Designing applications for containers
An application gains the most from containers when it follows a few design rules. The most important is one main process per container, so that the container’s lifecycle equals the application’s lifecycle and health checks, logs and restarts stay unambiguous.
- Keep containers stateless: store sessions, uploads and databases in volumes or external services.
- Configure through environment variables and mounted files, so the same image runs in every environment.
- Log to standard output and standard error, letting the platform collect and ship the logs.
- Set CPU and memory limits so that one container cannot starve its neighbors on the node.
- Run as a non-root user and drop Linux capabilities that the application does not need.
- Use small base images and multi-stage builds to reduce size and vulnerability count.
A single container is easy to run by hand; dozens are not. Local multi-container setups are typically described with Docker Compose, while production fleets rely on an orchestrator that handles scheduling, scaling, service discovery and rolling updates.
Common container problems and their causes
Most container incidents come from a small set of misunderstandings about ephemeral storage, resource limits and privileges. The table below links typical symptoms to their usual cause and fix.
| Symptom | Likely cause | Fix |
|---|---|---|
| Data lost after restart | Files written to the writable layer | Mount a persistent volume |
| Exit code 137 | Memory limit exceeded, OOM kill | Raise the limit or reduce memory use |
| Slow, throttled responses | CPU quota reached within each period | Adjust CPU limits, profile hot paths |
| Image with hundreds of CVEs | Large, outdated base image | Use a minimal base and rebuild regularly |
| Container escape risk | Privileged mode or mounted Docker socket | Remove privileges, use rootless runtimes |
| Zombie processes | No init to reap child processes | Add a minimal init or use the runtime flag |
The largest misconception is that a container is a security boundary equal to a VM. A kernel vulnerability can affect every container on the host, so multi-tenant platforms layer additional isolation rather than relying on namespaces alone.
The short version
A container is like a standardized shipping container for software. Before shipping containers, every cargo was packed differently and loading ships was slow. After standardization, any crane, truck or ship could move any container without caring what was inside.
Software containers do the same. A program is packed together with everything it needs to run, so it works the same way on any computer that can run containers. Many containers share one machine efficiently because they share its core operating system instead of each bringing a full copy.
Where it makes a difference
An online retailer runs its checkout service on three virtual machines that were configured by hand over several years. Each server has slightly different library versions, so a release that passes testing occasionally fails in production, and adding capacity before a holiday sale takes about two days of manual setup.
The team packages the checkout service as a container image of roughly 120 MB, built automatically on every merge and stored in a private registry. The same image runs on developer laptops, in the test pipeline and in production, with only environment variables changing between them. Each container gets a limit of 1 vCPU and 512 MiB of memory.
During the next sale, the platform scales from 6 to 40 checkout containers in under two minutes as traffic rises, then scales back down overnight. Release failures caused by environment differences disappear, because what was tested is exactly what runs.