This tutorial allows you to easily run commands through an LXC container.
When hacking on various applications it is often a requirement to install various dependencies and make other changes to your system to run these programs. I have found this often ends up creating an unstable system, and over time things start breaking. By using an LXC container, all these dependencies can be installed within a sandboxed system without affecting your host environment.
For examples of how this works have a look at the Usage section.
Initial Setup
First install LXC with you preferred package manner.
Then run the following commands, while replacing USER with your username:
sudo usermod --add-subuids 100000-165536 USER
sudo usermod --add-subgids 100000-165536 USER
echo 'USER veth lxcbr0 10' | sudo tee -a /etc/lxc/lxc-usernet
Create ~/.config/lxc/default.conf
(again, changing USER):
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up
lxc.network.hwaddr = 00:16:3e:xx:xx:xx
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536
# GUI
lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir
lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir
lxc.mount.entry = /tmp/.X11-unix tmp/.X11-unix none bind,optional,create=dir
lxc.mount.entry = /dev/video0 dev/video0 none bind,optional,create=file
lxc.hook.pre-start = /home/USER/.local/share/lxc/setup-pulse.sh
Then create ~/.local/share/lxc/setup-pulse.sh
:
#!/bin/sh
PULSE_PATH=$LXC_ROOTFS_PATH/home/ubuntu/.pulse_socket
if [ ! -e "$PULSE_PATH" ] || [ -z "$(lsof -n $PULSE_PATH 2>&1)" ]; then
pactl load-module module-native-protocol-unix auth-anonymous=1 \
socket=$PULSE_PATH
fi
Create A Container
To create the container itself, run:
lxc-create -t download -n mygui -- -d ubuntu -r bionic -a amd64
Replace the lxc.idmap lines in ~/.local/share/lxc/mygui/config
with:
lxc.id_map = u 0 100000 1000
lxc.id_map = g 0 100000 1000
lxc.id_map = u 1000 1000 1
lxc.id_map = g 1000 1000 1
lxc.id_map = u 1001 101001 64535
lxc.id_map = g 1001 101001 64535
lxc.mount.entry = /home/USER/MYPROJECTS home/ubuntu/mnt none bind,create=dir
Changing /home/USER/MYPROJECTS to the path where your projects are stored (or whichever folder you want to be accessible in the container).
Finish setting up the container by running these commands:
sudo chown -R 1000:1000 ~/.local/share/lxc/mygui/rootfs/home/ubuntu
echo 'export PULSE_SERVER=/home/ubuntu/.pulse_socket' >> ~/.local/share/lxc/mygui/rootfs/home/ubuntu/.profile
lxc-start -n mygui -d
lxc-attach -n mygui -- apt install pulseaudio -y
echo "enable-shm = no" | lxc-attach -n mygui -- tee -a /etc/pulse/client.conf
lxc-attach -n mygui -- su - ubuntu -c 'pulseaudio -k'
lxc-stop -n mygui
Create Shortcut
Now we create our shortcut command.
Download the shortcut script.
Replace /home/USERNAME/MYPROJECTS at the top of the file with the same path you used earlier.
Save it to /usr/local/bin/lr
.
Finally, make it executable and create a symlink:
sudo chmod +x /usr/local/bin/lr
sudo ln -s /usr/local/bin/lr /usr/local/bin/lrs
Usage
Now you have an LXC container to use, you can easily run programs you are working on with the shortcuts. The lr command can be used to run anything as a normal user within the LXC container, and when used within your shared folder will be run from the same location. To test this, try running:
cd ~/MYPROJECTS
ls
lr ls
The last command will run the ls command inside your LXC container, but both ls commands should produce the same output, as the lr will make sure the commands are run from the same location in the shared folder.
Additionally, we have the lrs command which can be thought of as lr sudo
and will run any command as root. Try installing and running Firefox in your container:
lrs apt install firefox
lr firefox
As an example for using this as a development tool, if you wanted to run a Java app without installing Java on your host machine, you could do so like this:
First, install the dependencies:
lrs apt install openjdk-11-jre
Then run the code from our projects folder:
cd ~/MYPROJECTS
lr java -jar myjavaprogram.jar
Resetting
If you’ve messed up your LXC container and want to wipe it. Just run:
lxc-destroy -n mygui
Then repeat the create a container section.
[2018-06-07] – Pass $DISPLAY variable, rather than using hardcoded value.