Skip to content

Port a Linux app

You do not need to rewrite a Linux container as a unikernel before testing it with SpaceOS. Start with the existing OCI image, describe where it runs in build.yaml and run.yaml, then move from local execution to a named target.

Linux services share the partition’s Linux kernel, so they provide weaker isolation than a unikernel. They are still the fastest path for existing software, especially when the application depends on a standard Linux userland or a large dependency tree.

Prerequisites

  • An OCI image for your application. Images that run with docker run can use the Linux service path.
  • The Space CLI (space), installed from the Parsimoni Homebrew tap: brew install parsimoni/tap/space.
  • A local SpaceOS environment from the quickstart.

Check the image

Run the image with your usual OCI tool first:

Terminal window
docker run --rm ghcr.io/<your-org>/<your-app>:latest

Space CLI resolves service images by OCI reference. Push the image to a registry that your local environment and deployment target can reach:

Terminal window
docker push ghcr.io/<your-org>/<your-app>:latest

Private registries work, but the target environment must have credentials for the reference you use in build.yaml.

Describe the service

Create a project with a build.yaml that bundles the service image:

schema: space.build
version: "1"
kernel: linuxkit/kernel:6.6.13
output: _build/spaceos
partitions:
payload:
init: pid1
disk: true
services:
- name: my-app
image: ghcr.io/<your-org>/<your-app>:latest
runtime: oci
isolation: runc
healthcheck:
type: command
argv: ["/bin/sh", "-lc", "test -f /tmp/ready"]

build.yaml defines what goes into the composition without choosing a target or allocating target resources.

Then create run.yaml for local execution:

schema: space.run
version: "1"
image: _build/spaceos
partitions:
payload:
memory: 512
apids: [0x010, 0x01F]
send_to: [ground]
services:
- name: my-app
isolation: runc
cpus: [0]
relay:
from: payload
to: [ground]
ground:
port: 8080
socket: /tmp/spaceos/ground.sock

run.yaml defines runtime memory, APID access, relay topology, ground endpoint, and service isolation. For Linux services, use isolation: runc.

Run locally

Build and run the composition. The first build creates and selects a development signing identity automatically and prints its fingerprint:

Terminal window
space build . -t my-app:dev
space run my-app:dev --runtime run.yaml

For a runner-supervised local deployment, give the workload a name. The engine starts on first use:

Terminal window
space run --name my-app my-app:dev --runtime run.yaml
space logs my-app
space stop my-app

The runner tracks lifecycle, logs, stats, and status for named workloads.

Deploy to a target

First build a release composition. The --release flag requires a non-development signing profile:

Terminal window
space build . -t ghcr.io/<your-org>/my-app:release --release --signing-profile release

Connect the target once, with its content-addressed profile and its uplink transport. --endpoint and --cla-address are the node’s delay-tolerant network name and the address that reaches it. A bench board on your network claims --always-reachable; a node reached over real passes names its orbit with --tle, a two-line element set, and --station:

Terminal window
space target connect sat-42 --profile cm5-dev \
--signing-key ./keys/sat-42.pem \
--endpoint ipn:7.1 --cla-address sat-42.local:4556 --always-reachable

Inspect the deployment plan before enqueueing it:

Terminal window
space deploy ghcr.io/<your-org>/my-app:release --target sat-42 --plan
space deploy ghcr.io/<your-org>/my-app:release --target sat-42

space deploy assembles the per-board release for the named target. Local space run executions exercise the runtime path; deployments bind the composition to a registered board and its admission policy.

Unikernel migration criteria

Stay on Linux services when you need a normal Linux userland, fast porting, or existing container images. Move to a unikernel when the mission requires a smaller trusted computing base (less code that has to be correct for the system to be secure), faster cold starts, or stronger service isolation.