I'm always looking for a way to automate things and improve my setup, so I spent a little time to see if I could get Everquest running in Docker. In another post, I explained how to get EQ running on Linux, hopefully this will help more people get it running due to the standardization that Docker brings.
You'll need a few things to get started:
Running the Container
We will come back to building the container in a minute, but I wanted to briefly touch on running the container. To get Docker to run games there are a few things we need to focus on that are different from running normal server applications.
#1 - GPU Acceleration.
This is where the Nvidia card comes in. Nvidia has released docker support for passing the GPU into a container by way of the nvidia-container-toolkit. Once this is installed on your system, all that is needed to pass the GPU into a given container is to use the
#2 - Displaying the GUI.
As anyone familiar with Docker knows, it is easy to map any file into a docker container with the
#3 - Sound.
If you are running pulse audio, some configuration needs to be done to tell the container to use the host's pulse audio daemon. I'll share a configuration file to do so below.
#4 - Running the game under Wine.
I've already covered this in a previous post and things don't change much for the Docker version once everything is set up. You can refer back to that article for details but we'll take care of everything in the Dockerfile.
Building the Containers
In my setup, I actually chose to build two containers. The first is a container I call
Make a folder called winegame and put the following in the winegame folder in a file called Dockerfile:
A few notes about the above Dockerfile:
Now it's time to build your container. From within the winegame/ folder run this command:
After a bunch of work, you should get your command line back and you can verify that the image was built:
The second container, I built from the first. This allows me extra control and to build other containers from the base without waiting for everything to install again. In a second folder called 'eq', put the following Dockerfile:
Switch into the eq directory and run:
You now have a new container:
There are two ways to run this container. Simply specifying the container name (i.e.
WARNING: Running the container this way will quit the entire container when LaunchPad.exe automatically exits. So just use this to update the container, while using 'eqgame.exe patchme' or 'eqgame.exe patchme /login:username' to run the game for real. I will make an edit if I figure out how to get the game not to quit when running LaunchPad.exe.
Putting together everything we've discussed, place the following in a script called 'runeq.sh':
NOTE: The
If you followed my instructions above, you should have the following files/folder structure:
Now, just make runeq.sh executable (
I'm anxious to hear your results. Please let me know if it's not working for you, it's possible I've forgotten to list a step or something is different on your platform. For me (on Arch Linux) this worked perfectly once I updated to a newer version of Wine. Have fun!
You'll need a few things to get started:
- A Linux machine running a modern kernel and Docker.
- An Nvidia graphics card (sorry no AMD instructions at this time).
- The nvidia-container-toolkit installed.
- A directory on your hard disk with EQ already installed.
Running the Container
We will come back to building the container in a minute, but I wanted to briefly touch on running the container. To get Docker to run games there are a few things we need to focus on that are different from running normal server applications.
- GPU acceleration
- Displaying the GUI on your X server (local machine)
- Sound
- Getting the game to run under Wine
#1 - GPU Acceleration.
This is where the Nvidia card comes in. Nvidia has released docker support for passing the GPU into a container by way of the nvidia-container-toolkit. Once this is installed on your system, all that is needed to pass the GPU into a given container is to use the
--gpus
flag when running the docker container. If you just have one GPU installed, you can just use --gpus all
.#2 - Displaying the GUI.
As anyone familiar with Docker knows, it is easy to map any file into a docker container with the
-v
command-line argument. And since "everything in Unix is a file", we pass through our X11 socket this way. We will use -v /tmp/.X11-unix:/tmp/.X11-unix:ro
to pass through our X server to the container. We also need to pass the DISPLAY environment variable in (see below).#3 - Sound.
If you are running pulse audio, some configuration needs to be done to tell the container to use the host's pulse audio daemon. I'll share a configuration file to do so below.
#4 - Running the game under Wine.
I've already covered this in a previous post and things don't change much for the Docker version once everything is set up. You can refer back to that article for details but we'll take care of everything in the Dockerfile.
Building the Containers
In my setup, I actually chose to build two containers. The first is a container I call
winegame
. This container is an ubuntu container that contains the Nvidia drivers, Wine, and configures pulseaudio to use the host's daemon. I then base a second container off of this one called eq
.Make a folder called winegame and put the following in the winegame folder in a file called Dockerfile:
Dockerfile:
FROM nvidia/opengl:1.2-glvnd-runtime
ENV DEBIAN_FRONTEND=noninteractive
ENV WINEPREFIX=/wine
# A bunch of things we need
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
apt-transport-https \
ca-certificates \
cabextract \
git \
gnupg \
gosu \
gpg-agent \
locales \
p7zip \
pulseaudio \
pulseaudio-utils \
sudo \
tzdata \
unzip \
wget \
&& rm -rf /var/lib/apt/lists/*
# Install a newer Wine than Ubuntu's
ARG WINE_BRANCH="stable"
RUN wget -nv -O- https://dl.winehq.org/wine-builds/winehq.key | APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add - \
&& echo "deb https://dl.winehq.org/wine-builds/ubuntu/ $(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2) main" >> /etc/apt/sources.list \
&& dpkg --add-architecture i386 \
&& apt-get update \
&& DEBIAN_FRONTEND="noninteractive" apt-get install -y --install-recommends winehq-${WINE_BRANCH} \
&& rm -rf /var/lib/apt/lists/*
# Install Winetricks
RUN wget -nv -O /usr/bin/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks \
&& chmod +x /usr/bin/winetricks \
&& mkdir /wine \
&& winetricks corefonts d3dx9 d3dcompiler_43 dxvk
# Configure Locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
COPY pulse-client.conf /etc/pulse/client.conf
A few notes about the above Dockerfile:
- This uses the official Docker image from Nvidia which is based on Ubuntu 20.04 and has the Nvidia drivers already installed.
- We are pulling a much newer version of Wine than the one that comes with Ubuntu 20.04, and installing the latest winetricks.
- We are installing various components through winetricks.
- We are copying in a new configuration file for pulse audio.
pulse-client.conf
in the winegame folder you created earlier.
pulse-client.conf:
# Connect to the host's server using the mounted UNIX socket
default-server = unix:/tmp/pulse-socket
# Prevent a server running in the container
autospawn = no
daemon-binary = /bin/true
# Prevent the use of shared memory
enable-shm = false
Now it's time to build your container. From within the winegame/ folder run this command:
$ docker build . -t winegame:1.0
After a bunch of work, you should get your command line back and you can verify that the image was built:
Shell:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
winegame 1.0 fb8e962e5091 37 minutes ago 3.63GB
nvidia/opengl 1.2-glvnd-runtime e229faf2721a 3 months ago 364MB
nvidia/cuda 10.0-base 97cca2bac989 9 months ago 109MB
The second container, I built from the first. This allows me extra control and to build other containers from the base without waiting for everything to install again. In a second folder called 'eq', put the following Dockerfile:
Dockerfile:
FROM winegame:1.0
WORKDIR /wine/drive_c/eq
CMD ["LaunchPad.exe", "--disable-gpu"]
ENTRYPOINT ["wine"]
Switch into the eq directory and run:
$ docker build . -t eq:1.0
You now have a new container:
Shell:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
eq 1.0 bdaca7fae36c 2 minutes ago 3.63GB
winegame 1.0 fb8e962e5091 37 minutes ago 3.63GB
nvidia/opengl 1.2-glvnd-runtime e229faf2721a 3 months ago 364MB
nvidia/cuda 10.0-base 97cca2bac989 9 months ago 109MB
There are two ways to run this container. Simply specifying the container name (i.e.
$ docker run [...args...] eq
) will run the LaunchPad.exe and allow us to update the EQ install.WARNING: Running the container this way will quit the entire container when LaunchPad.exe automatically exits. So just use this to update the container, while using 'eqgame.exe patchme' or 'eqgame.exe patchme /login:username' to run the game for real. I will make an edit if I figure out how to get the game not to quit when running LaunchPad.exe.
Putting together everything we've discussed, place the following in a script called 'runeq.sh':
runeq.sh:
docker run --rm \
-tid \
--init \
--name eq \
--gpus all \
-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
-v /games/eq/eq:/wine/drive_c/eq \
-v /run/user/$(id -u)/pulse/native:/tmp/pulse-socket \
-w /wine/drive_c/eq \
-e DISPLAY=$DISPLAY \
--device /dev/snd \
--group-add audio \
eq:1.0 eqgame.exe patchme /login:yourusernamehere
NOTE: The
$(id -u)
part means the current user's id will be used to make the path to the pulse audio daemon. This path is for Arch, you will need to find the path to the pulse audio device on your own distribution.If you followed my instructions above, you should have the following files/folder structure:
Shell:
$ tree
.
├── buildeq
│ ├── Dockerfile
├── buildwine
│ ├── Dockerfile
│ └── pulse-client.conf
└── runeq.sh
Now, just make runeq.sh executable (
$ chmod +x runeq.sh
) and run it!I'm anxious to hear your results. Please let me know if it's not working for you, it's possible I've forgotten to list a step or something is different on your platform. For me (on Arch Linux) this worked perfectly once I updated to a newer version of Wine. Have fun!