ROMs
DISCLAIMER
The ROM feature isn't currently enabled for the public Unikraft Cloud offering. As such, the CLI can't entirely leverage this feature. For boxes where it's enabled, use it via the Unikraft Cloud API.
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, you can use automounting by setting the at field on a ROM entry.
When at is present, the platform automatically mounts the ROM at the given path before the instance starts, 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 kraft CLI installed and configured with your Unikraft Cloud account.
Set the following environment variables:
Base Image
First, create a base image with a Python HTTP server that loads and executes custom Python programs from a ROM.
If you use the at field when attaching the ROM (see Automounting), the platform handles the mount for you and you can remove wrapper.sh and the mount/mkdir calls entirely.
Ensure that the wrapper.sh script is executable:
Package and push the base image:
Wait a few seconds for propagation and check that the image is present:
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:
Package and push the ROMs:
Wait a few seconds for propagation and check that the ROMs are present:
The --no-kernel flag tells kraft to package only the ROM files, without the kernel, since this is data that will get attached to another image.
This example packages the ROMs as EROFS filesystems.
If packaging the ROMs as a cpio archives (that is, --rootfs-type cpio), or as standalone files, you must align their size to 4096 bytes.
Instances
Create two instances with the same base image and attach different ROMs:
Check that the instances are up:
Note the roms array in the instances configurations.
Each ROM is available as a readable device at /dev/ukp_rom_python_function.py (in the form of an EROFS filesystem in this case), which the server program mounts at /tmp/rom.py and executes.
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.
API format
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.
Automounting
Instead of mounting the ROM device manually inside the guest, you can set the optional at field on any ROM entry.
The platform will then mount the ROM at the specified path before the instance starts.
POST /instances
With this configuration the EROFS filesystem is mounted at /tmp automatically, so /tmp/rom.py is available to the app without any mount call in a wrapper script.
In this case you can simplify or remove the wrapper.sh from the base image, since the platform handles the mount for you.
The at field is optional--omitting it leaves the ROM as a raw block device at /dev/ukp_rom_<name> and the guest remains responsible for mounting it.
Inline ROMs
Instead of referencing a pre-built image, you can supply file contents directly in the instance creation request using inline ROMs.
You specify an inline ROM by a files array instead of an image field.
Each entry in the array specifies the file path inside the ROM filesystem, the encoding of the provided data ("base64" or "text"), and the raw data string.
POST /instances
Inline ROMs are particularly useful when working with instances created from templates, where you can't change the environment variables and startup arguments of the original template. By attaching an inline ROM you can inject configuration files, scripts, or other data into the instance at creation time without modifying the base image or the template.
An inline ROM is ephemeral: it's automatically deleted once the last reference to it is closed.
Testing
Query the instances to call the Python function from the ROM. You should see different responses:
Cleanup
When done, remove the instances:
Learn more
- The CLI reference and the legacy CLI reference.
- Unikraft Cloud's REST API reference, and in particular the instances API.
- The
kraft pkgcommand reference for packaging images and ROMs. - The systemd
mountman page for filesystem mount options relevant to manual mounting scenarios.