I am Radostin, a student involved with Libvirt in the Ease creation of containers Google Summer of Code (GSoC) Project. The idea of this project was to provide a simple way to setup root file system for the Libvirt LXC driver. Here I present the complete work I did during the GSoC term and also explanations for the same.
This summer I mostly worked on 2 things:
Adding new features to virt-bootstrap
Integration of virt-bootstrap with virt-manager for smooth user experience.
What has been done?
At the beginning of the project I shared my idea for extending the user interface of virt-manager on the virt-tools mailing list. The received feedback gave me ideas for adjustments to work towards but mainly this was to show the progress of virt-bootstrap in virt-manager.
Before the integration with virt-manager some improvements for virt-bootstrap were required to ensure that the installation process is simple and the progress information is tracked in accessible for virt-manager way.
In addition to that, conversion of Docker image layers to qemu copy-on-write images using backing chains was enabled.
The integration of virt-bootstrap with virt-manager was achieved by extending the UI and importing the virtBootstrap python module. Creation of the root file system tree is done using the bootstrap() method which is called asynchronously in a thread. [Demo video]
Another feature added to virt-bootstrap was the UID/GID mapping which can be used to create Libvirt LXC container with enabled user namespace. In such container the owner/group of files must be mapped to UID/GID of users inside the container.
What code was merged?
How to use virt-bootstrap?
The command line tool virt-bootstrap provides an easy way to setup root file system from various sources such as a tar archive containing the file system, container image from Docker registry or VM disk image created with virt-builder.
Extract root file system from a tar archive.
$ virt-bootstrap /home/user/rootfs.tar /var/lib/Libvirt/filesystems/container1
This will extract securely the root file system from rootfs.tar to /var/lib/Libvirt/filesystems/container1 using LXC container if the user is with effective UID 0 or kvm instance (qemu:///session) otherwise.
Optionally to apply adjustments can be the flags:
--fmt Specify the output format. Possible values are “dir” and “qcow2”
--idmap Apply map for owner and group of entries
--uidmap Apply map for owner of entries
--gidmap Apply map for group of entries
--root-password Set password for root
Extract root file system from Docker image
Container images might have multiple layers where each layer store only the changes made. To extract root file system from them we have to extract the layers in order starting from base layer. This is what you can do with virt-bootstrap in the following example:
$ virt-bootstrap docker://ubuntu /var/lib/Libvirt/filesystems/ct1
The root file system extracted in /var/lib/Libvirt/filesystems/ct1 can be used by Libvirt to start LXC container.
Alternatively the layers of container image can be preserved using qcow2 image with backing chains:
$ virt-bootstrap docker://ubuntu /var/lib/Libvirt/filesystems/ct1 \
This example will create qcow2 image with single partition and ext3 file system which contains the base layer of the latest Ubuntu container image available on docker.io. Then it will create qcow2 image with backing file for each layer of the container image and store only the changes applied within this layer. This is implemented using libguestfs and does not require root privileges.
Optionally the flags for UID/GID mapping or root password can be used as well.
Extract root file system from VM image build with virt-builder
The tool virt-builder can be used to build disk image for virtual machine from template. To create container from such VM image we have to extract the root file system. The example below demonstrates how this can be achieved with virt-bootstrap:
$ virt-bootstrap virt-builder://fedora-25 /var/lib/Libvirt/filesystems/ct1
This command will build VM image from fedora-25 in temporary file and extract the root file system to /var/lib/Libvirt/filesystems/ct1 which can be used with Libvirt to create LXC container. Optionally the flags for UID/GID mapping or setting root password can be used as well.
Apply UID/GID mapping
The flags --idmap, --uidmap and --gidmap can be used to map the owner and group of members in the created root file system. Each of these flags can be used multiple times and take input with format: <start>:<target>:<count>
Where <start> is the UID/GID on the host, <target> is the UID/GID inside the container and <count> is the number of UID/GIDs to be mapped (range).
$ virt-bootstrap docker://fedora /var/lib/Libvirt/filesystems/ct1 \
--idmap 0:1000:10 \
This will apply the UID/GID map:
0, 1, 2 … 9 to 1000, 1001, … 1009
500, 501 … 509 to 1500, 1501 … 1509
Limitations and known bugs
You do not necessarily need to be root to use virt-bootstrap, however there are some limitations for unprivileged users when used with output format “dir”. In such case all members of the extracted root file system will be owned by the same unprivileged and UID/GID mapping cannot be applied.
When the output format is qcow2 all functionalities are available for unprivileged users, however at the time of writing this post Libvirt has a bug which does not allow to start LXC container from qcow2 image with enabled user namespace . This bug has been reported here https://bugzilla.redhat.com/show_bug.cgi?id=1328946 and the work around is to mount the qcow2 image and start LXC container from the mounted directory with enabled user namespaces.
I would like to thanks all members of Libvirt and virt-tools communities and particularly Cédric Bosdonnat, Cole Robinson and Pavel Hrdina for all commit reviews and suggestions.
I would also like to thanks Daniel P. Berrange for the help in resolving issues.
And of course, many thanks to the staff of GSoC for running the programme.