Deprecation notice
Snapcraft now supports the --use-lxd
command-line option, which can create a clean, compatible LXD container for snap building instead of using a Multipass VM.
While the instructions in this topic should still work to a degree we recommend using the built-in feature whenever possible to benefit from the upstream’s enhancements.
License
Creative Commons — Attribution-ShareAlike 4.0 International — CC BY-SA 4.0+, with an exception of explicitly licensed to be compatible with the snapcraft.io documentation’s licensing.
Benefits of snap development in a LXD container
Multipass builds are essentially virtual machines, which suffer from the limitations of a VM:
- Limited memory capacity, which is not shared with the host
- Limited computation resources as only a subset of CPU cores are used in the VM(but configurable)
- Lower efficiency as certain level of emulation is required
- Requires some extra time to boot from power-off state
Building snaps withing LXD containers will not affected by these limitations.
Demonstration-specific details
- The name of the container to-be-created is
my-snapcraft-playground
- Your regular account UID is
12345
Basic operations
Install LXD
Follow Linux Containers - LXD - Getting started - command line for the instructions. Note that the latest LXD distribution is provided via snaps.
(OPTIONAL) APT optimizations
By default Ubuntu containers use the non-localized archive.ubuntu.com
software source, which can be replaced by a faster mirror in your region.
NOTE: LXD profile modifications only apply to containers created in the future.
Before creating the container, run lxc profile edit default
to edit the default
profile, customize then merge the following config to the config key:
config:
user.user-data: |
#cloud-config
apt:
disable_suites: $RELEASE-proposed
primary:
- arches: [default]
uri: http://my.favorite.ubuntu.mirror/ubuntu/
conf: |
APT {
Get {
Assume-Yes "true";
}
Periodic {
Enable "0";
}
}
NOTE: The #cloud-config
line is NOT a comment, but an identifier of Cloud-Init’s cloud config data, which CANNOT be removed.
This cloud-init config sets the Ubuntu software archive to the my.favorite.ubuntu.mirror
site, and setup a APT configuration at /etc/apt/apt.conf.d/94cloud-init-config
to by default --assume-yes
in apt-get(8) and conforming utilities, this promises faster download speeds and smaller download sizes during package installation. It also disables APT’s periodic package management system maintenance as it will occasionally disturb with our package management operations.
References
- Official Archive Mirrors for Ubuntu
- Add apt repositories - Cloud config examples — Cloud-Init 18.1 documentation
- apt-get(8) manual page
- apt.conf(5) manual page
- Cloud Config Data - Formats — Cloud-Init 18.1 documentation
- /usr/lib/apt/apt.systemd.daily
Create a Ubuntu 16.04/18.04 LXD Container
If your snap is targeting the core
snap, run lxc launch ubuntu:16.04 my-snapcraft-playground
in the terminal to create a Ubuntu 16.04 container.
If your snap is targeting the core18
snap, run lxc launch ubuntu:18.04 my-snapcraft-playground
in the terminal to create a Ubuntu 18.04 container.
NOTE:
- By default LXD creates unprivileged containers.
- If you’re targeting the
core
snap create a Ubuntu 16.04 container instead.
Install Snapcraft
Run lxc exec my-snapcraft-playground -- snap install snapcraft --classic
to install snapcraft.
$ lxc exec my-snapcraft-playground -- snap install snapcraft --classic
2019-03-26T09:50:32Z INFO Waiting for restart...
snapcraft 3.2 from Canonical✓ installed
Set SNAPCRAFT_BUILD_ENVIRONMENT
environment variable to host
Currently Snapcraft builds the snap in a Multipass VM by default and will refuse to operate in the host environment, to tell Snapcraft to build snaps directly in the container we need to set the SNAPCRAFT_BUILD_ENVIRONMENT
environment variable to the value host
.
Run the lxc exec my-snapcraft-playground -- editor /etc/profile
and add the following line at the end of the file:
export SNAPCRAFT_BUILD_ENVIRONMENT=host
Maintain a clean Snapshot
Run the lxc stop my-snapcraft-playground
command to stop the container, and run lxc snapshot my-snapcraft-playground clean
to create a clean snapshot of the container.
NOTE: It is possible to create a snapshot while the container is running, the writer just prefers not to do so.
Whenever you want to restore the container to the clean state, run lxc restore my-snapcraft-playground clean
.
You can re-create the snapshot by running the lxc delete my-snapcraft-playground/clean
command to delete the old snapshot, make changes to the container(like upgrading the packages and snaps), and recreate a new one using the aforementioned lxc snapshot
command.
Conclusion
You may now access the shell of the default ubuntu
user by running lxc exec my-snapcraft-playground -- sudo --login --user ubuntu
username@hostname$ lxc exec my-snapcraft-playground -- sudo --login --user ubuntu
ubuntu@my-snapcraft-playground:~$
Now you can push the snapcraft recipe into the container via various VCS utilities or the lxc file push
command and run snapcraft
to build the snap inside the container. You can pull the snap package back to the host by using the lxc file pull
command.
The process can be more simplified and straight-forward by using the advance features of the LXD containers, refer the following section for info.
Advanced usage
Mount the source tree in the host system directly into the container
It is possible to reuse the source tree in the host to avoid pulling them manually in container. To achieve this a disk
device configuration is required.
Run lxc config device add my-snapcraft-playground 'Source Tree of Foo Software' disk source=/path/to/foo/software/source/tree path=/home/ubuntu/foo
to setup the mountpoint.
NOTE:
- The destination directory(e.g.
foo
in/home/ubuntu/foo
) need not to be created in advance. - Without user/group ID mapping, contents in mounted folders can not be modified within the container.
Reference
Setup user/group ID mapping for writable host source tree
The user and group IDs in unprivileged containers are shifted from the host ID range for security reasons, the result is the disk
device mounted host source tree is not writable in the container:
ubuntu@my-snapcraft-playground:~$ ls --format=long
total 4
drwxr-xr-x 27 nobody nogroup 4096 Mar 14 19:54 foo
An ID mapping configuration is required to make the ownership of files in host appears to be the same of the user in container so that regular write access is possible. This configuration is the lxc.idmap
key in LXC, and is exposed by LXD via the raw.idmap
key, which has the following format:
both 1000 1000
uid 50 500
gid 10000 10000
Run lxc config edit my-snapcraft-playground
and merge the following either config to map both host UID/GID of 12345 to container’s 1000 (The UID/GID of the default ubuntu
user)
config:
raw.idmap: both 12345 1000
or
config:
raw.idmap: |-
uid 12345 1000
gid 12345 1000
You must also edit the /etc/subuid
and /etc/subgid
host config to allow LXD using your UID & GID, the following one is the config I’m using:
lxd:100000:100000
root:100000:100000
lxd:12345:1
root:12345:1
WARNING: This particular config works for me™ but I AM TOTALLY NO IDEA WHY IT WORKS, it should be improved to be making sense
A container restart is required to apply the configuration, run lxc restart my-snapcraft-playground
to do so. If everything goes properly the mounted disk
device directory /home/ubuntu/foo
should now be owned by ubuntu
in the container and regular write access is available.
ubuntu@my-snapcraft-playground:~$ ls --format=long
total 4
drwxrwxr-x 14 ubuntu ubuntu 4096 Mar 26 02:58 foo
References
- Linux Containers - LXC - Manpages - lxc.container.conf.5 - UID MAPPINGS
- Custom idmaps - Userns idmap - LXD - system container manager
- Custom user mappings in LXD containers | Stéphane Graber’s website
- subuid(5) manpage
- subgid(5) manpage
Conclusion
Now you can map your source tree directly into the container and run snapcraft within it. You can create containers specific for certain snap’s building by running the lxc copy my-snapcraft-playground snapcraft-_snap_name_
command so that you can ensure it can be built cleanly from scratch.
Happy snapcrafting!