Build on Docker

Snapcraft, the snap-building tool, is designed to use Multipass and bases to both simplify the build process and to confine the build environment within a virtual machine. This mostly removes the need to use Docker.

However, Docker can still be used, and is particularly useful when you’re already using Docker within your build and test infrastructure. All you need is a working snapcraft.yaml (see Creating a snap for more details).

To create a snap with Docker, first make sure you have Docker installed. You can test that Docker is correctly set up with:

$ docker run hello-world
[...]
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
[...]

If you don’t see the “Hello from Docker!” message, consult the Docker documentation for troubleshooting steps.

Snaps using bases

When using a base snaps other than core, a custom Docker image will need to be built. For details, see Creating docker images for snapcraft.

The process for building a core18 compatible image, the default for Snapcraft 3.x, is outlined below.

Docker images are built from a Dockerfile. This is a script that Docker interprets to assemble whatever is required to generate the image.

The following is an example Dockerfile to build a core18 compatible image:

stable.Dockerfile for core18
FROM ubuntu:bionic as builder

# Grab dependencies
RUN apt update
RUN apt dist-upgrade --yes
RUN apt install --yes \
      curl \
      sudo \
      jq \
      squashfs-tools

# Grab the core snap from the stable channel and unpack it in the proper place
# (the 'Snap-CDN: none' header allows building in restricted network
# environments such as Launchpad builders)
RUN curl -L -H 'Snap-CDN: none' $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core' | jq '.download_url' -r) --output core.snap
RUN mkdir -p /snap/core
RUN unsquashfs -d /snap/core/current core.snap

# Grab the core18 snap from the stable channel and unpack it in the proper place
RUN curl -L -H 'Snap-CDN: none' $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/core18' | jq '.download_url' -r) --output core18.snap
RUN mkdir -p /snap/core18
RUN unsquashfs -d /snap/core18/current core18.snap

# Grab the snapcraft snap from the stable channel and unpack it in the proper place
RUN curl -L -H 'Snap-CDN: none' $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/snaps/details/snapcraft?channel=stable' | jq '.download_url' -r) --output snapcraft.snap
RUN mkdir -p /snap/snapcraft
RUN unsquashfs -d /snap/snapcraft/current snapcraft.snap

# Create a snapcraft runner
RUN mkdir -p /snap/bin
RUN echo "#!/bin/sh" > /snap/bin/snapcraft
RUN snap_version="$(awk '/^version:/{print $2}' /snap/snapcraft/current/meta/snap.yaml)" && echo "export SNAP_VERSION=\"$snap_version\"" >> /snap/bin/snapcraft
RUN echo 'exec "$SNAP/usr/bin/python3" "$SNAP/bin/snapcraft" "$@"' >> /snap/bin/snapcraft
RUN chmod +x /snap/bin/snapcraft

# Multi-stage build, only need the snaps from the builder. Copy them one at a
# time so they can be cached.
FROM ubuntu:bionic
COPY --from=builder /snap/core /snap/core
COPY --from=builder /snap/core18 /snap/core18
COPY --from=builder /snap/snapcraft /snap/snapcraft
COPY --from=builder /snap/bin/snapcraft /snap/bin/snapcraft

# Generate locale
RUN apt update && apt dist-upgrade --yes && apt install --yes sudo snapd locales && locale-gen en_US.UTF-8

# Set the proper environment
ENV LANG="en_US.UTF-8"
ENV LANGUAGE="en_US:en"
ENV LC_ALL="en_US.UTF-8"
ENV PATH="/snap/bin:$PATH"
ENV SNAP="/snap/snapcraft/current"
ENV SNAP_NAME="snapcraft"
ENV SNAP_ARCH="amd64"

Dockerfiles for the Snapcraft project, including files that can be built with snapd from different channels, can be found on Snapcraft’s GitHub repository.

To build a Docker image, enter the following command from the same location as the saved version of the Dockerfile, which we’ve called stable.Dockerfile:

$ docker build --no-cache -f stable.Dockerfile --label mycustomimage --tag mycustomimage:stable --network host .

When the process has completed, you should be able to see the new image in the output from docker images:

REPOSITORY      TAG       IMAGE ID       CREATED              SIZE
mycustomimage   stable    76dcf5eafcd2   About a minute ago   882MB

Snaps without bases

If your snapcraft.yaml has no base entry or base: core defined, you can simply pull down the latest snapcraft image:

$ docker pull snapcore/snapcraft:stable
[...]
Status: Downloaded newer image for snapcore/snapcraft:stable

Running a build

After either building or downloading the snapcraft Docker image, return to the root directory of the project containing your snapcraft.yaml and run snapcraft:

$ docker run -v "$PWD":/build -w /build <IMAGE-NAME> snapcraft

Repleace <IMAGE-NAME> with either the name of your manually built Docker image, mycustomimage:stable in our example above, or the downloaded image, such as snapcore/snapcraft:stable.

These options instruct Docker to map the current directory, your project root, to the /snapcraft_build directory inside the container, and then start the snapcraft command (the final command-line argument) from this same location inside the container.

When the snap build completes successfully, you will find a .snap file in the current directory. You can inspect its contents to ensure it contains all of your application’s assets:

$ unsquashfs -l *.snap

Next steps

After creating a snap, you should upload it to the Snap Store, from where it can reach a potential audience of millions. See Releasing your app for further details.


Last updated 2 years ago.