TL;DR: In the containers vs virtual machines comparison, a virtual machine boots a complete guest operating system on virtual hardware, while a container runs the application and its dependencies as plain processes on a kernel it shares with the host: that one difference makes containers lighter, faster to start and cheaper to move, and less strongly isolated.
The image bundles code, exact dependency versions and configuration, so one unit serves development, test and production on any Docker-equipped host.
Underneath, isolation rests on two kernel facilities: namespaces scope what a process can observe, and cgroups cap its CPU time and memory.
The idea predates the product by three decades: chroot dates to 1982, LXC to 2008, and Docker’s open-sourcing to March 2013.
Production stacks both: Kubernetes schedules each container into a pod on a node, and that node can be a virtual machine or a physical one.
“It works on my machine” survives as an excuse because it is true: the application ships, and the…