Easy containers on Ubuntu Touch with qemu-debootstrap

There are few ways to use containers on Ubuntu Touch, but my favorite one is using qemu-debootstrap. This is a layer atop debootstrap, which is easier to use. But it does require a package that is not present on the Ubuntu Touch by default, and approx 80MB of additional disk space. This is only if you are going to build containers, and you do not need it to just use the containers once they are already created and distributed. So without a further do, I will cover these topics:
  1. Installing qemu-debootstrap
  2. Creating containers
  3. Using containers
  4. Configuring X forwarding for containers (for using GUI apps from container)
DESCLAIMER: using qmu-debootstrap in conjunction with qemu-system-arm has one amazing advantage: you can actually fully create the container on your Ubuntu Desktop x86_64 because the qemu-system-arm will emulate ARM architecture. In this article Iam showing you steps for doing everything on your Ubuntu Touch device, but I want you to know that you don't have to. Sometimes building this on your desktop can be even faster.
Installing qemu-debootstrap

Connect to your Ubuntu Touch device either with adb shell or ssh, and run:
#make the filesystem writable:
sudo mount -o remount,rw /
sudo apt-get update
sudo apt-get -q -y install mc xauth qemu-user-static qemu-system-arm
#turn the filesystem read-only again:
sudo mount -o remount,ro /
now notice that gemu-user-static and qemu-system-arm are the packages that will provide us with qemu-debootstrap, but we are also installing mc package to have most user friendly terminal mode file manager and text editor at hand, as well as xauth, which we will use in the last step to make X forwarding over SSH possible.
Be advised that qemu-system-arm is basically only needed on non-arm host. Ubuntu Touch or any other arm linux does not require this. On the other hand it will allow you to run arm chroot even on a non-arm machine, ie. on your Ubuntu Desktop x86_64. That will allow you to have a native ARM environment on your dekstop for natively building apps.


Creating containers

For the purpose of this tutorial we will create a container with Ubuntu 14.04 Trusty ARM, into a trusty-arm.img file under ~/Containers, so:
#Prepare working folder:
mkdir ~/Containers
cd ~/Containers
#create img file, here i am just making a small 4G, but it's up to you
dd if=/dev/zero of=trusty-arm.img bs=1M count=4096
#this will take a while ;), and when done time to make a filesystem:
mkfs ext4 -F trusty-arm.img
The image is now created and it has a valid filesystem on it. The next step is to mount this image, and create the chroot environment inside using qemu-debootstrap. We will mount the image into a folder with the same name as the image file (PLEASE read the comments within!):
#mounting:
mkdir trusty-arm
sudo mount -o loop,rw,sync trusty-arm.img ./trusty-arm
#just in case permissions prevent you from doing anything inside the image:
sudo chmod -R ug+rw ./trusty-arm
#actually build the chroot into the mounted image (will take a good while):
sudo qemu-debootstrap --arch=armhf trusty ./trusty-arm
#just a touchup if you are making this on non-arm machine (not needed on Ubuntu Touch):
sudo cp `which qemu-arm-static` ./trusty-arm/usr/bin/

This way we already have a working chroot inside the mounted image, but before we use or share this image to others, we can first do a bit of initial configuration, so later we just have this out of our way. TO do it, we will now chroot into this new container:
sudo chroot ~/Containers/trusty-arm
And when finally inside, we will carry out some initial pre-configuration:
#TTY configuration:
sed 's/tty1/ttyAMA0/g' /etc/init/tty1.conf > /etc/init/ttyAMA0.conf
#Enabling Universe repo:
echo "deb  http://ports.ubuntu.com trusty main restricted multiverse universe" > /etc/apt/sources.list
apt-get update
#basic network configuration:
echo -e "\nauto eth0\niface eth0 inet dhcp" >> /etc/network/interfaces
#building some locale, so later apps don't shout about it:
locale-gen "en_US.UTF-8"
sudo dpkg-reconfigure locales
apt-get install --reinstall language-pack-en
#installing gedit will also install some X11 dependencies, so although
#heavy (200+ MB), it is very useful, because later when you install GUI apps,
#they will share a lot of underlaying libraries:
apt-get install -q -y gedit
#You can at this point isnatll whatever else you want to ship your container with:
apt-get install -q -y ssh mc xauth nautilus gnome-system-monitor
At this point your container is ready. It has some basic config included, as well as whatever packages you installed, so when anyone uses it, the stuff will be there already.

