# Images

What a machine boots: an Arrakis image with SSH and the usual tools, or an image of your own, public or private.

## Arrakis images

A machine boots an Arrakis image unless you pick another. Each is an official base with SSH, a login banner and everyday tools added: git, git-lfs, tmux, htop, nvtop, rsync, curl, wget, jq and an editor. Python is on the path in every SSH session.

| Image | What's in it | Docker image |
|---|---|---|
| PyTorch 2.14 (default) | PyTorch 2.14.1, CUDA 13.0, Python 3.12, Ubuntu 24.04 | `goodailabs/arrakis:pytorch-2.14.1-cuda13.0` |
| PyTorch 2.14 with the CUDA toolkit | The same plus nvcc, the CUDA headers and a compiler | `goodailabs/arrakis:pytorch-2.14.1-cuda13.0-devel` |
| CUDA 13.0 toolkit | CUDA 13.0.3, cuDNN 9, nvcc, Python 3.12, Ubuntu 24.04 | `goodailabs/arrakis:cuda-13.0.3-devel` |
| Ubuntu 26.04 | Python 3.14. The GPU driver comes from the machine | `goodailabs/arrakis:ubuntu-26.04` |

CUDA 13.0 is the build `pip install torch` gives, so wheels built for PyTorch fit. It runs on every machine on Arrakis, Blackwell included: each has an NVIDIA driver from the 580 series or newer. The images are public on Docker Hub, so you can pull the same one on your own computer; `goodailabs/arrakis:latest` is the default.

A login shows the machine's GPUs, the image and the free disk:

```text
  6 × NVIDIA RTX A4000, 16 GB each
  PyTorch 2.14.1, CUDA 13.0, Python 3.12.3, Ubuntu 24.04.5 LTS
  32 CPU cores, 125 GB memory, 412 GB free in /workspace
```

Work in `/workspace`. Everything on a machine, `/workspace` included, is deleted when it stops.

## Your own images

Any image works: vLLM, SGLang, NVIDIA NGC containers, or your team's own image, public or private.

- On **Images**, choose **Add an image** and paste it the way `docker pull` takes it, such as `vllm/vllm-openai:v0.11.0`. For a public image you can also pick **Your own image** when you rent.
- Arrakis asks the image's registry first: the image must exist, be pullable and have a linux/amd64 build. A typo or a wrong token is refused before anything is charged.
- Registries: Docker Hub, GitHub (`ghcr.io`), Amazon ECR and ECR Public, Google (Artifact Registry and `gcr.io`), Azure (`azurecr.io`), NVIDIA NGC (`nvcr.io`), Quay, GitLab and Microsoft (`mcr.microsoft.com`), or your own: Harbor, Artifactory, Nexus, a self-hosted GitLab or Quay, any registry at its public DNS name, such as `registry.example.com:5000/team/app:v1`.
- SSH is added to any image at start, so you log in as root the same way. The image needs a shell.
- The first start on a machine downloads the image. Large images take longer: a 12 GB image can take 10 to 20 minutes on a slow network.

### Private images

Tick **It's private: log in to pull it** when you add the image, and give the login `docker login` would take. Arrakis checks the image with it before saving, keeps it encrypted, and uses it only to pull this image when you rent. The password is never shown again.

| Registry | Username | Password or token |
|---|---|---|
| Docker Hub | Your Docker Hub username | A personal access token with read-only access |
| GitHub (`ghcr.io`) | Your GitHub username | A classic token with only `read:packages` |
| Amazon ECR (`<account>.dkr.ecr.<region>.amazonaws.com`) | An access key ID | Its secret access key |
| Google (`<region>-docker.pkg.dev`, `gcr.io`) | `_json_key` | A service account's JSON key with the Artifact Registry Reader role |
| Azure (`<name>.azurecr.io`) | A repository token or service principal | Its password, with pull access only |
| NVIDIA NGC (`nvcr.io`) | `$oauthtoken` | Your NGC API key |
| GitLab (`registry.gitlab.com`) | A deploy token's username | The deploy token, with `read_registry` |
| Quay | A robot account | Its token |
| Your own registry | The username it takes | Its password or token |

- **Amazon ECR**: use an AWS user that can only pull images (the `AmazonEC2ContainerRegistryReadOnly` policy). Each time you rent, Arrakis trades the key for a fresh 12-hour pull login, the one `aws ecr get-login-password` prints, so the machine never sees the key itself.
- **Your own registry**: machines pull straight from it, from wherever they are, so it must answer on the public internet over HTTPS with a certificate from a public authority (such as Let's Encrypt). A registry behind a VPN or an IP allowlist can't be reached; one with a self-signed certificate is refused.
- Use a token that can only read. The machine pulls with it, and the image can stay cached on that machine after your rental ends, so keep secrets out of the image and pass them in when it runs.
- To change a token, choose **Change login** next to the image, or save the same image again with the new one. Removing the image deletes its login everywhere Arrakis kept it.

### When it starts

| Choice | What runs | Use it for |
|---|---|---|
| Wait for me to log in (default) | Nothing. The machine waits for you | Training, notebooks, anything you start over SSH |
| Run the image's command | The image's own entrypoint and command | Servers such as vLLM, TGI or SGLang |
| Run a command | One plain line you give, such as `python -m http.server 8000` | A job that starts by itself |

If the command exits, the machine can't be reached any more. When in doubt, choose **Wait for me to log in**.

Reach a server on the machine through SSH:

```sh
ssh -L 8000:localhost:8000 root@<host> -p <port>
curl localhost:8000/v1/models
```

### Environment variables

Add `KEY=value` pairs to an image, one per line. They're stored with the image, so keep secrets out of them and set those over SSH instead, for example `export HF_TOKEN=...` in your session.

## From the CLI, API and agents

```sh
arrakis images list
arrakis images add vllm/vllm-openai:v0.11.0 --start image
arrakis instances create --node-id <node> --image vllm/vllm-openai:v0.11.0 --start image --termination-hours 2
```

A private image takes its login, with the token on stdin the way `docker login` takes it:

```sh
echo "$GITHUB_TOKEN" | arrakis images add ghcr.io/acme/trainer:v3 --username acme-bot --password-stdin
arrakis instances create --node-id <node> --template-id <image id> --termination-hours 2
```

```sh
curl -X POST $ARRAKIS_URL/v1/instances -H "Authorization: Bearer $ARRAKIS_TOKEN" -H "Content-Type: application/json" \
  -d '{"node_id": "<node>", "name": "vllm", "termination_hours": 2, "ssh_public_key": "ssh-ed25519 AAAA...",
       "image": "vllm/vllm-openai:v0.11.0", "start": "image"}'
```

- `GET /v1/templates` lists the Arrakis images and yours; `POST /v1/templates` saves one (`image`, `start`, `command`, `environment`, and for a private image `registry_username` and `registry_password`). The password is write-only: answers show `private` and `registry_username`. `PATCH /v1/templates/{id}` with both replaces the login.
- `POST /v1/instances` boots `template_id`, or any public `image` with a `start`.
- Over MCP, `list_images` lists them, private ones marked, and `rent_gpu` takes `template_id` or `image`.

More: [all docs](/docs.md) · [OpenAPI](/openapi.json) · [llms.txt](/llms.txt)
