How to Implement Doom UI Streaming in Docker

Written by mattmcclaskey | Published 2020/10/14
Tech Story Tags: docker | gaming | streaming | doom | docker-image | programming | coding | videogames

TLDR Kasm is a new containerized desktop infrastructure (CDI) solution. The benefit of using the full Kasm stack is scalability, ease of management, and enterprise features like SAML and LDAP authentication, logging, persistent profiles, and more. Kasm has a community edition, which has all the same features as the paid, but is limited to 5 concurrent users. As a test, we will be containerizing Doom. What better way to demonstrate the containerization of UI applications than killing daemons?via the TL;DR App

Docker is all the rage these days, with its simple and elegant way to package applications and even entire systems into something that can be ran on any Linux host with Docker installed. But what if Docker could be extended to desktop applications?
That would open up all kinds of new use cases for containerization. This is where Kasm and KasmVNC come in. Kasm is a new containerized desktop infrastructure (CDI) solution while KasmVNC is the open source core that provides the rendering of the containerized desktop environment. Kasm is 100% web based on the front-end with no software to install for clients.
This blog will walk you through how to implement UI streaming using nothing but open source and then the full Kasm stack. The benefit of using the full Kasm stack is scalability, ease of management, and enterprise features like SAML and LDAP authentication, logging, persistent profiles, and more. Kasm has a community edition, which has all the same features as the paid, but is limited to 5 concurrent users.
As a test, we will be containerizing Doom. What better way to demonstrate the containerization of UI applications than killing daemons in this 1990s classic first person shooter.
Disclaimer: I am co-founder of Kasm Technologies and the KasmVNC open source project.

Open Source Route

Who doesn’t like a fully open source solution to a problem? It is completely possible to implement much of what Kasm does using our open source KasmVNC and the docker image examples we provide.
The KasmVNC GitHub page provides the Doom example right in the code repository https://github.com/kasmtech/KasmVNC/tree/master/docker.
git clone https://github.com/kasmtech/KasmVNC.git
cd KasmVNC/docker
sudo docker build -t kasm/doom -f Dockerfile.ubuntu18.doom .
sudo docker run -it -p 443:8443 — rm -e “VNC_USER=matt” -e “VNC_PW=password123” kasm/doom:latest
Now navigate to https://<your-ip>
Ok, that was too easy, lets break down that dockerfile and see what is going on…
FROM ubuntu:18.04
ENV DISPLAY=:1 \
  VNC_PORT=8443 \
  MAX_FRAME_RATE=24 \
  VNCOPTIONS="-PreferBandwidth -DynamicQualityMin=4 -DynamicQualityMax=7" \
  HOME=/home/user \
  TERM=xterm \
  STARTUPDIR=/dockerstartup \
  INST_SCRIPTS=/dockerstartup/install \
  KASM_RX_HOME=/dockerstartup/kasmrx \
  DEBIAN_FRONTEND=noninteractive \
  VNC_COL_DEPTH=24 \
  VNC_RESOLUTION=640x480 \
  VNC_PW=vncpassword \
  VNC_USER=user \
  VNC_VIEW_ONLY_PW=vncviewonlypassword \
  LD_LIBRARY_PATH=/usr/local/lib/ \
  OMP_WAIT_POLICY=PASSIVE \
  SHELL=/bin/bash \
  SINGLE_APPLICATION=1
EXPOSE $VNC_PORT
WORKDIR $HOME
### REQUIRED STUFF ###
RUN apt-get update && apt-get install -y supervisor xfce4 xfce4-terminal xterm libnss-wrapper gettext libjpeg-dev wget
RUN apt-get purge -y pm-utils xscreensaver*
RUN mkdir -p $STARTUPDIR
COPY src/startup/ $STARTUPDIR
RUN mkdir -p $HOME/.config/xfce4/xfconf/xfce-perchannel-xml
COPY src/xfce/ $HOME/.config/xfce4/xfconf/xfce-perchannel-xml
# overwite default with single app config
RUN mv $HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop-single-app.xml $HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml
RUN echo 'source $STARTUPDIR/generate_container_user' >> $HOME/.bashrc
# KasmVNC install
RUN wget -qO- https://github.com/kasmtech/KasmVNC/releases/download/v0.9.1-beta/KasmVNC_0.9.1-beta_Ubuntu_18.04.tar.gz | tar xz --strip 1 -C /
RUN cp /usr/local/share/kasmvnc/www/vnc.html /usr/local/share/kasmvnc/www/index.html
### START CUSTOM STUFF ####
# We need the server to use a fixed resulution and have the client scale, which is not the default behavior of KasmVNC
RUN sed -i "s#UI.initSetting('resize', 'remote');#UI.initSetting('resize', 'scale');#" /usr/local/share/kasmvnc/www/app/ui.js
RUN apt-get install -y chocolate-doom doom-wad-shareware prboom-plus freedoom
# Use software rendering, comment this out if you have a GPU
#RUN mkdir -p $HOME/.local/share/chocolate-doom && \
#       echo 'force_software_renderer    1' > $HOME/.local/share/chocolate-doom/chocolate-doom.cfg
### END CUSTOM STUFF ###
RUN chown -R 1000:0 $HOME
USER 1000
WORKDIR $HOME
ENTRYPOINT [ "/dockerstartup/vnc_startup.sh", "xfce4-terminal", "-e", "/usr/games/chocolate-doom" ]
We are interested in a few environmental variables up top. Any of these can be overridden at run time, you can see in the docker run example we over wrote the username and password used for KasmVNC. The VNC_PW environmental variable is unset during startup, so your password is not kept in that variable at runtime. Another environmental variable of interest is the last one SINGLE_APPLICATION, which will get rid of the desktop and just display the single app in the KasmVNC webpage.
After that is the required stuff, which is the installation of a desktop environment, KasmVNC, and copying over configurations and scripts. The meat of what you need is after the “START CUSTOM STUFF HERE” comment. You can see that doom is installed. Just before that you see a sed command, this is changing the KasmVNC web page to default to client scaling, which locks the server into the configured resolution.
By default KasmVNC automatically scales the server side resolution as the client resolution changes, which is not advantageous for this example, but for most desktop applications is highly preferred. So, you may want to comment that line out for your specific use case.
Finally, the ENTRYPOINT, needs to be customized. It needs to have /dockerstartup/vnc_startup.sh first, followed by commands and arguments for your application. To get Doom to work for me, I had to open an xfce4-terminal first and execute Doom from there. In most situations you would likely just execute the GUI application directly.