Using Containers

Using these containers comes down to few basic actions:
  • Obtaining the image file
  • Mounting the image file under a dedicated directory
  • entering chroot
  • working inside the chroot
  • leaving the chroot
  • unmounting the image
As for obtaining the image, I will not be covering this here. It is really all up to your own liking. You can copy it with a usb pendrive, you can host it on a server for downloading, or really, whatever you fancy. Le'ts just asume that you already have the image file, and move from here.
For my tutorial I am using a uniform naming, so all that is happening goes inside ~/Containers directory. On Ubuntu Touch devices, the filesystem is read-only excep/click.ubuntu.t for user's home directory, and few other places belonging to userspace (like /opt/click.ubuntu.com/).
Also, as my general rule, I mount chroot images under folders that are also placed under ~/Containers and have the same name as the image file. So let's go:
#go into the directory that has our image:
cd ~/Containers
#mount the image:
mkdir -p ~/Docuemnts/trusty-arm
sudo mount -o loop,rw,sync trusty-arm.img trusty-arm
#get into the chroot:
sudo chroot trusty-arm
At this point you are inside the chroot container, and your prompt have changed:
And when you are done using the container:
#leave from the chroot:
exit
#unmount the image:
sudo umount trusty-arm
#if you so wish, remove the directory, but I do not do this:
rm -R trusty-arm
And so:
And that's how you do it. One thing that I remember is that I couldn't when inside chroot, find out the image free space using df -h command. I have to go outside the container, and call the command filtering output with the name of the chroot folder, and it only works when the folder is currently mounted:
Also worth noticing is that your chroot is isolated from your actual filesystem, and while within, you cannot access files from your host filesystem. Unless you mount some local files into the container. Let's say I'd like to be able to access my local Pictures folder within the chroot, no problem, just follow thess steps when the image is mounted:
#do these steps after the image is already mounted:
sudo mkdir -p ~/Containers/trusty-arm/home/phablet/Pictures-from-host
sudo mount --bind /home/phablet/Pictures /home/phablet/Containers/trusty-arm/home/phablet/Pictures-from-host
sudo chroot ~/Containers/trusty-arm
ls ~/Pictures-from-host



Configuring X forwarding for containers


This is the most cool and useful part of this tutorial. X Forwarding is what will allow you to install GUI apps in a chroot container on your Ubuntu phone/tablet, and then run it on the screen of your Linux desktop or laptop. 

PLEASE also see my other post for more detail on the ssh+chroot scenario, especially regarding so called magic cookies: SSH and Ubuntu Touch - everything you want to ask but are afraid to ask

In order for this to work, you will first have to enable X forwarding for the phone itself, and then forward this configuration into the chroot.
Now, this is actually super interesting, because the Ubuntu Touch devices run Unity desktop on Mir display server, and they lack the X11 display server. So how are you suppose to enable X forwarding on the phone itself first, if there is no X on the phone?? This is the interesting part!
Turns out, that all you need for X Forwarding over SSH is to have a valid .Xauthority file in the home directory on your device. SSH will need only this file to initiate X Forwarding. Once you have this file on your phone, you just need to copy it into the home directory of your chroot container.
So what if you don't have this file? How to make it? You can either do that on the phone itself, or do it on your Linux desktop and then upload to your phone. I will show you how to do it on the phone. Do you remember earlier in a part of the script I was installing package xauth ? This will create the .Xauthority, so if case you didn't install the package already, just do it like this:

#only if do this if you didn't already install xauth earlier:
sudo mount -o remount,rw /
sudo apt-get install xauth
sudo mount -o remount,rw /
Now let's generate new .Xauthority, just copy paste these commands:
#remember, this is to be done in the phone directly, not in the chroot!
#and only if you don't already have the file ~/.Xauthority
key=`perl -e 'srand; printf int(rand(100000000000000000))'`
key=$key$key
touch ~/.Xauthority
xauth add ${HOST}:0 . $key  

#then copy it into the chroot:
sudo cp ~/.Xauthority ~/Containers/trusty-arm/home/phablet/
So yes, it requires installing xauth, but this package is really tiny in size, so it shouldn't be a big deal. If you do however mind, you could always backup your .Xauthority on your desktop, generate a new one using the exact same method, upload it to the phone, then restore the previously backed-up original file on the desktop.

