Docker as an Alternative to Virtual Machines for Transient Environments That Require a GUI
Tags: docker, nomachine, linux, automation
Published: 2020-05-01 08:29:36

It is not uncommon, especially in consulting, to have to try several stacks of tools from different vendors, most of the times at an alarming rate.

Over the past few weeks I've been setting up a new project for a customer (full remote team, due to COVID-19), for which the tooling will revolve around Red Hat Openshift and Fuse.

Enforcing consistent tools and configuration is one of the main concerns when working with geographically dispersed teams, which is increasingly difficult when the tools are UI bound, as is the case of Red Hat CodeReady Studio, which basically sits on top of Eclipse and has many a Wizard or Diagram to work with.

This consistency has over the years taken different shapes and forms:

ZIP Files, Virtual Machines, Installation from Network in LAN cases, Chef, Vagrant, you name it...

Virtual Machines (such as the ones ran on VirtualBox) end up being the easy and low (well, zero) cost approach to the problem, but they come at a prohibitive download size and are extremely hard to maintain unless you opt for a mix-in with Chef or Vagrant.

It does need to be said that Windows Subsystem for Linux 2 might address some of these issues, but it is not fully mature yet and not all company provided laptops or desktops will be able to use it anytime soon.

**Enter Docker!**

First things first, I'm completely aware that Docker is not mean to substitute Virtual Machines, and it's highly questionable if it is appropriate for graphical use.

Still, I wanted to try to streamline some of the work and gave it a shot through a lot of iterations:

There are a lot of technologies and protocols that allow remote display:

X11, VNC, RDP are the most common and with the notable exception of RDP in Windows and whichever VMWare or VirtualBox are using, they all suck as far as performance is concerned, even without network hops (ie: loopback adapter).

After successfully running apps and window managers inside a Docker container (which is easier said than done), I was left with appalling performance even with local X11 Forwarding, which might be due to the fact that I'm on Windows 10, but it is the default company policy, no use in crying.

**Enter NoMachine!**

I came across NoMachine at the very end of some Reddit thread which lead to https://www.nomachine.com/DT08M00100

NoMachine is an amazing piece of software as far as ease of installation, configuration and performance goes. There is barely any performance degradation in using CodeReady inside the container, and CodeReady doesn't benefit from many optimizations as far as rendering goes due to the fact that it is written in Java with SWT.

Further down you can find a guide on how to use the solution I came across, which needs a lot of hacking and tweaking still, but the results are promising.

I'm not advocating that entire teams of developers need to be forced to have a worse development experience and productivity, since the native version of something will always be more performant, but there are some important niches to explore.

One of them is training. There is really no good excuse for having someone install a software for training purposes (unless it's ops training), and if you can provide someone with a way to pull an pre-built environment of 1.5GB instead of a 15GB one, that counts for something.

Additionally, with the layering capabilities of Docker, this pre-built environment is a lot more dynamic. You can have a base image with the desktop environment, required services and packages, which is quite small compressed (450MB with Xcfe, which isn't a lightweight desktop environment by any standard), and progressively add more specialized images, with git, jdk, ide's, etc...

Other important niches include prototyping, proof of concepts, evaluation of tools, assessing the impact of new software versions, etc... 
These things I end up doing a lot, and being able to dispose and change an environment in such a fast way is a huge time saver.

It is also a nice added bonus that you can distribute this weird type of container alongside "regular" ones with Docker Compose, and then we can setup extremely complex environments with great control and ease of change.

Hopefully this is useful for someone and can start some healthy debate, and I'm more than open to feedback here or in github.

The following guide is also available (and will be updated) at https://github.com/cmanique/docker-fedora-xfce-nomachine but part is here for the sake of the post

### Start a container

```
$ docker run --cap-add=SYS_PTRACE -d -p 4000:4000 --name fedora-xfce-nomachine cmanique/fedora-xfce-nomachine
```

> note the container needs to be run as a daemon (unless you want it to run privileged, and it's pointless because of the entrypoint)

### Bash into the container with docker exec

```
$ docker exec -it fedora-xfce-nomachine bash
```

### Start the NoMachine server

```
$ /usr/NX/bin/nxserver --startup

NX> 111 New connections to NoMachine server are enabled.
NX> 161 Enabled service: nxserver.
NX> 162 WARNING: Cannot find X servers running on this machine.
NX> 162 WARNING: A new virtual display will be created on demand.
NX> 161 Enabled service: nxd.
```

### Download NoMachine

Open https://www.nomachine.com/download on your browser and download the appropriate installer (Windows, Mac, Linux)

### Install NoMachine on your Docker **host**

Follow the instructions at https://www.nomachine.com/DT02O00124 in order to correctly install the software on your computer

### Start the NoMachine Client and Create a New Connection

![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-001-nomachine-new.jpg?raw=true)

### Choose **NX** as protocol and click **Continue**

![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-002-nomachine-protocol.jpg?raw=true)

### Ensure the default values are appropriate and click **Continue**

![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-003-nomachine-host.jpg?raw=true)

### Ensure authentication is set to **Password** and click **Continue**
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-004-nomachine-authentication.jpg?raw=true)

### Ensure **Don't use a proxy** is selected and click **Continue**
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-005-nomachine-proxy.jpg?raw=true)

### Name your connection accordingly and click **Done**
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-006-nomachine-saveas.jpg?raw=true)

### **Double-click** the newly created connection
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-007-nomachine-connect.jpg?raw=true)

### Enter the **Username** and **Password**, optionally save the credentials and click **OK**
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-008-nomachine-unp.jpg?raw=true)

> for the time being the credentials are hard-coded on the Dockerfile as nomachine/nomachine

### Tick **Always create a new display on this server** and click **Yes**
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-009-nomachine-createdisplay.jpg?raw=true)

### Tick **Mute audio on the server while I'm connected**, **Don't show this message again for this connection**, select the second icon on the bottom row in order to resize the remote display to your window and click **OK**
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-010-nomachine-audio.jpg?raw=true)

### Enjoy your Fedora Xfce Desktop
![alt](https://github.com/cmanique/docker-fedora-xfce-nomachine/blob/media/readme-011-nomachine-fullscreen.jpg?raw=true)

> this case shows Red Hat CodeReady Studio, which was also installed through Docker, by having an image extending this one

### Stop the container

```
$ docker stop fedora-xfce-nomachine
```