Build a kernel snap

The kernel snap is one of Ubuntu Core’s key components. It holds the Linux kernel image alongside its associated modules, the ramdisk image for system initialisation, and optional firmware and device tree files.

It’s one of the essential snaps that need to be specified in the model assertion when building a custom image. Being such a vital part of the system, it can be updated but it cannot be swapped.

See Types of snap for details on which snaps are integral to Ubuntu Core’s functionality.

Canonical publishes several reference kernel snaps, alongside kernel snaps for models such as the official Ubuntu Core VMs on various certified public clouds. There are also several general purpose computing images for popular physical devices such as 64-bit x86 PC and Raspberry Pi 2, 3 and 4:

A custom build of the Linux kernel allows for device-specific architectures, configuration and modifications, and manually building the kernel snap has the same advantages and requirements. Consequently, building a working kernel first is highly recommended, before migrating this to a kernel snap build. The same configuration options and dependencies will be required.

The main difference between a standard manual kernel build and building a kernel snap is that the latter is built via the snapcraft command, and its accompanying snapcraft.yaml, as outlined below.

Using LXD

Unlike broader snap packages, kernel snaps are typically built within the host environment using snapcraft --destructive-mode. This step can still be isolated from the host system by building the kernel with LXD. To do this, install LXD (if it’s not already installed), instantiate an Ubuntu image (Ubuntu 20.04.4 LTS Focal Fossa), and create the kernel build there:

sudo snap install lxd
sudo lxd init --auto
sudo lxc launch ubuntu:20.04 focal
sudo lxc shell focal
snap install snapcraft --classic

kernel snapcraft.yaml

The Ubuntu Linux kernels include a snapcraft.yaml for building a kernel snap, as do the kernels in the sample-kernels repository.

The following is a breakdown of a typical snapcraft.yaml used to build a kernel snap. It will need to be modified to fit your chosen platform and requirements, starting with the standard global keys and values used by all snaps:

name: kernel-snap-name
version: kernel version
summary: kernel snap quick description 
description: kernel snap longer description
grade: stable
confinement: strict

Next comes the snap-type definition to specify that we’re building a kernel snap:

type: kernel

The influence of the host environment, or LXD instance, can be mitigated with the optional build-base key, used to explicitly define the base snap used for the build environment.

build-base: core18

Similarly, it’s also common to build a kernel for a different architecture. This can be accomplished with architectures. The following example allows for an arm64 kernel to be built from an amd64 host:

  - build-on: amd64
    run-on: arm64

The kernel part declares the kernel plugin, its arguments, and the kernel build configuration:

    plugin: kernel
    source: .
    source-type: git
    kconfigflavour: generic
    kernel-image-target: Image
    kernel-with-firmware: false

The kernel plugin documentation lists the available options, but it’s the kconfigs: key that lists the kernel configuration options for the kernel snap.

The kernel can optionally be accompanied by a firmware section for bundling the firmware within the snap (the following example taken from the Ubuntu 20.04 kernel):

    plugin: nil
      - linux-firmware
      lib/firmware: firmware
      - -usr
      - -lib
      - cpio
      - libssl-dev

Building the kernel snap

With snapcraft.yaml complete, and the kernel source either cloned locally or linked to from the snapcraft.yaml, the snapcraft command will build the kernel. As mentioned earlier, it’s often more convenient to build the kernel within the host environment, using --destructive-mode:

# snapcraft --destructive-mode --target-arch=arm64
Snapped kernal-snap-name_arm64.snap

If the above command was executed within an LXD environment, the resultant kernel snap can be extracted with the following commands:

# exit
$ lxc file pull path/to/kernal-snap-name_arm64.snap .

The kernel snap has now been built and is ready to be integrated into an Ubuntu Core image. See Custom images for further details.

1 Like

I’ll make this comment only once … the Qualcomm DragonBoard is not actively maintained, its last release was for UC18, so it would not be unreasonable to drop references to it from ongoing docs.

Nice, thanks for letting us know.

How much do you want to cover building kernel snaps, as Canonical is typically responsible for the kernel snap during an enablement, no?

This document was specifically requested (despite being relatively high level) and I think going through the process is helpful, even if it’s just for transparency.

As with the gadget, I am here only to improve. Man, a better version would have made my first year so much easier…

As with the gadget snap,

break up into page 1 & 2
    - trivial: stage the (reference) snap
         - it's easier, so here we can showcase
           - trimming kernel modules
           - trimming firmware files
           - MAYBE explain unpacking the initrd for modification
             - However I think we can instead appeal to:

    - hard: build a kernel from source
          - probably focus on Ubuntu kernel?
             - includes KCONFIG, make, initrd
                - initrd may be its own page?
          - vendor kernel is challenging
            - don't necessarily want to "bless" their usage
            - may require additional patching (for snapd)

Good news:

  1. We (Kernel) have a nifty new repository with some cool tools we may be able to showcase
  2. We (Field) have some kernels which cover all three topics, and as such we might be able to simply link to those branches for the hard-vendor-kernel case and say “you are on your own, here be dragons” – I plan to make Field’s kernel repository public Soon™.

Bad news:

  1. Mad hard to explain kernel configuration, I don’t want to write a slashdot article.
  2. Will take a while to finish.

I think we can easily do at least the first page and cull this ancient content.