Now, we want the very same .Xauthority file inside chroot, but since it can be considered a security risk to just leave it there, you could copy it before chrooting, and then deleting it when you exit your chroot, it's up to you. Also there are few preparations before you can fully enjoy the X Fowarding, and you could script them so that you can always initialize the chroot before getting in, and also undo any initialization after you are done working with it:
#mount image unless already mounted:
cd ~/Containers
sudo mount -o loop,rw,sync trusty-arm.img ./trusty-arm

#INITIALIZASTION before goint into chroot (optional):
sudo mount --bind /dev /home/phablet/Containers/trusty-arm/dev
sudo mount --bind /proc /home/phablet/Containers/trusty-arm/proc
sudo mount --bind /sys /home/phablet/Containers/trusty-arm/sys
sudo cp /etc/resolv.conf /home/phablet/Containers/trusty-arm/etc/

#Copying the XAUTHORITY:
sudo cp ~/.Xauthority ~/Containers/trusty-arm/home/phablet/

#entering chroot:
sudo chroot ~/Containers/trusty-arm

#(...)

#leaving the root
exit

#removing XAUTHORITY (Optional):
sudo rm ~/Containers/trusty-arm/home/phablet/.Xauthority

#FINALIZATION (optional):
sudo umount /home/phablet/Containers/trusty-arm/sys
sudo umount /home/phablet/Containers/trusty-arm/proc
sudo umount /home/phablet/Containers/trusty-arm/dev

#unmount the image:
sudo umount /home/phablet/Containers/trusty-arm
Now that we are done with the tutorial, time for some facts checking:
  • Ubuntu Touch phones and tablets do have x11 stack installed, but it xorg server is not running. Xmir is providing emulated x server for apps that need it
  • Ubuntu Touch uses Mir as desktop environment but you can use other desktp environments on it as well, including XFCE, LXDE, Mate, etc. If that interests you, see dedicated post on this that will come soon (link will be added here) 
  • The rootfs space is limited so you are always welcome to use containers as a way out of this problem. On some devices you will be able to grow rootfs space easily though, which will be covered separately (and linked here).
  • if you put x11 app (for example Gtk) on your phone, you can then run it via X Forwarding onto your Linux desktop/laptop
  • you can also run it on the phone itself on the phone's screen using XMir which emulates x11 server for backward compatibility
  • The ultimate problem is that awfully some Linux legacy apps depend on external libraries and parts of x11 stack that is not present in Ubuntu TOuch by default and to manually solve these dependency issues on your Ubuntu Touch device, could be a real pain in the ass hectic task, unless you have enough space on your rootfs and can install dependencies in it with apt-get.
  • Container solves the problem above, you can install all the dependencies easily, and the filesystem space is not limited by the size of rootfs on the host, as you can save your container in the userspace or (if your device allows it) on an external SD card.
All in all, it is always a great thing to carry your legacy apps in your phone, and when having access to your Desktop/laptop launch them on its screen, like this:

Comments

  1. Hi Kris, thanks for this tutorial. Ssh forwarding works great when I use my ubuntu and mint laptop. Now I try to login with putty from windows 10, but no success. Tablet keeps responding Diconnected: no supported authetication methods available (server sent: publickey.) Ssh to other linux hosts from windows10 no problem. Did you ever succesfully connected from a windows 10 pc to the tablet? Any suggestions?

    ReplyDelete
    Replies
    1. Hi JD, sorry if I am asking for an obvious, but did you add your windows (where you use PuTTY) key to the phone's trusted list?
      The reason you can connect to other Linux servers is because probably these other servers either don't require key authentication (ie, they allow for password authentication instead) or you already imported the key. UT device however does not allow for password authentication via ssh, only key. So you need to have a key on the machine where you use PuTTY from, and then you need to register the key on your phone.
      Cheers.

      Delete
  2. Hi Chris, thanks for your reply. I found the reason. The key file was generated with Putty on the Windows pc and stored in Windows format. It had some hard returns in it. Now it works. Cheers.

    ReplyDelete

Post a Comment

Popular posts from this blog

Lazarus IDE on ARM Ubuntu (Raspberry Pi, Ubuntu Touch, etc)

Console vs GUI application in Object Pascal - is it either-or?

SSH and Ubuntu Touch - everything you want to ask but are afraid to ask