This guide explains how to deploy TypeScript/JavaScript functions as auxiliary Read-Only Memory (ROM) images, then load them dynamically in a Node.js runtime. With Unikraft Cloud, you can create a base image with a generic runtime, package custom code as ROMs, and attach different ROMs to instances of the same base image.
-
Install the CLI: Use the unikraft CLI or the legacy kraft CLI. You need a BuildKit builder. The easiest way is via Docker. Alternatively, set up and use BuildKit directly, see the quick start.
-
Clone the
examplesrepository andcdinto theexamples/node-code-executiondirectory:git clone https://github.com/unikraft-cloud/examples cd examples/node-code-execution/
Make sure to log into Unikraft Cloud and pick a metro close to you.
This guide uses fra (Frankfurt, π©πͺ):
Using the unikraft CLI (Recommended)
unikraft loginor
Using the legacy kraft CLI
# Set Unikraft Cloud access token
export UKC_TOKEN=token
export UKC_METRO=fraFirst, package and push the base Node.js image (see server.ts for the runtime implementation):
Using the unikraft CLI (Recommended)
unikraft build . --output <my-org>/node-code-exec:latestor
Using the legacy kraft CLI
kraft pkg \
--name index.unikraft.io/<my-org>/node-code-exec:latest \
--plat kraftcloud \
--arch x86_64 \
--rootfs-type erofs \
--push \
.The server implementation in server.ts is a simple Node.js application that listens for HTTP requests and executes JavaScript code from the attached ROM, if available.
There is a little tweakβright before loading the ROM code and starting the server, it writes 1 to the special file /uk/libukp/template_instance (see https://unikraft.com/docs/platform/instances#instance-templates), triggering a conversion of the instance into a template.
Create an instance that uses the base Node.js image without any ROM attached:
Using the unikraft CLI (Recommended)
unikraft run --metro fra \
--name node-exec \
-m 512M \
--image <my-org>/node-code-exec:latestor
Using the legacy kraft CLI
kraft cloud instance create \
--start \
--name node-exec \
-M 512Mi \
<my-org>/node-code-exec:latestThe output shows the instance details:
Using the unikraft CLI (Recommended)
metro: fra
name: node-exec
uuid: 96608ed2-45e0-4c8f-8269-5d8cd3e4b41a
state: starting
image: <my-org>/node-code-exec
resources:
memory: 512MiB
vcpus: 1
networks:
- uuid: 6f7a8b9c-0d1e-2f3a-4b5c-f6a7b8c9d0e1
private-ip: 10.0.5.4
mac: 12:b0:6c:3e:ab:95
timestamps:
created: just now
or
Using the legacy kraft CLI
[β] Deployed successfully!
β
ββββββββββ name: node-exec
ββββββββββ uuid: 96608ed2-45e0-4c8f-8269-5d8cd3e4b41a
βββββββββ metro: https://api.fra.unikraft.cloud/v1
βββββββββ state: starting
βββββββββ image: oci://unikraft.io/<my-org>/node-code-exec@sha256:71487fd6196987cf65fb89eb84405cb796677aba177dabacf391f09618313328
ββββββββ memory: 512 MiB
ββ private fqdn: node-exec.internal
ββββ private ip: 10.0.5.4
This instance is short-lived, since right before the server starts, it triggers a conversion into a template. To check that the template is ready, run:
Using the unikraft CLI (Recommended)
unikraft instances templates listUsing the unikraft CLI (Recommended)
METRO NAME STATE IMAGE ARGS MEMORY VCPUS CREATED
fra node-exec template <my-org>/node-code-exec 512MiB 1 5 seconds agoor
Using the legacy kraft CLI
kraft cloud instance template listUsing the legacy kraft CLI
NAME IMAGE ARGS CREATED AT
node-exec oci://unikraft.io/<my-org>/node-code-exec@sha256:71487fd6196987cf65fb89eb84405cb796677aba177dabacf391f09618313328 5 seconds agoCreate and push the ROMs with the code (see rom1/fs/rom.js and rom2/fs/rom.ts):
Using the unikraft CLI (Recommended)
unikraft build rom1/ --output <my-org>/node-rom1:latest
unikraft build rom2/ --output <my-org>/node-rom2:latestor
Using the legacy kraft CLI
kraft pkg \
--name index.unikraft.io/<my-org>/node-rom1:latest \
--rom ./fs \
--rom-type erofs \
--plat kraftcloud \
--arch x86_64 \
--push \
rom1/
kraft pkg \
--name index.unikraft.io/<my-org>/node-rom2:latest \
--rom ./fs \
--rom-type erofs \
--plat kraftcloud \
--arch x86_64 \
--push \
rom2/Create a new instance from the template, attaching the first ROM:
Using the unikraft CLI (Recommended)
unikraft run --metro fra \
--name node-exec-rom1 \
-p 443:8080/tls+http \
--scale-to-zero policy=on,cooldown-time=1000,stateful=true \
--rom image=<my-org>/node-rom1:latest,at=/rom \
--template node-execor
Using the legacy kraft CLI
# kraft does not support creating instances with attached ROMs, but you can use the API directly
curl -X POST "$UKC_METRO/instances" \
-H "Accept: application/json" \
-H "Authorization: Bearer $UKC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "node-exec-rom1",
"template": {
"name": "node-exec"
},
"autostart": true,
"service_group": {
"services": [
{
"port": 443,
"destination_port": 8080,
"handlers": ["tls", "http"]
}
]
},
"scale_to_zero": {
"policy": "on",
"stateful": true,
"cooldown_time_ms": 1000
},
"roms": [
{
"name": "js_function",
"image": "index.unikraft.io/<my-org>/node-rom1:latest",
"at": "/rom"
}
]
}'Create another instance from the same template, but with the second ROM attached:
Using the unikraft CLI (Recommended)
unikraft run --metro fra \
--name node-exec-rom2 \
-p 443:8080/tls+http \
--scale-to-zero policy=on,cooldown-time=1000,stateful=true \
--rom image=<my-org>/node-rom2:latest,at=/rom \
--template node-execor
Using the legacy kraft CLI
# kraft does not support creating instances with attached ROMs, but you can use the API directly
curl -X POST "$UKC_METRO/instances" \
-H "Accept: application/json" \
-H "Authorization: Bearer $UKC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "node-exec-rom2",
"template": {
"name": "node-exec"
},
"autostart": true,
"service_group": {
"services": [
{
"port": 443,
"destination_port": 8080,
"handlers": ["tls", "http"]
}
]
},
"scale_to_zero": {
"policy": "on",
"stateful": true,
"cooldown_time_ms": 1000
},
"roms": [
{
"name": "ts_function",
"image": "index.unikraft.io/<my-org>/node-rom2:latest",
"at": "/rom"
}
]
}'List the instances and note their FQDN values:
Using the unikraft CLI (Recommended)
unikraft instances listMETRO NAME STATE IMAGE ARGS MEMORY VCPUS FQDN CREATED
fra node-exec-rom2 standby <my-org>/node-code-exec 512MiB 1 nameless-wood-gw7pbnls.fra.unikraft.app 2 minutes ago
fra node-exec-rom1 standby <my-org>/node-code-exec 512MiB 1 sparkling-dawn-syowlbtj.fra.unikraft.app 3 minutes agoor
Using the legacy kraft CLI
kraft cloud instance listNAME FQDN STATE STATUS IMAGE MEMORY VCPUS ARGS BOOT TIME
node-exec-rom2 nameless-wood-gw7pbnls.fra.unikraft.app standby standby oci://unikraft.io/<my-org>/node-code-exec@sha256:71487f... 512 MiB 1 6.98 ms
node-exec-rom1 sparkling-dawn-syowlbtj.fra.unikraft.app standby standby oci://unikraft.io/<my-org>/node-code-exec@sha256:71487f... 512 MiB 1 7.86 msTest both instances:
curl https://sparkling-dawn-syowlbtj.fra.unikraft.app
curl https://nameless-wood-gw7pbnls.fra.unikraft.appBye, World!
Auf Wiedersehen!
Use the --help option for detailed information on using Unikraft Cloud:
Using the unikraft CLI (Recommended)
unikraft --helpor
Using the legacy kraft CLI
kraft cloud --helpOr visit the CLI Reference or the legacy CLI Reference.