VMs are literally so hard to do correctly and in a performant fashion that parts of CPU instruction sets[0], and kernel subsystems (KVM[1]) were created to make them easier to run. Containers, in contrast are literally a few flags and a bunch of in-kernel antics.
A few people, notably Liz Rice and Jessie Frazelle have given talks on how to make containers from scratch that are very illuminating for those that are interested:
https://www.youtube.com/watch?v=HPuvDm8IC-4
https://www.youtube.com/watch?v=cYsVvV1aVss
[0]: https://en.wikipedia.org/wiki/X86_virtualization
[1]: https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine
VMs are "hard" because you start with nothing save some very low-level help from the hardware.
What I should have made clearer was that I think containers are both easier and simpler than VMs. There are both less moving parts (I haven't looked, but I assume less code), and containers are easier to get started with than VMs (set some flags on some syscalls versus make sure you buy the right CPU).
That isn't pedantry, it is an extremely critical point and the one most people miss when figuring out Docker. Both from a security context (docker doesn't provide vm level promises about isolation) and from a resource management side (docker is really close to no overhead).
It is not uncommon to deploy containers on VMs in the real world...