Containers versus virtual machines: images, layers and isolation
In short: A container packages an application with its dependencies and runs it as an isolated process on a shared kernel. Images are built from read-only layers and stored in registries. Containers start fast and are small, but their isolation is weaker than a virtual machine, which shapes how you secure them.
What a container is
A container is an ordinary Linux process (or group of processes) that the kernel isolates so it sees its own filesystem, network and process list. It is created from an image: a read-only bundle containing the application, its libraries and a minimal set of operating system files. Because everything the app needs is inside the image, it behaves the same on a laptop, a test server and in the cloud.
The formats are standardised by the Open Container Initiative (OCI), so images built with Docker, Podman or Buildah run on containerd, CRI-O and Kubernetes alike.
Containers versus virtual machines
A virtual machine runs a complete guest operating system on virtual hardware provided by a hypervisor. A container shares the host's kernel and relies on kernel features for isolation:
- Namespaces give each container its own view of process IDs, network interfaces, mount points, hostnames and users.
- Control groups (cgroups) limit CPU, memory and other resources so one container cannot starve the rest.
- Capabilities, seccomp and AppArmor or SELinux restrict which privileged operations and system calls are allowed.
| Aspect | Virtual machine | Container |
|---|---|---|
| Isolation boundary | Hypervisor, strong | Shared kernel, weaker |
| Kernel bug impact | Affects one VM | Can affect every container on the host |
| Start time | Tens of seconds to minutes | Usually seconds or less |
| Typical lifetime | Months, patched in place | Hours or days, replaced not patched |
Where stronger isolation is needed, for example running untrusted customer code, you can use sandboxed runtimes such as gVisor or lightweight VMs such as Kata Containers and Firecracker.
Images, layers and registries
Each instruction in a build file such as a Dockerfile creates a layer. Layers are shared and cached, which saves space and speeds up builds. Images are stored in a registry (Docker Hub, Amazon ECR, Azure Container Registry, GitHub Container Registry or a private registry) and identified by a name, a tag and a content digest.
docker pull nginx:1.27-alpine
docker image ls
docker image history nginx:1.27-alpine
docker run -d --name web -p 8080:80 nginx:1.27-alpine
Tip: deleting a file in a later layer does not remove it from the earlier layer. A secret copied in and then deleted is still inside the image for anyone who pulls it.
Why this matters for security
- Shared kernel: a container escape or kernel exploit can reach the host and its neighbours, so keep hosts patched and containers unprivileged.
- Inherited vulnerabilities: everything in the base image ships with your app; see image security.
- Supply chain: you often run images built by strangers, so trust and signing matter.
- Short lifetimes: evidence disappears when containers are replaced, so central logging is essential.
- Immutability: the good side is that you fix problems by rebuilding and redeploying, not by logging in and patching.
Practice
Why is a kernel vulnerability more serious for containers than for virtual machines?
What do namespaces and cgroups each provide?
A password was added in one Dockerfile step and deleted in the next. Is it gone from the image?
Key takeaways
- Containers are isolated processes sharing the host kernel.
- Namespaces isolate views; cgroups limit resources.
- Images are read-only layers stored in registries and identified by digests.
- Isolation is weaker than a VM, so host and kernel security matter.
- Containers are replaced rather than patched, which suits automation.
Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.