Virtualisation and containerisation solve the same historical problem from two different levels of abstraction: how to isolate and package software so that it runs reproducibly, independent of the underlying hardware. The virtual machine virtualises the entire hardware and loads a guest operating system on top of a hypervisor (VMware ESXi, KVM, Hyper-V). The container, by contrast, virtualises the operating system: it shares the host's kernel and isolates processes through Linux kernel primitives such as namespaces (visibility isolation) and cgroups (resource control). That difference explains why a container starts in milliseconds and weighs megabytes, whereas a virtual machine takes seconds or minutes and occupies gigabytes.
Docker popularised containers in 2013 by offering a simple packaging experience, and Kubernetes—released by Google in 2014 and today under the Cloud Native Computing Foundation—has become the standard orchestrator for running containers at scale. In this article we break down both technologies with technical rigour: how an image is built, how Kubernetes orchestrates, which mistakes are costly in production and what security regulations apply.
Docker: images, layers and the packaging model
A Docker image is an immutable, read-only template, built in stacked layers (each instruction in the Dockerfile generates a layer) on top of a union file system (overlayfs). A container is a running instance of that image, with a thin writable layer on top. This layered architecture makes it possible to share common layers across images and to speed up downloads, since only the new layers are transferred.
Docker's value is reproducibility: the classic "it works on my machine" disappears because the image contains the application and all its dependencies frozen in place. Good build practices include:
- Multi-stage builds: compiling in a heavy image and copying only the resulting binary into a minimal final image, drastically reducing the size and the attack surface.
- Minimal base images (Alpine, distroless) to limit vulnerable dependencies.
- Running as a non-root user with the
USERdirective, preventing a container escape from inheriting host privileges. - Immutability and versioned tagging instead of
:latest, to guarantee deterministic deployments.
Kubernetes: orchestrating containers at scale
When you move from a handful of containers to hundreds spread across dozens of servers, you need an orchestrator that decides where to place each workload, restarts whatever fails, scales according to demand and routes the traffic. That is Kubernetes. Its architecture separates the control plane (the kube-apiserver as the entry point, etcd as the state store, the scheduler that assigns pods to nodes and the controllers that reconcile) from the worker nodes, where the kubelet runs the containers through a CRI-compatible runtime (containerd, CRI-O).
The smallest deployable unit is not the container but the pod, which groups one or more containers that share network and storage. On top of pods, Kubernetes offers declarative abstractions: the Deployment manages replicas and progressive rollouts (rolling updates), the Service provides a stable IP and load balancing to a set of pods, the Ingress exposes HTTP/S externally, and the ConfigMap and Secret externalise configuration and credentials. The model is declarative: the user describes the desired state in YAML and the Kubernetes reconciliation loop works tirelessly to make the actual state match it.
Autoscaling is articulated on three levels: the Horizontal Pod Autoscaler (HPA) adds or removes replicas according to CPU, memory or custom metrics; the Vertical Pod Autoscaler adjusts the resources per pod; and the Cluster Autoscaler adds or removes nodes from the cloud provider according to aggregate demand.
Comparison table: virtual machine versus container
| Dimension | Virtual machine | Container |
|---|---|---|
| Isolation | Full hardware (hypervisor) | Process (namespaces + cgroups) |
| Operating system | Full guest OS per VM | Shares the host kernel |
| Start-up time | Seconds to minutes | Milliseconds |
| Typical size | Gigabytes | Megabytes |
| Density per host | Dozens | Hundreds or thousands |
| Isolation surface | Larger (own kernel) | Smaller (shared kernel) |
The practical conclusion is not that one technology replaces the other: they coexist. It is common to run Kubernetes on top of virtual machines, combining the strong isolation of the VM at the security boundary with the density and agility of the container at the application layer.
Microservices and the deployment pattern
Containers are the natural vehicle for the microservices architecture, in which a monolithic application is broken down into small services that can be deployed and scaled independently. This enables zero-downtime deployments through strategies such as rolling update (Kubernetes replaces pods progressively), blue-green (two parallel environments with traffic switching) or canary (a small percentage of traffic is routed to the new version and observed before rolling it out widely). These techniques are the basis of modern continuous delivery, integrated with CI/CD pipelines and, increasingly, with GitOps (Argo CD, Flux), where the Git repository is the single source of truth for the cluster's state.
Security and regulations in container environments
The attack surface changes compared with virtual machines and demands specific controls. NIST SP 800-190, the Application Container Security Guide, is the official reference and addresses risks in the image (vulnerabilities, embedded secrets), the registry, the orchestrator and the runtime. The CIS organisation publishes hardening benchmarks for both Docker and Kubernetes, which it is advisable to apply as a baseline. Concrete measures: scan images in the pipeline (Trivy, Clair), sign images (Cosign/Sigstore), apply Network Policies to microsegment east-west traffic, use RBAC with least privilege and manage secrets with an external store (Vault) instead of leaving them in environment variables.
On the compliance front, when containers process personal data the GDPR applies: the principle of security of processing (Article 32) requires encryption and minimisation, and the portability of containers across regions and providers must respect the rules on international data transfers.
Common mistakes in production
The first is not defining resource limits (requests and limits): without them, a runaway pod consumes all the node's memory and triggers the eviction of its neighbours. The second is treating containers as pets rather than cattle, keeping state inside the container instead of in persistent volumes or external databases. The third is running as root and mounting the Docker socket inside the container, which is equivalent to giving away the host. The fourth is ignoring the health checks (liveness and readiness probes), without which Kubernetes does not know whether a pod is actually ready to receive traffic. The fifth, very common, is adopting Kubernetes for three services: its operational complexity only pays off at a certain scale, and for small workloads Docker Compose or a managed PaaS is often enough.
Frequently asked questions
Do I need Kubernetes if I already use Docker?
Not necessarily. Docker solves the packaging and execution of containers on a host. Kubernetes solves the orchestration of many containers across many hosts: autoscaling, recovery from failures, progressive rollouts and load balancing. If you manage a few services on a single server, Docker Compose may be enough; Kubernetes adds value when scale and high availability justify it.
Are containers less secure than virtual machines?
The container's isolation is weaker because it shares the host's kernel, so an escape potentially compromises the whole machine. However, with minimal images, non-root execution, network policies, vulnerability scanning and, where strong isolation is required, sandbox runtimes (gVisor, Kata Containers), you reach a level of security suitable for production. The rule is defence in depth.
Which runtime does Kubernetes use now that Docker was deprecated?
Kubernetes removed the dockershim component, but this does not mean that Docker images stop working: they follow the OCI standard and run with CRI-compatible runtimes such as containerd (which in fact underlies Docker) or CRI-O. The change was internal; images built with Docker remain fully valid.
How are state and databases managed in containers?
State is externalised in persistent volumes (PersistentVolume) backed by block or network storage. For databases in Kubernetes, StatefulSets are used, which provide a stable network identity and dedicated storage per replica, although many organisations prefer to delegate the database to a managed service from the cloud provider because of its criticality.
Conclusion
The choice between virtual machines and containers is not a duel, but a decision about layers: the VM provides strong isolation at the security boundary and containers provide density, start-up speed and reproducibility at the application layer, and the usual approach in 2026 is to combine them by running Kubernetes on top of VMs. Docker solved the reproducible packaging that eliminated "it works on my machine", and Kubernetes solved the declarative orchestration that allows hundreds of containers to self-heal and scale without manual intervention. The real risk is not in the technology but in adopting it without discipline: root containers without resource limits, unscanned images and clusters without RBAC turn a modern architecture into an attack surface. Adopting containers pays off when the scale justifies it and when hardening (NIST SP 800-190, CIS benchmarks) is treated as a requirement rather than a decoration. At Summum Systems we design reproducible container architectures, CI/CD pipelines with image scanning and hardened Kubernetes clusters, sized to each client's real scale rather than to the fashion of the moment.