ROMs
Unikraft Cloud supports the ability to attach Read-Only Memory (ROM) blobs to instances. It allows you to create a general-purpose base image and then customize individual instances by attaching code or data as separate ROM blobs. This enables quick deployment of custom functionality to preexisting language environments without rebuilding the entire image.
Overview
With ROMs, you can:
- Deploy variations of an app from a single base image.
- Update app code without rebuilding the base image.
- Reduce image size and deployment time.
The ROM workflow consists of two main components:
- Base Image: A general-purpose image containing the runtime environment (for example, Python interpreter, Node.js, etc.).
- ROM Blobs: Separate, lightweight images containing your app code or any other data you want to customize.
This separation allows you to maintain one base image while deploying many different instances with different data.
By default, the app running inside the base image needs to mount the attached ROM device.
ROM blobs appear as block devices at paths like /dev/ukp_rom_<rom_name>, where <rom_name> is the ROM name you specify when creating the instance.
For convenience, this guide uses automounting by setting the at field on a ROM entry.
When at is present, the platform automatically mounts the ROM at the given path on boot, so your app can read files from it directly without any manual mount step.
Setup
This example shows how to deploy Python functions using ROMs on Unikraft Cloud.
Ensure you have the CLI installed and configured with your Unikraft Cloud account.
Make sure to log into Unikraft Cloud and pick a metro close to you.
This guide uses fra (Frankfurt, 🇩🇪):
Code
Base image
First, create a base image with a Python HTTP server that loads and executes custom Python programs from a ROM.
Dockerfile
The commands below will use the at field to automount the ROM.
That's why the Kraftfile omits the wrapper.sh script and the app can read the ROM file directly from /rom/rom.py.
This base image builds for x86_64 only, and its Dockerfile copies libraries from architecture-specific paths such as /lib/x86_64-linux-gnu.
To run the same base image on ARM hosts, add kraftcloud/arm64 to targets, and copy from the matching aarch64-linux-gnu paths.
See architectures for more detail.
Package and push the base image:
Code
Wait a few seconds for propagation and check that the image is present:
Code
ROM files
To showcase the benefits of using ROMs, create two files, each containing a Python function that the base image will load and execute. Create a separate directory for each of the ROMs:
ROMs are architecture-specific.
A ROM Kraftfile has no runtime to take architectures from, so it names them itself under targets, or you pass --arch on the command line.
A ROM build that does neither fails.
Listing more than one architecture builds the ROM for each of them in one invocation, and each instance needs the ROM that matches the architecture of its base image.
Package and push the ROMs:
Code
Wait a few seconds for upload and check that the ROMs are present:
Code
Instances
Create two instances with the same base image and attach different ROMs:
The API requires a name on each ROM entry, while the unikraft CLI derives one from at when you omit name=.
See ROM names and mount points for the rules that both fields follow.
Check that the instances are up:
Code
Note the roms array in the instances configurations.
Each ROM is available as a readable device at /dev/ukp_rom_python_function, in the form of an EROFS filesystem.
In this example, the platform mounts it automatically at /rom, and the app reads /rom/rom.py from that mount point.
Testing
Query the instances to call the Python function from the ROM. You should see different responses:
Code
Code
Cleanup
When done, remove the instances:
Code
Inline ROMs
Instead of pre-packaging and pushing a ROM image to a registry, you can provide file contents directly in the instance creation request.
This is useful when you create instances from a template where the snapshot locks ENV and ARGS, but you still need to inject instance-specific data.
An inline ROM is ephemeral: it's automatically deleted once the last reference to it is closed.
To use inline ROMs with unikraft, specify a local directory as source:
Code
API format
The API allows you to specify the contents of an inline ROM directly in the JSON request body when creating an instance.
Add a files array to a ROM entry instead of an image field:
POST /instances
Each file in the files array has three fields:
| Field | Description |
|---|---|
path | File path inside the ROM filesystem. The platform creates directories automatically. |
encoding | Either text (UTF-8 string) or base64 (base64-encoded binary data). |
data | The file contents in the specified encoding. |
The platform packages the provided files into an EROFS filesystem and attaches it as a ROM device, the same way image-based ROMs work.
The at field is optional and works the same as for image-based ROMs—when present, the platform mounts the ROM at the given path automatically.
Combining with image-based ROMs
You can mix inline ROMs and image-based ROMs in the same request:
POST /instances
Limits
The platform enforces the following default limits on inline ROMs:
| Limit | Default |
|---|---|
| ROMs per instance | 8 (inline and image-based combined) |
| Files per inline ROM | 16 |
| Total size per inline ROM | 1 MB (across all files) |
| Max API request body | 8 MB |
No per-file size limit exists. The total size limit applies to the combined size of all files in a single inline ROM. Since inline ROM data is base64-encoded in the JSON request body, the 8 MB request body limit is the practical upper bound on total data per API call.
ROM names and mount points
The guest derives each ROM's device node, /dev/ukp_rom_<name>, from the ROM's name.
A ROM name has a maximum length of 63 characters and contains only these characters, the same as a plugin name:
- Lowercase and uppercase letters (
a–z,A–Z) - Digits (
0–9) - Hyphen (
-) and underscore (_)
When a --rom flag carries no name=, the unikraft CLI builds the name from at.
It drops the leading /, turns every other / into -, and removes every character other than a letter, a digit, or -, so at=/rom/base gives the name rom-base.
A ROM can't share its name with a plugin of the same instance, and that includes a name the CLI derives from at.
For example, a ROM at /sandbox gets the name sandbox, which collides with the sandbox plugin.
The at field takes an absolute path without . or .. components and without colons (:).
The platform reserves /uk and every path below it for its own use in the guest, where it mounts plugins, so a ROM can't mount there.
The same rule applies to the mount points of volumes.
Two ROMs of the same instance also can't mount at the same path.
| Error message | Cause |
|---|---|
ROM name must be between 1 and 63 characters long | The name is empty or longer than 63 characters. |
ROM name may only contain the characters 'A'-'Z', 'a'-'z', '0'-'9', '-' and '_' | The name holds another character, such as the . of a file extension. |
The mountpoint must not be '/uk' or a path below it | The at path is /uk or a path below it. |
Failed to configure roms: EINVAL or Failed to configure plugins: EINVAL | A ROM and a plugin share a name, or two ROMs share a mount point. |
Failed to update roms: EINVAL or Failed to update plugins: EINVAL | A PATCH request that the platform applies right away breaks one of these two rules. |
When the platform can't apply a PATCH request right away, for example on a running instance, it queues the change.
It then checks these two rules only when it applies the change.
A queued change that breaks one of them shows up with "status": "failed" in the updates array of the instance status.
Learn more
Use the --help option for detailed information on using Unikraft Cloud:
Code
Or visit the CLI Reference. For more information on the features used in this use case and how to use them, check out the following documentation:
- Unikraft Cloud's REST API reference, and in particular the instances API.
- Tutorial explaining the difference of storage media on Unikraft Cloud.
- Running serverless functions packaged as ROMs on Unikraft Cloud.
- Running and customizing game servers using ROMs on Unikraft Cloud.