Full Kasm Stack

Running Doom inside a streaming container is cool, but what if we had an enterprise use case for streaming UI containers to a bunch of users and needed stuff like SAML authentication, logging, performance metrics and analytics, audio in and out, and all that nice commercial grade gravy. That’s where Kasm comes in. Kasm is available in Community Edition, Professional, and Enterprise and can run in the cloud as a SaaS, on-premise, or in a hybrid configuration.
Kasm actually open sources examples of how to create your own Kasm compatible docker images, to include single applications. Here is a link to the Chrome Container: 
Installation
Kasm installation on a single server deployment is very easy, full details can be found here: 
The short of it is, install docker, download the kasm release tar file and run a few commands. The installation will download the base images, so it will take about 10 minutes to install depending on the speed of your internet.
wget https://kasm-static-content.s3.amazonaws.com/kasm_release_1.7.0.a80105.tar.gz
tar -xzvf kasm_release_1.7.0.a80105.tar.gz
sudo bash kasm_release/install.sh
If you are running on a cloud VM with no swap, you will get a warning, just press y to continue. At the end of the installation it will list all the credentials, which are randomly generated during the install. Navigate to the web page https://<ip-address> and login as [email protected] using the password provided.
Next go to Users and click the key icon next to the [email protected] user and change the password.

Custom Kasm Image

The custom Kasm image is slightly different then the open source version. Create a file dockerfile.doom with the following contents.
FROM kasmweb/core:1.7.0
USER root
ENV HOME /home/kasm-default-profile
ENV STARTUPDIR /dockerstartup
ENV INST_SCRIPTS $STARTUPDIR/install
WORKDIR $HOME
######### Customize Container Here ###########
# Install Doom
RUN apt-get install -y chocolate-doom doom-wad-shareware prboom-plus freedoom
# Enabled Single Application Mode - No desktop environment will be spawned
RUN wget -O $HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml https://bitbucket.org/kasmtech/kasm_release/raw/44c6c00e086649f54e8b2756601f710dbca89805/src/common/install/kasm/xfce_settings/xfce4-desktop-single-app.xml
ENV SINGLE_APPLICATION=1
RUN apt-get remove -y xfce4-panel
RUN echo 'xfce4-terminal -e /usr/games/chocolate-doom' > $STARTUPDIR/custom_startup.sh
RUN chmod +x $STARTUPDIR/custom_startup.sh
######### End Customizations ###########
RUN chown 1000:0 $HOME
RUN $STARTUPDIR/set_user_permission.sh $HOME
ENV HOME /home/kasm-user
WORKDIR $HOME
RUN mkdir -p $HOME && chown -R 1000:0 $HOME
USER 1000
Now we can build our Doom Kasm.
sudo docker build -t kasmweb/doom:1.7.0 -f dockerfile.doom .
Next log into Kasm as an administrator and navigate to Images. Click “Create New Image” in the upper right corner. Fill in the details as shown in this screenshot, feel free to provide a thumbnail image, but it is not require. This is a locally built image, so be sure to leave the Docker Registry details empty.
  • Name — Must be the docker image name kasmweb/doom:1.7.0
  • Description — Anything you want
  • Friendly Name — The name displayed to users
  • Thumbnail URL — The image to display to users, here I used the image from wikipedia
  • Cores — The number of cores to allow for this image. Two seems adequate but you might get away with one if you have a good CPU.
  • RAM — In my testing 1.7GB was plenty of RAM to explore the underworld
Click save and go back to User->Kasm and you will see the image available to create.
Click Create, now you can enjoy Doom with audio, share the session with other users, and start your own Doom SaaS.

Written by mattmcclaskey | Kasm Tech CTO and Docker fan boy
Published by HackerNoon on 2020/10/14