Snapd upstream project provides reference packaging for various distributions that are part of its CI process (Ubuntu, Debian, Fedora, openSUSE, Arch etc). The reference packaging is provided under the top level packaging directory in snapd source tree.
It is recommended to stay as close as possible to what is in the upstream repository. Snapd developers keep the packaging updated as new features or dependencies are introduced. At the same time, we are happy to accept patches and contributions related to packaging. If you find that the reference packaging is done incorrectly, or does not meet established conventions for your distribution, feel free to open a pull-request.
The guide focuses on packaging of snapd for use with a classic Linux distribution, such as Ubuntu, Fedora, Arch Linux, and not an immutable system like Ubuntu Core.
Majority of snapd is written in Go, but some smaller bits are written in C. See the go.mod file for the minimum required version of Go. While for building the C code any reasonably recent version of GCC or Clang will suffice.
Other high level build and runtime dependencies are:
- Linux kernel >= 4.4 (or otherwise reasonably recent)
- systemd
- autotools, pkg-config
- libc static
- libudev
- libseccomp
- libcap
- libapparmor (if using AppArmor)
- libselinux (if using SELinux)
- gnupg2
- python3-docutils
- squashfs
Snapd release assets consist of 3 source tarballs:
snapd_<ver>.tar.xz(e.g.snapd_2.72.tar.xz) - a unified snapshot, which includes the snapd source tree plus all vendored Go dependenciessnapd_<ver>.no-vendor.tar.xz- snapshot without any Go dependenciessnapd_<ver>.only-vendor.tar.xz- snapshot of all Go dependencies only
Refer to the packaging policy of your distribution to decide which source tarball is appropriate for your use case.
The build process of snapd is split in a couple of parts:
- set snapd version
- configure and build the C code
- configure and build the Go code
- generate any other data files
The build version is set by invoking mkversion.sh script like so:
./mkversion.sh <snapd-version>
# e.g. 2.72.1 with Arch build tag
./mkversion.sh 2.72.1-arch1All of the C code is contained within cmd directory. It is configured and
built using autotools. The high level process for building the code is:
cd cmd
autoreconf -i -f
./configure <options>Most relevant configure options:
--enable-apparmor- enable AppArmor support--enable-selinux- enable limited SELinux support--libexecdir- set the location of where snapd internal tools are located, typically /usr/lib/snapd (or /usr/libexec/snapd)--with-snap-mount-dir- expected snap mount directory, typically /var/lib/snapd/snap (or /snap)
It is recommended to use packaging/snapd.mk helper for simplifying the build
of Go code which will invoke go build with appropriate options and build tags.
The helper requires a bit of configuration, see openSUSE RPM
spec for examples of usage. It expects to find a
snapd.defines.mk configuration file within the build directory. The file
itself it directly included by snapd.mk and so it must follow Make syntax. An
example snippet which generates the configuration file, extracted from openSUSE
RPM spec, is provided below:
# This file is generated by openSUSE's snapd.spec
###
# Directory variables.
###
# Desired installation prefix, usually /usr
prefix = %{_prefix}
# Desired installation path for system wide binaries, usually /usr/bin
bindir = %{_bindir}
# ...and /usr/sbin
sbindir = %{_sbindir}
# Desired location of snapd internal tools, one of /usr/lib/ or /usr/libexec/
libexecdir = %{_libexecdir}
# Location of manpages, typically /usr/share/man
mandir = %{_mandir}
# Location of data files, typically /usr/share
datadir = %{_datadir}
# Location of local state, typically /var/lib
localstatedir = %{_localstatedir}
# Location of shared state, typically /var
sharedstatedir = %{_sharedstatedir}
# Systemd system units directory, usually /usr/lib/systemd/system
unitdir = %{_unitdir}
# Build directory, depends on the build environment
builddir = %{_builddir}
###
# Build configuration
###
# Enable or disable Ubuntu Core specific pieces, 0|1
with_core_bits = 0
# Expect alternative snap mount directory, 0|1
with_alt_snap_mount_dir = 1
# Enable AppArmor support, 0|1
with_apparmor = 1
# Enable use of PIE when building static binaries, 0|1
# Ensure support in your distribution toolchain.
with_static_pie = $build_with_static_pie
# Use vendored dependencies, 0|1
with_vendor = 1
# Pass any additional flags to `go build`
EXTRA_GO_BUILD_FLAGS = -v -x
# Pass any additional flags for `go tool link` in go build invocation
EXTRA_GO_LDFLAGS = -compressdwarf=false
# Enable test keys
# NOTE this option is relevant only in builds for snapd CI
with_testkeys = 0The helper is invoked like so:
make -f packaging/snapd.mk \
SNAPD_DEFINES_DIR=$PWD \
install # or: build|check|clean|allWhere SNAPD_DEFINES_DIR is set to the path of the directory containing
snapd.defines.mk file.
The top level data directory contains additional files that need to be
configured and built. Those are systemd units, completion support, SELinux
policy module, environment tweaks and similar. The build and installation is
carried out like so, passing a number of overrides for the desired filesystem
locations (snippet extracted from Fedora
packaging):
pushd ./data
make BINDIR="%{_bindir}" LIBEXECDIR="%{_libexecdir}" DATADIR="%{_datadir}" \
SYSTEMDSYSTEMUNITDIR="%{_unitdir}" \
USE_CANONICAL_SNAP_MOUNT_DIR=false \
USE_ALT_SNAP_MOUNT_DIR=true \
SNAPD_ENVIRONMENT_FILE="%{_sysconfdir}/sysconfig/snapd"
# or
make install BINDIR=...
popdIt is essential to pass the same set of Make variable overrides during build and installation.
The following binaries are provided by the native host package, but need to be executed within the snap sandbox, and as such they need to be built statically:
- snap-exec
- snap-update-ns
- snapctl
- snapd-gdbserver-shim
The reference packaging contains relevant snippets for confirming that the binaries listed above are indeed built statically. Packagers are encouraged to copy the applicable snippets as needed.
The snap-confine binary is expected to have the file capabilities listed in
cmd/snap-confine/snap-confine.v2-only.caps.
set on it once the package has been installed.
The cmd/snap-confine/snap-confine.caps
file lists the same set of capabilities, but additionally includes
cap_setuid,cap_setgid, which is a workaround for kernel cgroup v1 issues and
relevant only if expecting that the snapd package will be used within a
container running on a host kernel that is booted with cgroup v1 support.
Packaging is encouraged to not ship or otherwise use this file, unless
deemed necessary for the use case.
The main systemd units are snapd.service, the snapd daemon, and
snapd.socket, a socket unit which is responsible for creating the two sockets
over which clients communicate with snapd: /run/snapd.sock (for snap command),
and /run/snapd-snap.sock (for calls from within the sandbox using snapctl
tool).
On systems with AppArmor enabled, snapd.apparmor.service needs to be installed
as well. It is a dedicated unit which invokes snapd-apparmor internal tool,
that is responsible for loading AppArmor profiles of installed snaps.
The table provides a summary of all systemd units that are relevant for classic distribution packaging:
| Unit | Kind | Purpose |
|---|---|---|
snapd.service |
system | Main snapd service |
snapd.socket |
system | Snapd sockets unit, activates snapd.service |
snapd.apparmor.service |
system | Loads snap AppArmor profiles |
snapd.mounts.target |
system | Synchronization target right after snap mounts have completed |
snapd.mounts-pre.target |
system | Synchronization target for mounting snap units |
snapd.seeded.service |
system | Service waiting for snapd initialization to complete |
snapd.session-agent.service |
user | User session agent |
snapd.session-agent.socket |
user | User session socket for communication with snapd, activates the agent |
It is recommended to enable at least snapd.socket and
snapd.session-agent.socket units, however this should be done in accordance
with a policy established by a given distribution.
The snapd daemon will create relevant state directories as needed (see the
reference packaging for a list of actual locations), however some directories
are expected to be created by the packaging, those are:
- /usr/lib/snapd or /usr/libexec/snapd - snapd internal tools directory
- /var/lib/snapd/snap or /snap - snap mount directory
Consult your distribution policies to decide which locations are appropriate.
Historically, the internal tools and snap mount directories needed to be
hardcoded in snapd, however starting with 2.71, snapd will probe and use the
locations created by distribution packaging.
Support for classic snaps (such as code editors, compilers etc.) requires /snap to be present, either as directory, or as a symbolic link pointing to /var/lib/snapd/snap. The users are free to create a symbolic link themselves and the packaging should account for that.
Snapd provides support scripts that can be used during package installation:
This script is expected to be invoked during package removal, in a pre-remove step, like so:
${libexecdir}/snapd/snap-mgmt --purgeIts purpose is to ensure that all snaps and their data is removed from system wide locations.
A support script which can be invoked from the snapd SELinux policy subpackage. Its purpose is to patch snap mount units to use a dedicated SELinux context for all snap mounts. The script is only relevant if there is possibility that the users, on a SELinux enabled system, may be updating from snapd older than 2.39.