Docker is using libcontainer, that runs in the same operating system as its host. This allows it to share a lot of the host operating system resources. It also uses layered filesystems like AuFS. It also manages the networking for you as well.
AuFS is a layered file system, so you can have a read only part, and a write part, and merge those together. So you could have the common parts of the operating system as read only, which are shared amongst all of your containers, and then give each container its own mount for writing.
So let’s say you have a container image that is 1GB in size. If you wanted to use a Full VM, you would need to have 1GB times x number of VMs you want. With LXC and AuFS you can share the bulk of the 1GB and if you have 1000 containers you still might only have a little over 1GB of space for the containers OS, assuming they are all running the same OS image.
A full virtualized system gets its own set of resources allocated to it, and does minimal sharing. You get more isolation, but it is much heavier .
With LXC you get less isolation, but they are more lightweight and require less resources. So you could easily run 1000’s on a host, and it doesn’t even blink. Try doing that with Xen, and unless you have a really big host, I don’t think it is possible.
A full virtualized system usually takes minutes to start, LXC containers take seconds, and sometimes even less than a second.
There are pros and cons for each type of virtualized system. If you want full isolation with guaranteed resources, a full VM is the way to go. If you just want to isolate processes from each other and want to run a ton of them on a reasonably sized host, then LXC might be the way to go.