Install ROS using LXD Container
In this guide I will show you how to setup a LXD Container for ROS

When you want to start using ROS (Robot Operating System) it might be a good practice to install it in an closed environment to prevent conflicts with other packages and add more flexibility to the complex dependency structure. There are multiple ways on how to approach this idea. For example you could create a VM running Ubuntu and use it exclusively for ROS development or you can create a Docker Container for the ROS system. When I was looking for possible solutions I came accross a video from the user celebrateubuntu who showed how to install ROS using LXD. LXD containers are a super convenient way to set up containerized linux machines. In the following lines I want to describe the process on how to install ROS using a LXD container.

Install and configure LXD

I am using an Ubuntu based machine. If you are using a different OS you might need to refer to the LXD docs. First step is to install LXD using snap.

snap install lxd

Next you need to configure the installation. Make sure to run this as root.

sudo lxd init

To interact with LXD you need to have root privileges or be part of the lxd group. You can add yourself to the lxd group for the current terminal session using the command newgrp lxd.

Prepare for launch

Now that we have all the tools we need, we can start with the setup. In theory you can start an instance right now using the following command. (Yes, now its called lxc instead of lxd)

lxc launch ubuntu:20.04 my_instance

However we need some more configuration to get all the features we want. Creating a profile will help us when we want to setup multiple instances with different ROS versions. A profile acts like blueprint for the instance where we can define some useful setting. Create a profile called ros and edit it using the following command.

lxc profile create ros
lxc profile edit ros

Let’s have a look at the lines we will add to the profile. Under config you will need to add the following parameters. Please don’t just copy paste those settings because you might need to adjust them for your machine.

config:
  environment.DISPLAY: :1   ### Defines a variable for the X Windows display
  raw.idmap: both 1000 1000 ### Maps your host id to the container host id.
                            ### If your id differs, you need to change the first number to your id.
  user.user-data: |         ### Define commands that are run on initiation of the container. 
                            ### We add the ros1 and ros 2 repositorys to the system.
    #cloud-config
    runcmd:
      - apt-key adv --fetch-keys https://raw.githubusercontent.com/ros/rosdistro/master/ros.key
      - apt-add-repository http://packages.ros.org/ros2/ubuntu
      - apt-add-repository http://packages.ros.org/ros/ubuntu

Let’s move on to the devices section. Here we can add components to pass through to the container. In our case we will add the display, network and filestorage component.

The X1 device is used for X-Windows. Check if the directory existst on your machine if it has an other name (for example X0) then you need to use X0 instead of X1. In this case you also have to change environment.DISPLAY under config to the corresponding number.

  X1:
    path: /tmp/.X11-unix/X1
    source: /tmp/.X11-unix/X1
    type: disk

The eth0 device will bridge your network to the container. Use a command like ifconfig to find your network adapter name and add it under the parent node.

  eth0:
    name: eth0
    nictype: macvlan
    parent: wlxb06ebfa49658
    type: nic

Last but not least we will connect to our file storage. Just use the default storage pool.

  root:
    path: /
    pool: default
    type: disk

Now your profile should look similar to this.

### This is a YAML representation of the profile.
### Any line starting with a '# will be ignored.
###
### A profile consists of a set of configuration items followed by a set of
### devices.
###
### An example would look like:
### name: onenic
### config:
###   raw.lxc: lxc.aa_profile=unconfined
### devices:
###   eth0:
###     nictype: bridged
###     parent: lxdbr0
###     type: nic
###
### Note that the name is shown but cannot be changed

config:
  environment.DISPLAY: :1
  raw.idmap: both 1000 1000
  user.user-data: |
    #cloud-config
    runcmd:
      - ¨apt-key adv --fetch-keys https://raw.githubusercontent.com/ros/rosdistro/master/ros.key¨
      - ¨apt-add-repository http://packages.ros.org/ros2/ubuntu¨
      - ¨apt-add-repository http://packages.ros.org/ros/ubuntu¨
description: ROS
devices:
  X1:
    path: /tmp/.X11-unix/X1
    source: /tmp/.X11-unix/X1
    type: disk
  eth0:
    name: eth0
    nictype: macvlan
    parent: wlxb06ebfa49658
    type: nic
  gpu:
    type: gpu
  root:
    path: /
    pool: default
    type: disk
name: ros
used_by:
- /1.0/instances/rosfoxy

Start the engines

Now that we succesfully added a profile for our container we just need to create it using the following command.

#lxc launch -p [profile_name] ubuntu:20.04 [container_name]
lxc launch -p ros ubuntu:20.04 rosfoxy

The container is now created and we can access it with the following command.

lxc exec rosfoxy -- su --login ubuntu

If there are no errors we can go ahead and install ROS.

sudo apt install ros-foxy-desktop

Enjoy the ride

Congratulation. You can now use the container like your usual linux environment without complications when experimenting with different versions. Just create a new container and you are good to go.

*****