|
| 1 | +# Build a Custom Image |
| 2 | + |
| 3 | +The default Slicer images ship with a minimal Ubuntu or Rocky Linux installation. If your sandboxes need specific packages - compilers, runtimes, libraries - installing them via userdata on every boot wastes time. A derived image bakes those dependencies in, so VMs start ready to work. |
| 4 | + |
| 5 | +This page covers building a derived image locally. For publishing via CI, see [Publish your own images](/platform/publish-images/). For the full reference on image building, see [Build a custom root filesystem](/tasks/custom-image/). |
| 6 | + |
| 7 | +## How it works |
| 8 | + |
| 9 | +Slicer images are OCI images built with a Dockerfile. You write a `FROM` line pointing at a base Slicer image, add your `RUN` and `COPY` steps, then push the result to a container registry. Slicer pulls the image at startup and uses it for every VM in the host group. |
| 10 | + |
| 11 | +The base images are listed in the [images reference](/reference/images/). For most x86_64 workloads: |
| 12 | + |
| 13 | +```Dockerfile |
| 14 | +FROM ghcr.io/openfaasltd/slicer-systemd:6.1.90-x86_64-latest |
| 15 | +``` |
| 16 | + |
| 17 | +For arm64: |
| 18 | + |
| 19 | +```Dockerfile |
| 20 | +FROM ghcr.io/openfaasltd/slicer-systemd-arm64:6.1.90-aarch64-latest |
| 21 | +``` |
| 22 | + |
| 23 | +## Example: Python sandbox |
| 24 | + |
| 25 | +A sandbox image with Python 3, pip, and common data libraries pre-installed: |
| 26 | + |
| 27 | +```Dockerfile |
| 28 | +FROM ghcr.io/openfaasltd/slicer-systemd:6.1.90-x86_64-latest |
| 29 | + |
| 30 | +RUN apt-get update -qy \ |
| 31 | + && apt-get install -qy \ |
| 32 | + python3 \ |
| 33 | + python3-pip \ |
| 34 | + python3-venv \ |
| 35 | + && apt-get clean |
| 36 | +``` |
| 37 | + |
| 38 | +Build and push: |
| 39 | + |
| 40 | +```bash |
| 41 | +docker build -t ghcr.io/your-org/slicer-python:6.1.90-x86_64 . |
| 42 | +docker push ghcr.io/your-org/slicer-python:6.1.90-x86_64 |
| 43 | +``` |
| 44 | + |
| 45 | +Then reference it in your Slicer YAML: |
| 46 | + |
| 47 | +```yaml |
| 48 | +config: |
| 49 | + host_groups: |
| 50 | + - name: sandbox |
| 51 | + count: 0 |
| 52 | + # ... |
| 53 | + image: "ghcr.io/your-org/slicer-python:6.1.90-x86_64" |
| 54 | +``` |
| 55 | +
|
| 56 | +## Things to know about Dockerfile builds |
| 57 | +
|
| 58 | +Slicer images run systemd as PID 1. During the Docker build, systemd is not running, so: |
| 59 | +
|
| 60 | +* Use `systemctl enable SERVICE` to configure a service to start on boot. Do not use `--now` |
| 61 | +* Avoid commands that need a running kernel or network stack |
| 62 | +* Do not change the `CMD` or `ENTRYPOINT`. Slicer manages the boot process |
| 63 | + |
| 64 | +For anything that cannot run inside a Dockerfile (e.g. commands that need networking or a running init system), use [userdata](/tasks/userdata/) to run the steps on first boot, or add a one-shot systemd unit. |
| 65 | + |
| 66 | +See [Build a custom root filesystem](/tasks/custom-image/) for more detail. |
| 67 | + |
| 68 | +## Watch the architecture |
| 69 | + |
| 70 | +If you are building on a Mac with Apple Silicon, Docker defaults to arm64 images. A Slicer host running on x86_64 cannot boot an arm64 root filesystem, and the failure mode is not obvious. The VM may hang or kernel panic on boot. |
| 71 | + |
| 72 | +Options: |
| 73 | + |
| 74 | +* Use `docker buildx build --platform linux/amd64` to cross-compile locally. This works but is slower due to QEMU emulation inside Docker Desktop. |
| 75 | +* Build on a matching architecture: an x86_64 Linux machine, a CI runner, or a Slicer VM itself. |
| 76 | + |
| 77 | +If all your Slicer hosts are arm64 (e.g. Raspberry Pi, Ampere), the reverse applies - build for `linux/arm64`. |
| 78 | + |
| 79 | +Slicer images are not multi-arch. Each architecture needs its own image built natively on matching hardware. If you need to automate this, see [Publish your own images](/platform/publish-images/). |
| 80 | + |
| 81 | +!!! note "Private registries" |
| 82 | + GHCR packages default to private. Either make the package public in GitHub's package settings, or configure `insecure_registry: true` in your Slicer YAML if using a private registry without TLS. |
| 83 | + |
| 84 | +## Test the image |
| 85 | + |
| 86 | +After pushing, restart Slicer with the new image reference and create a sandbox: |
| 87 | + |
| 88 | +```bash |
| 89 | +slicer new sandbox \ |
| 90 | + --count=0 \ |
| 91 | + > sandbox.yaml |
| 92 | +``` |
| 93 | + |
| 94 | +Edit `sandbox.yaml` and set the `image:` field to your custom image, then start Slicer: |
| 95 | + |
| 96 | +```bash |
| 97 | +sudo slicer up ./sandbox.yaml |
| 98 | +``` |
| 99 | + |
| 100 | +Create a VM and verify the packages are present: |
| 101 | + |
| 102 | +```bash |
| 103 | +export TOKEN=$(sudo cat /var/lib/slicer/auth/token) |
| 104 | +
|
| 105 | +curl -sf -H "Authorization: Bearer $TOKEN" \ |
| 106 | + -H "Content-Type: application/json" \ |
| 107 | + -X POST http://127.0.0.1:8080/hostgroup/sandbox/nodes -d '{}' |
| 108 | +
|
| 109 | +# Wait for agent, then check python is installed |
| 110 | +curl -sf -H "Authorization: Bearer $TOKEN" \ |
| 111 | + -X POST \ |
| 112 | + "http://127.0.0.1:8080/vm/sandbox-1/exec?cmd=python3&args=--version&stdout=true" |
| 113 | +``` |
| 114 | + |
| 115 | +## Wrapping up |
| 116 | + |
| 117 | +Derived images let you trade a one-time build step for faster, more predictable sandbox boot times. Bake in everything your workload needs, publish it to GHCR, and let Slicer pull it on startup. |
| 118 | + |
| 119 | +See also: |
| 120 | + |
| 121 | +* [Build a custom root filesystem](/tasks/custom-image/) - full reference for Dockerfile-based image builds |
| 122 | +* [Images for microVMs](/reference/images/) - base image tags and availability |
| 123 | +* [Userdata](/tasks/userdata/) - run scripts on first boot for anything that cannot be baked into the image |
| 124 | +* [Storage backends](/storage/overview/) - ZFS and devmapper for near-instant boot from snapshots |
0 commit comments