Running Steam in a LXD system container

Update February 2021: This tutorial shows how to install manually the shared libraries for OpenGL in the container. The user needs to make sure that the library versions in the container matches those of the host. That was not very good. Now, LXD supports the NVidia container runtime, which is provided by NVidia and has the matching shared library versions from the host. Please, follow instead the new post on How to Run X11 Applications in a LXD container.

You can run Steam directly on your desktop, but it tends to install all sorts of 32-bit packages. How can you restrict Steam and any games into a container so that it does not mess the rest of your desktop? A virtual machine would be overkill. In this post, we see how to do this with a LXD system container. We create a LXD system container with Ubuntu 18.04, configure it to run GUI applications that will appear on our desktop with full graphics acceleration and sound, and install Steam.

Prerequisites

  • You need to have LXD installed and configured on your desktop computer.
  • You need to have a desktop with X11 (or Wayland with XWayland).
  • If you have an NVidia graphics card and you are using the closed-source driver, note down the driver package. For example, nvidia-driver-390. You need to install that driver additionally into the system container.
  • If you have an NVidia graphics card along with an integrated graphics card, then your NVidia graphics card is your second graphics card. You need to take note of that later in this guide.

Adding the steam LXD profile

When you create system containers with LXD, you specify one or more profiles to be applied to the newly created container. In our case, we create a LXD profile specifically for Steam LXD system containers. First, we download the profile from the LXD Steam profile gist. Then, we create an empty LXD profile and populate it with the contents of the gist. The profile has been tested Ubuntu 18.04 (either deb or snap packages of LXD).

wget https://gist.githubusercontent.com/simos/6e84dcb2aa554b8e2954b26d10e40f69/raw/dac99a48a7941281f45c389cd7dd998d9ccf6098/steam.lxdprofile

lxc profile create steam

cat steam.lxdprofile | lxc profile edit steam

lxc profile show steam

Let’s see the contents of the profile to figure out where to make changes, if needed. Here are the notable places that you may need to change, if you adapt for another system. With this profile, we set in the container

  1. The DISPLAY to :0.
  2. The IDMap to the UID and GID of our desktop user account on the host. For Ubuntu, the default non-root account has UID/GID of 1000/1000 respectively.
  3. We use cloud-init to add the i386 architecture and install a set of require packages for X11 and sound.
  4. We configure PulseAudio to connect to the PulseAudio server of the host. There is an additional device directive later in the profile for the PulseAudio socket.
  5. We download and install the Steam deb package.
  6. We make available the Unix sockets for both X11 and PulseAudio to the container. If your active GPU is NOT the second GPU on your system, then change /tmp/.X11-unix/X1 into /tmp/.X11-unix/X0 As it is, this profile is for a system with an intergrated GPU and an NVidia GPU, and the latter is in use.
  7. We enable the GPU sharing between the host and the container.
config:
  environment.DISPLAY: :0
  raw.idmap: both 1000 1000
  user.user-data: |
    #cloud-config
    runcmd:
      - 'dpkg --add-architecture i386'
      - 'apt-get update'
      - 'apt-get install -y x11-apps:i386'
      - 'apt-get install -y mesa-utils:i386'
      - 'apt-get install -y libgl1-mesa-glx:i386'
      - 'apt-get install -y libcanberra-gtk-module:i386'
      - 'apt-get install -y pulse-audio'
      - 'apt-get install -y dbus-x11'
      - 'sed -i "s/; enable-shm = yes/enable-shm = no/g" /etc/pulse/client.conf'
      - 'echo export PULSE_SERVER=unix:/tmp/.pulse-native | tee --append /home/ubuntu/.profile'
      - 'wget https://steamcdn-a.akamaihd.net/client/installer/steam.deb'
      - 'dpkg -i /steam.deb'
      - 'apt-get install -y -f'
description: Steam LXD profile
devices:
  PASocket:
    path: /tmp/.pulse-native
    source: /run/user/1000/pulse/native
    type: disk
  X0:
    path: /tmp/.X11-unix/X0
    source: /tmp/.X11-unix/X1
    type: disk
  mygpu:
    type: gpu
name: steam
used_by:

Up to this point, we created the steam LXD profile. In the next section, we launch the container and get playing.

Launching the LXD system container for Steam

We launch the container with the following command. The container is ubuntu:18.04, which means it runs Ubuntu 18.04. We apply first the default profile, which means that the container will use the configuration of your local LXD installation (i.e. storage, networking). Then, we apply the steam profile, which is the one we added just earlier.

lxc launch ubuntu:18.04 steam --profile default --profile steam

Let’s the the container running.

$ lxc list steam
+-------+---------+---------------------+------------+
| NAME | STATE | IPV4 | TYPE |
+-------+---------+---------------------+------------+
| steam | RUNNING | 10.10.10.210 (eth0) | PERSISTENT |
+-------+---------+---------------------+------------+

We now get a shell into the steam LXD system container. Since your LXD installation is probably pristine, we create first a nice LXD alias and then use it to get a shell into the container.

