Containerizing the GUI separates your work and play.
Virtualization has always been a rich man's game, and more frugal
enthusiasts—unable to afford fancy server-class components—often
struggle to keep up. Linux provides free high-quality hypervisors, but when
you start to throw real workloads at the host, its resources become
saturated quickly. No amount of spare RAM shoved into an old Dell desktop
is going to remedy this situation. If a properly decked-out host is out of
your reach, you might want to consider containers instead.
Instead of virtualizing an entire computer, containers allow parts of the Linux
kernel to be portioned into several pieces. This occurs without the
overhead of emulating hardware or running several identical kernels. A full
GUI environment, such as GNOME Shell can be launched inside a container,
with a little gumption.
You can accomplish this through namespaces, a feature built in to the Linux
kernel. An in-depth look at this feature is beyond the scope of this
article, but a brief example sheds light on how these features can create
containers. Each kind of namespace segments a different part of the kernel.
The PID namespace, for example, prevents processes inside the namespace
from seeing other processes running in the kernel. As a result, those
processes believe that they are the only ones running on the computer. Each
namespace does the same thing for other areas of the kernel as well. The
mount namespace isolates the filesystem of the processes inside of it. The
network namespace provides a unique network stack to processes running
inside of them. The IPC, user, UTS and cgroup namespaces do the same for
those areas of the kernel as well. When the seven namespaces are combined,
the result is a container: an environment isolated enough to believe it is
a freestanding Linux system.
Container frameworks will abstract the minutia of configuring namespaces
away from the user, but each framework has a different emphasis. Docker is
the most popular and is designed to run multiple copies of identical
containers at scale. LXC/LXD is meant to create containers easily that
mimic particular Linux distributions. In fact, earlier versions of LXC
included a collection of scripts that created the filesystems of popular
distributions. A third option is libvirt's lxc driver. Contrary to how
it may sound, libvirt-lxc does not use LXC/LXD at all. Instead, the
libvirt-lxc driver manipulates kernel namespaces directly. libvirt-lxc
integrates into other tools within the libvirt suite as well, so the
configuration of libvirt-lxc containers resembles those of virtual machines
running in other libvirt drivers instead of a native LXC/LXD container. It
is easy to learn as a result, even if the branding is confusing.