In the world of modern software development, it's crucial to stay ahead of the curve and embrace cutting-edge technologies. Unikernels, which are specialized, single-address-space machine images that run a single application, have been gaining traction as a powerful approach to building lightweight, secure, and highly efficient software systems.
Unikraft, an open-source project for building unikernels, has been at the forefront of this movement. It offers developers a versatile and efficient framework to create unikernels for various use cases. And today, we're thrilled to introduce KraftKit v0.7.0, a huge update to the companion command-line tool that makes Unikraft even more accessible and developer-friendly!
With a whole slew of new features and improvements, KraftKit v0.7.0 is a game-changer for unikernel development.
The highlights of this KraftKit release:
kraft cloudcommand, for deployments via KraftCloud.
Let's dive into the exciting new features and improvements in this release:
Kraftfilev0.6 Specification Update#
This release introduces a new
Kraftfile specification which makes new adjustments to the user's workflow such that it is easier to run applications in binary compatibility mode and with a template.
At a high-level, the following adjustments are made to the specification:
runtimeelement to be used for defining the user of an elfloader or existing pre-built unikernel image. Similar to other component-type elements like
runtimeelement is intended to allow for a short-hand and long-hand syntax where a
versionand set of
kconfigoptions can be used to qualify the elfloader application.
platformelement names such that can be used in short-hand syntax as
volumeselement which is used for defining user-specified paths which are to be used during runtime of a unikernel.
rootfselement which is used for defining the root filesystem of the user. The provided implementation allows a user to serialize a filesystem from three new contexts: an existing CPIO archive (pass-through), a path to a directory, and a
Dockerfilewhich is constructed via BuildKit.
cmdwhich is a string or list which represents the command-line argument to execute for the unikernel as a way to porcelain the Kraftfile and the intended application use case.
Aside from these introductions to the v0.6 specification, the underlying parser is adjusted to handle reading both the specifications and defaulting to v0.6 as the latest. These adjustments are subsequently implemented through the release.
Kraftfilev0.6 specification changes#
In addition to bumping the specification version to v0.6, the
specification element can be abbreviated to
Within the list of
platform attributes can be abbreviated to
plat, respectively, and be used interchangeably:
targets:- plat: qemuarch: x86_64
targets:- plat: qemuarchitecture: x86_64
targets:- platform: qemuarch: x86_64
The list of targets can now accept an even shorter syntax where only the architecture and platform are desired in the list:
This shorthand syntax can be mixed with full target elements:
targets:- qemu/x86_64- platform: qemuarchitecture: arm64- plat: fcarch: x86_64
cmdelement for specifying program operation#
cmd is array or string element which can be used for setting default arguments to be used during the instantiation of a new unikernel instance:
Specified as an in-line array:
spec: v0.6cmd: ["-c", "/nginx/conf/nginx.conf"]
Specified as a multi-line array:
spec: v0.6cmd:- -c- /nginx/conf/nginx.conf
Specified as a string:
spec: v0.6cmd: "-c /nginx/conf/nginx.conf"
runtimeelement for accessing pre-built images#
runtime element is a new top-level element which has been designed to ease the declaration of a previously constructed unikernel image in the project.
In many cases, specifically instances where the user is writing in a high-level language such as Python or where they wish to use a pre-built Linux userpace image, the user does not care for wanting to build a unikernel image from scratch.
Instead, the goal is to leverage pre-built unikernel images which are distributed using the OCI Package Manager.
Similar to the top-level
template elements (see below), the
runtime element can be specified using a short-hand syntax or a long-hand syntax for greater control or preference.
In short-hand syntax, simply referencing the pre-built unikernel image is possible by declaring:
spec: v0.6runtime: unikraft.org/nginx:latest
In the above example, the
runtime element refers to an OCI archive for Nginx.
kraft run scenario, this is simply pulled and executed verbatim.
Paired with the ability to customize the
rootfs element or
volumes elemen, the
runtime element becomes more pragmatic:
spec: v0.6runtime: unikraft.org/nginx:latestrootfs: ./
Or with a volume, which simply "overwrites" an existing directory already located within Nginx's root filesystem that is distributed as part of the OCI image:
spec: v0.6runtime: unikraft.org/nginx:latestvolumes:- ./html:/nginx/html
In the above snippet, the user customizes only the directory which serves HTML with a path
./html which is located on their host.
Note that this usecase is not limited to a single application and applies to the ELF Loader application and customizing the loaded application which is part of a root filesystem:
spec: v0.6# Default ELF Loader applicationruntime: unikraft.org/base:latest# Path must contain the Linux ELF binary, e.g. at ./rootfs/helloworldrootfs: ./rootfscmd: ["/helloworld"]
or a high-level programming language such as python3:
spec: v0.6runtime: unikraft.org/python3:latestrootfs: ./Dockerfilecmd: ["/main.py"]
In the above snippet, the user has created a
Dockerfile which contains the necessary root filesystem and included their application at
The long-hand syntax allows specifically setting
kconfig options which are requirements of the runtime:
spec: v0.6runtime:source: unikraft.org/nginxversion: latestkconfig:CONFIG_LIB9PFS: 'y'
In the above example, the pre-built Nginx unikernel has been requested as the runtime with the explicit option of having the 9P Filesystem enabled.
There were several issues related to the
template element, including the fact that it was not properly seeded, or transformed, from the
Kraftfile into the application structure.
This has now been tested end-to-end and enables:
Workflows where a user may wish to reference an existing application repository and make customizations, for example, with the ELF Loader application, making changes to the core configuration and adding additional targets:
spec: v0.6template: https://github.com/unikraft/app-elfloader.gitunikraft:version: stablekconfig:CONFIG_LIBUKLIBPARAM: 'y'CONFIG_LIBNOLIBC: 'y'CONFIG_LIBNOLIBC_UKDEBUG_ASSERT: 'y'CONFIG_LIBPOSIX_EVENT: 'y'CONFIG_LIBPOSIX_FUTEX: 'y'CONFIG_LIBPOSIX_MMAP: 'y'CONFIG_LIBPOSIX_releaseOCESS: 'y'CONFIG_LIBPOSIX_releaseOCESS_PIDS: 'y'CONFIG_LIBPOSIX_releaseOCESS_MAX_PID: 31CONFIG_LIBPOSIX_releaseOCESS_CLONE: 'y'CONFIG_LIBPOSIX_SOCKET: 'y'CONFIG_LIBPOSIX_SYSINFO: 'y'CONFIG_LIBPOSIX_TIME: 'y'CONFIG_LIBPOSIX_USER: 'y'CONFIG_LIBUKSIGNAL: 'y'CONFIG_LIBSYSCALL_SHIM: 'y'CONFIG_LIBVFSCORE_AUTOMOUNT_ROOTFS: 'y'CONFIG_LIBVFSCORE_ROOTFS_INITRD: 'y'CONFIG_LIBVFSCORE_ROOTFS: "initrd"CONFIG_APPELFLOADER_VFSEXEC_EXECBIT: 'n'targets:- plat: qemuarch: x86_64kconfig:CONFIG_VIRTIO_BUS: 'n'- plat: firecrackerarch: x86_64
Similar to other component elements (e.g.
template element can be expressed in a longer format:
spec: v0.6template:source: https://github.com/unikraft/app-elfloader.gitversion: stable
The following workflow scenarios were used during testing.
Customizing the whole root filesystem is now possible by supplying either:
A path representing a prebuilt CPIO archive file:
spec: v0.6runtime: unikraft.org/nginx:latestrootfs: ./initramfs.cpio
A directory which will be dynamically serialized into a CPIO archive:
spec: v0.6runtime: unikraft.org/nginx:latestrootfs: ./rootfs/
Dockerfile which will be built via BuildKit and then serialized into a new CPIO archive:
spec: v0.6runtime: unikraft.org/nginx:latestrootfs: ./Dockerfile
To use BuildKit, set the address within the new
buildkit_host user setting, the new environmental variable
KRAFTKIT_BUILDKIT_HOST or the command-line flag
This defaults to
Specifying via short-hand syntax a map between a directory on the host and a path within the instance:
spec: v0.6runtime: unikraft.org/nginx:latestvolumes:- ./src:/nginx/html
Using a more verbose (long-hand) syntax and mapping between the mount on the host and a path within the instance:
spec: v0.6runtime: unikraft.org/nginx:latestvolumes:- source: ./srcdestination: /nginx/html
This contains breaking changes to the OCI package manager. As a result, when you upgrade be sure to re-package and re-push your OCI images.
This large refactor reworks the OCI package manager to assume the use of the OCI image specification's index such that we can represent multiple manifests within a single canonical referencable name. This means that we can build multiple unikernels with the same name. This makes sense for multi-target projects which build the same application but target different hardware/platform vendors.
The structure of the index can be found here and in this implementation we itemized each manifest in the index in the same way.
When we use the
Catalog method now, we are able to query a remote registry based on the selected OS (platform) and architecture as well as any embedded KConfig options (if they are embedded).
When packaging multiple targets of a single application, the resulting package will be listed for all unique targets:
kraft pkg ls --apps
TYPE NAME VERSION FORMAT DIGEST PLATapp helloworld latest oci e8be0a9 qemu/x86_64app helloworld latest oci a6802f4 qemu/arm64
Use cases include selecting appropriately based on the host's architecture as well as feature selection via embedded KConfig options.
Notable additional improvements which are incorporated in this pull request include:
kraftin offline mode;
kraft pkg lswhich now has dynamic column data information;
kraft pkgfor selecting and packaging individual targets from an application project;
kraft pkg prunehas been renamed to
kraft pkg rmand now works for all underlying implementations (per-manifest type for libraries and components, and directory and containerd for OCI packages);
kraft pkg pullwhen no additional flags are provided.
Following the ability to package multiple platform/architecture combinations now using a single canonical OCI image reference, and to help ease using pre-built unikernel applications, we're excited to release a new community catalog of pre-built unikernel images, ready to use.
kraft pkg ls --apps --update
This release includes the ability to construct root filesystems from new and existing
This is made possible by rearchitecting the
initrd package to support different input types.
When using a root filesystem which is ultimately serialized into a CPIO archive (including previously built CPIO archives which simply represent a no-op), these can be dynamically built.
Dockerfile via BuildKit to build root filesystems offers several advantages in terms of efficiency, portability, and ease of management which were considered before implementation:
Dockerfileenables you to specify the exact steps needed to build your filesystem, making the build process reproducible.
Ease of Use
Dockerfileprovides a user-friendly, human-readable format for defining the build steps, making it accessible to developers with varying levels of expertise.
To get started building
Dockerfiles as part of your existing project, check out the updated documentation on filesystem support in KraftKIt.
Feel free to ask questions, report issues, and meet new people.