lxc alias add ubuntu 'exec @ARGS@ --mode interactive -- /bin/sh -xac $@ubuntu - exec /bin/login -p -f '

Now, we can get a shell with lxc ubuntu steam. “lxc” is the command, “ubuntu” is the alias that gives us a non-root shell into the Ubuntu container (default non-root account is also called “ubuntu”), and finally “steam” is the name of the container.

$ lxc ubuntu steam
exec /bin/login -p -f ubuntu
Last login: Thu Apr 4 15:44:07 UTC 2019 on UNKNOWN

Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-47-generic x86_64)
Documentation: https://help.ubuntu.com
Management: https://landscape.canonical.com
Support: https://ubuntu.com/advantage
System information as of Thu Apr 4 15:44:07 UTC 2019
System load: 0.49 Processes: 21
Usage of /home: unknown Users logged in: 0
Memory usage: 1% IP address for eth0: 10.10.10.210
Swap usage: 0%
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
7 packages can be updated.
6 updates are security updates.
Your Hardware Enablement Stack (HWE) is supported until April 2023.
ubuntu@steam:~$

Great! We got a shell into the container. Before continuing, let’s verify first that the cloud-init instructions have completed in the container. For example, if you are too fast, the container may still be installing Steam! We check by running the following. It says finished, all good!

ubuntu@steam:~$ tail -1 /var/log/cloud-init-output.log
Cloud-init v. 18.5-45-g3554ffe8-0ubuntu1~18.04.1 finished at Thu, 04 Apr 2019 15:43:59 +0000. Datasource DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud-net][dsmode=net].  Up 205.00 seconds
ubuntu@steam:~$ 

The container is ready. In the following section we install the NVidia closed-source driver, if required. If you do not need it, skip to the section on Running Steam.

Installing the NVidia closed-source driver (if required)

If you have an NVidia graphics card, you need to install the driver in the container as well. Note that the LXD system containers do not and cannot add Linux kernel drivers. But by installing the driver, we manage to install the user-space libraries that are required for software to work in the container.

In this example, we install the nvidia-driver-390 package in the container. Please make sure that you install the exact same version as on the host.

ubuntu@steam:~$ sudo apt install nvidia-driver-390
The driver package is nvidia-driver-390. Image source: ItsFoss.

We have installed the necessary additional driver in the container. We can now run Steam.

Running Steam

Let’s run Steam. We run it from the shell. Below, there are some actual screenshots from this installation of Steam.

ubuntu@steam:~$ steam
Running Steam on ubuntu 18.04 64-bit
STEAM_RUNTIME is enabled automatically
Pins up-to-date!
Installing breakpad exception handler for appid(steam)/version(1550534751)
...

In terms of functionality, any game should be able to run from within the container. Note that we have not installed a web browser or a file browser, or even an image viewer in the container. You may want to do so. For example, if you take screenshots, you would need a file browser program to view them in the container.

Creating a shortcut to Steam

As it stands now, we would need to open a shell into the steam container and then run steam. If you would rather create a shortcut, perform the following on the host (your desktop, not the container).

First, grab an icon for Steam and place it into a sensible directory. In our case, we place it into ~/.local/share/icons/.

lxc file pull steam/home/ubuntu/.local/share/Steam/tenfoot/resource/images/steam_home.png ~/.local/share/icons/

Then, paste the following in a text editor and save it as steam.desktop.

[Desktop Entry]
Name=Steam
Comment=Play gameis on Steam
Exec=lxc exec steam -- sudo --user ubuntu --login steam
Icon=/home/user/.local/share/icons/steam_home.png
Terminal=false
Type=Application
Categories=Game;

Finally, move steam.desktop into the ~/.local/share/applications directory.

mv steam.desktop ~/.local/share/applications/

We can then search for the Steam application and place it on the launcher.

Conclusion

We have seen how we can install Steam in a LXD system container. It is handy to separate gaming from our desktop. If you found any gotchas that need addressing, please post a comment.

Troubleshooting

Do X11 applications work?

Run the following. You should get as output the clock application.

ubuntu@steam:~$ xclock 
The xclock X11 application running from within the steam container.

Does graphics acceleration work?

Run the following in the container. If you get a similar output, then it works.

ubuntu@steam:~$ glxinfo 
name of display: :0
display: :0 screen: 0
direct rendering: Yes
server glx vendor string: NVIDIA Corporation
server glx version string: 1.4
server glx extensions
...

Do accelerated OpenGL applications work?

Run the following in the container. If you get a similar output, then it works.

ubuntu@steam:~$ glxgears 
The glxgears OpenGL application running in a LXD system container.

I rebooted my desktop and now it does not work!

When you reboot the desktop, the steam container may not autostart. You need to start it yourself by running the following. This has to do with the Unix socket for X11 and PulseAudio; when the container is being started, it is likely that you have not logged in into the desktop (especially if you set it to ask you for a password). There are ways to get around this, but that’s for another tutorial.

lxc start steam

Permanent link to this article: https://blog.simos.info/running-steam-in-a-lxd-system-container/

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.