Introduction
Because the development environment for MAAS versions 2.0 through 2.3 was targeted for Ubuntu 16.04 “Xenial”, bugs can and will occur if you try to develop code for MAAS 2.3 on more recent releases of Ubuntu. But developing against older versions of Ubuntu doesn’t have to be cumbersome; LXD offers a great way to create a lightweight, full-featured development environment.
In this post, I’ll show how to launch a Xenial-based container that is capable of running a full-fledged IDE for development purposes. Of course, if you’re just using a generic text editor, you may not need to do this. But I like to use pycharm
, so I want my IDE to be able to access all aspects of the development environment, including Python files installed onto system paths. These won’t line up properly if I use the IDE outside of the container.
Scripting the creation of your container
Below you can find the script I use to create a Xenial-based development environment that is able to communicate with the X server running on my host (Bionic) system. (It also installs the pycharm-community
snap; you can install pycharm-professional
instead if you have a license.) It also imports your SSH keys from launchpad (modify the LAUNCHPAD_USER variable to customize this), and maps your $HOME
into the container so that your work environment transitions seamlessly into the container.
#!/bin/bash
CONTAINER=xenial-dev
LAUNCHPAD_USER=$USER
lxc init ubuntu:xenial $CONTAINER -s default --no-profiles
lxc network attach virbr0 $CONTAINER eth0 eth0
# An idmap is required in order to allow for a read/write container $HOME,
# and to run X11 apps that will display on the host.
lxc config set $CONTAINER raw.idmap "both $UID 1000"
# Remap home directory.
lxc config device add $CONTAINER home disk source=$HOME path=/home/$USER
# Allow use of DISPLAY=:1 (gdb typically runs on :0; adjust as needed)
lxc config device add $CONTAINER X1 disk path=/tmp/.X11-unix/X1 source=/tmp/.X11-unix/X1
# Allow GPU passthrough for X applications
lxc config device add $CONTAINER gpu gpu
lxc config device set $CONTAINER gpu uid 1000
lxc config device set $CONTAINER gpu gid 1000
lxc config set $CONTAINER user.user-data "#cloud-config
users:
- name: $USER
shell: /bin/bash
ssh_import_id: $LAUNCHPAD_USER
sudo: ALL=(ALL) NOPASSWD:ALL
package_upgrade: true
packages:
- jq
- build-essential
- silversearcher-ag
- x11-apps
- default-jre
- fonts-dejavu-core
- fonts-freefont-ttf
- ttf-ubuntu-font-family
snap:
commands:
00: ['install', 'pycharm-community', '--classic']
locale: en_US.UTF-8
timezone: $(timedatectl | grep 'Time zone:' | awk '{print $3}')
runcmd:
- [touch, /tmp/startup-complete]
"
lxc config set $CONTAINER user.network-config "version: 2
ethernets:
eth0:
match:
name: eth0
dhcp4: true
"
lxc config device add $CONTAINER kvm unix-char path=/dev/kvm
lxc start $CONTAINER
lxc exec $CONTAINER -- /bin/bash -c 'while ! [ -f /tmp/startup-complete ]; do sleep 0.5; done'
Note here that I attached eth0
in the container to the virbr0
bridge, which I recommended using by default with LXD in a previous post.
When creating this container, it was very useful to use a cloud-init
configuration to install the packages I’ll need for development.
The custom network-config
isn’t really needed here, but I included it in case I wanted to expand on it later, such as by passing through more networks to use for testing.
Additional considerations
If you’re using a local Ubuntu mirror, you might find it useful to include the following in the cloud-config, as a workaround for bug #1791185:
bootcmd:
- [ 'sh', '-c', 'rm -rf /var/lib/apt/lists/*' ]
apt:
primary:
- arches: [default]
uri: http://<your-local-ubuntu-mirror>/ubuntu/
Finally, I added the following hack to my .profile
, which makes it so I don’t have to export DISPLAY=:1
every time I log into the container:
if [ "$DISPLAY" = "" ]; then
X11_SOCK=/tmp/.X11-unix/X1
if [ -e $X11_SOCk ]; then
owner=$(ls -l $X11_SOCK | awk '{ print $3 }')
if [ "$owner" = "$USER" ]; then
export DISPLAY=:1
fi
fi
fi
References
Thanks to the following posts, which I referenced while creating this script:
- A nicer way to mount your /home in LXD (Chris Glass)
- How to run graphics-accelerated GUI apps in LXD containers on your Ubuntu desktop (Simos Xenitellis)