Key | Value |
---|---|
Summary | Create your own image of Ubuntu Core 20, the latest release of our snap-based operating system. Make your own device image with some snap preinstalled or additional functionalities! |
Categories | iot |
Difficulty | 3 |
Author | Canonical Web Team webteam@canonical.com |
Overview
Duration: 1:00
Building a bespoke image for a supported platform enables an Ubuntu Core device to be customised at the point of deployment. Customisation options include configuration for both hardware and software, specific kernels, and which snap packages to pre-install.
We are going to create an image of the latest Ubuntu Core release, UC20, first by generating our own authority keys, then making the snap store aware of them, then creating and signing a model assertion before building the image.
This document will walk you through all the steps to build an image for an x86 device, but the same instructions will work for other platforms.
What you’ll learn
- Different fundamental snap notions on the board, like gadget, kernel and core snap
- Assembling a kernel and gadget snaps
- Creating and using your authority keys
- Create a model assertion for your target device
- Compose and build a custom image using the
ubuntu-image
command
What you’ll need
- Ubuntu 20.04 LTS desktop. You can’t do this on an Ubuntu Core device directly as creating your image can take quite some disk spaces. A VM can work as well.
- A Snap Store account to register your authority keys. See Create a developer account for details.
- An SSH public key associated with your Snap Store account. See Adding SSH keys to your account.
- Some very basic knowledge of command line use, know how to edit files.
How will you use this tutorial?
- Only read through it
- Read it and complete the exercises
0 voters
What is your current level of experience?
- Novice
- Intermediate
- Proficient
0 voters
Getting started
Duration: 1:00
To build a custom image, first use the snapcraft command to login to the Snap Store:
$ snapcraft login
Snapcraft can be installed with sudo snap install snapcraft --classic
, see Snapcraft overview for further details, and visit Create a developer account if you don’t yet have an account. Make sure you have an SSH public key associated with your account.
Before creating a custom model assertion, you will need to retrieve your developer ID and generate a properly formatted timestamp. The snapcraft command can be used to retrieve your developer id:
$ snapcraft whoami
email: <email>
developer-id: bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq
You will need to use the following date command to output the correctly formatted timestamp for the model assertion, but not yet! The date must be more recent than any key you need to generate in a later step.
$ date -Iseconds --utc
2021-01-25T10:40:41+00:00
Custom model assertion
Duration: 4:00
The model assertion is a text-based document that contains the fundamental definition of a snap-based device. It describes what the system image includes and is signed by the brand account owning the device definition.
The model assertion contains:
- Identification information, such as brand account id and model name.
- Which essential snaps make up the device system, including the gadget snap, kernel snap and the boot base snap with the root filesystem.
- Other required or optional snaps that implement the device functionality.
- Additional options for the defined device, such as grade for a UC 20 device.
The model assertion is central to both the creation of the device image and the deployed device’s lifecycle, in particular it:
- drives image creation via ubuntu-image. The resultant system seed includes the set of snaps and assertions specified in the model assertion.
- allows first boot verification of the system seed before its snaps are turned into an installed system.
- conveys model information, through registration from either the factory or in the field, which is used for cross-checking and registration affecting options, such as which account can issue a serial assertion for the device.
The following is a tweaked JSON-formatted custom model assertion based on
ubuntu-core-20-amd64
:
{
"type": "model",
"series": "16",
"authority-id": "bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq",
"brand-id": "bJzr2XzZ56Qv6Z51HIeziXvxtn1XItIq",
"model": "ubuntu-core-20-amd64",
"architecture": "amd64",
"timestamp": "2021-01-25T10:40:41+00:00",
"base": "core20",
"grade": "signed",
"snaps": [
{
"name": "pc",
"type": "gadget",
"default-channel": "20/stable",
"id": "UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH"
},
{
"name": "pc-kernel",
"type": "kernel",
"default-channel": "20/stable",
"id": "pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza"
},
{
"name": "core20",
"type": "base",
"default-channel": "latest/stable",
"id": "DLqre5XGLbDqg9jPtiAhRRjDuPVa5X1q"
},
{
"name": "snapd",
"type": "snapd",
"default-channel": "latest/stable",
"id": "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4"
},
{
"name": "htop",
"type": "app",
"default-channel": "latest/stable",
"id": "hJmReLmgXSUj4SF7WhyTVRV6IzUa4QUZ"
}
]
}
We’ve saved the above example to a file called my-model.json, and it contains the following modified properties:
- base: provides the run-time environment. core20 is the newest base, built from Ubuntu 20.04 LTS. core18 is the current standard base and is built from Ubuntu 18.04 LTS. See Base snaps for more details.
-
authority-id, brand-id: defines the authority signing the assertion
reference assertions are signed by canonical. Non-reference assertions are signed by their brand store. For a custom model assertion, this needs to be the developer ID. -
timestamp: UTC formatted time and date
used to denote the assertion’s creation time. -
snaps: “pc”, “pc-kernel”, “core20” and “snapd” are all required for a functioning core20 device. In addition to those, the example shows the arbitrary addition of a snap called ‘htop’ from the Snap Store. This is purely for illustration purposes. The id field is from the output of
snap info <snap-name> | grep snap-id
to ensure the correct snap is references.
For a complete list of model assertion keywords, see Model assertion.
Signing a model assertion
Duration: 5:00
The difference between building an image from a reference model assertion and
building from a modified model assertion is that the modified model assertion needs to be digitally signed. This is accomplished in four stages:
- create a key
- export/register the key
- sign the model assertion
- build the image
First, sign in to the Snap Store (snap login) and check whether there is already a published key available. You can list any published snaps with the snap keys command:
$ snap login
[...]
Login successful
$ snap keys
No keys registered, see `snapcraft create-key`
If you have no registered keys, create one as follows:
$ snap create-key my-key-name
Passphrase:
Confirm passphrase: <passphrase>
$ snap keys
Name SHA3-384
my-key-name E-n0AOKPFjIyy4S_i9JxTT4tkuaZf7rP9D2ARCmBNXjlgTGDjL8euFSlb87U0NPl
With a key created, use the snapcraft command to upload and register it with the store:
$ snapcraft register-key
[...]
Registering key...
You can safely generate the date string, as described in the Getting started section, and insert it into the model definition (the key we just created needs to be older than any generated date).
A custom model assertion is signed by piping the assertion through the snap sign command with the key name as its sole argument:
$ cat my-model.json | snap sign -k my-key-name > my-model.model
The resulting my-model.model
file contains the signed model assertion and can now be used to build the image.
Building the image
Duration: 3:00
With a signed model assertion, the Ubuntu Core image can now be built just like a reference image, using the ubuntu-image
command. First, install ubuntu-image if it isn’t already installed:
$ sudo snap install ubuntu-image --classic
You can now use ubuntu-image to build the image:
$ ubuntu-image snap my-model.model
ubuntu-image snap my-model.model
Fetching snapd
Fetching pc-kernel
Fetching core20
Fetching pc
Fetching htop
The output includes the img file itself, alongside _seed.manifest. The manifest file simply list the specific revision numbers for the snapd, htop, pc, pc-kernel and core20 snaps built into the image.
Testing the image
Duration: 8:00
To test your UC20 image with QEMU (https://www.qemu.org/), first install the OVMF package (eg. sudo apt install ovmf
) then run the following command to boot a UC20 image (renamed pc.img) within a virtual machine:
$ sudo qemu-system-x86_64 -smp 2 -m 2048 \
-net nic,model=virtio -net user,hostfwd=tcp::8022-:22 \
-drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
-drive file=pc.img,cache=none,format=raw,id=disk1,if=none \
-device virtio-blk-pci,drive=disk1,bootindex=1 -machine accel=kvm
Older OVMF packages can cause QEMU boot problems. Either build them manually, or consider extracting the files from a more recent package. OVMF for Ubuntu 20.04 LTS (Focal Fossa)](https://releases.ubuntu.com/20.04/) is known to work.
After running through the Ubuntu Core network setup and entering your account details, you will be able to SSH to your new Ubuntu Core deployment:
$ ssh <username>@localhost -p 8022
You are now connected to the Ubuntu Core virtual machine, from where you can configure and install whatever apps you need.
From within a running session on a custom image, you can run the pre-installed
snaps, such as htop:
$ htop
[...]
Use snap list to see which snaps are installed:
snap list
Name Version Rev Tracking Publisher Notes
core20 20201210 904 latest/stable canonical✓ base
htop 3.0.5 2069 latest/stable maxiberta -
pc 20-0.4 115 20/stable canonical✓ gadget
pc-kernel 5.4.0-64.72.1 708 20/stable canonical✓ kernel
snapd 2.48.2 10707 latest/stable canonical✓ snapd
The snap known model command will show the read-only custom model assertion used to build the image:
$ snap known model
type: model
authority-id: bJzr2XzZg6Qv6Z53HIeziXyxtn1XItIq
series: 16
brand-id: bJzr2XzZg6Qv6Z53HIeziXyxtn1XItIq
model: ubuntu-core-20-amd64
architecture: amd64
base: core20
grade: signed
snaps:
-
default-channel: 20/stable
id: UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH
name: pc
type: gadget
-
default-channel: 20/stable
id: pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza
name: pc-kernel
type: kernel
-
default-channel: latest/stable
id: DLqre5XGLbDqg9jPtiAhRRjDuPVa5X1q
name: core20
type: base
-
default-channel: latest/stable
id: PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4
name: snapd
type: snapd
-
default-channel: latest/stable
id: hJmReLmgXSUj4SF7WhyTVRV6IzUa4QUZ
name: htop
type: app
timestamp: 2021-01-25T10:40:41+00:00
sign-key-sha3-384: 9aZR3b1UX9kqiVVxzfUrK
[...]
Congratulations!
Duration: 1:00
You now have your own device image file for your specific device. This image is easily flashable on any SDCard or eMMC and can be booted right away.
You should by now be familiar with the various snaps composing an Ubuntu image: Core snap, kernel, gadget. You know that snapd is using a model assertion to define all pieces composing an image and this is what is used to build the image via the ubuntu-image tool.
Finally, you know also that you can change those default snaps, and add more applications snaps as you require them. If you produce your own gadget or kernel snap, you can swap as well default ones and enable a new board that way.
Next steps
- You should flash your new image to your device to test how it behaves
- Join the snapcraft.io community on the snapcraft forum.
- Take a look at the Ubuntu Core documentation