You want several disposable Linux environments on one machine. Containers and virtual machines can both get you there, but they do not give you the same boundary.
The first question is surprisingly useful: which kernel handles a process’s system calls? A system call is a request from a program to the operating system, such as opening a file or creating a network socket.
Draw the kernel before the boxes
A Linux container gives processes separate views of selected system resources. The processes still use the host’s Linux kernel. A VM runs a guest kernel against virtual hardware.
If a Linux VM hosts ten containers, those containers share the VM’s guest kernel. They are not ten nested VMs. The LXC introduction describes the namespaces and resource controls used for this kind of containment.
Read the diagram vertically. The left-hand environments converge on a shared kernel; the right-hand environments have their own kernels above a hypervisor.
Work through two requirements
Suppose you need to test an application against two Linux userspace distributions. Both work with the same host kernel. Containers can provide different libraries and package sets without starting a new kernel for each environment.
Now change the requirement: you need to test a kernel upgrade and reboot one guest while leaving another guest’s kernel unchanged. Ordinary containers cannot provide that independence. A VM is the appropriate unit to investigate.
The important change is the requirement, not the number of environments. “Ten environments” doesn’t tell you what boundary they need.
Pause and predict
Two containers have different /etc/os-release contents but the same uname -r output. Is that a contradiction?
Need a hint?
One file describes the userspace distribution. The other command asks the running kernel for its release.
Show the reasoning
/etc/os-release does not establish that a separate kernel booted inside the container.Observe it in a disposable environment
On an existing Linux test host, record uname -r. Run the same command inside two test containers, then inspect /etc/os-release in each. Use the container manager’s normal exec or attach command.
On macOS or Windows, a Linux container engine often runs inside a Linux VM. Compare the containers with that VM’s kernel, not with the desktop operating system’s kernel. The extra layer explains otherwise confusing output.
Matching version strings are an observation consistent with sharing a kernel, not a proof by themselves: separate VMs can boot identical kernel versions. Use the runtime architecture to interpret the measurement.
Put resource and failure boundaries on the drawing
Containers need explicit resource controls. A separate filesystem view does not automatically give a process a useful CPU or memory budget. Likewise, using a VM does not automatically distribute failure across physical hosts.
Suppose one VM hosts ten containers. A failure of that VM can stop all ten. Running the application in ten boxes has increased the number of processes you can manage independently, but it has not created ten independent host failure domains.
Nested hardware virtualization is a separate capability. Its availability depends on the host and instance type. The original version of this post made a blanket claim that EC2 could not support it; consult AWS’s nested virtualization requirements for a current deployment.
Try a different requirement
Apply the idea
A team needs two incompatible kernel modules, one per environment. Would changing container images solve the conflict?
Need a hint?
Where are kernel modules loaded?
Show the reasoning
For your own lab, write down the kernel boundary, the resource budget, and the failure domain. Once those are clear, inspect a container host inside a VM.