Upgrading to 4.0.0 requires Orka 3.6. If your cluster runs an earlier version, upgrade to the latest Orka 3.6 release first. On MacStadium-hosted clusters, Orka 4.0.0 hosts run macOS 26.6.2 on hardware that supports it, and the upgrade includes the host macOS upgrade for any hosts on macOS 15. See Orka compatibility matrix for macOS and hardware. Clusters with Intel worker nodes can’t upgrade to 4.0: the upgrade checks for Intel nodes and stops before making any changes. Contact MacStadium support to schedule your upgrade.Until now, getting a VM from a golden image to “ready for this specific job” meant one of two things: bake the enrollment or registration script into the image (and maintain a separate image per purpose), or SSH in after deployment and run it yourself. User Data removes that step. You pass a shell script to Through the REST API, pass the base64-encoded script in the new The endpoint is reachable from the paired VM at the address shown by Manage role subjects with
Admin-only.The new CLI renamed to
The CLI binary is now
Release summary
Orka 4.0.0 is the first Apple silicon-only release of Orka. The CLI is renamed fromorka3 to orka, so update any scripts and pipelines that call it. It introduces VM User Data, so you can hand a VM a bootstrap script at deploy time and keep your golden images unmodified, and makes Android emulators generally available, with new emulator configurations that let you define a platform, system image, and device profile once and deploy from it everywhere. It also removes the CLI, API, and Web UI surface that only ever worked on Intel, deprecates NFS-hosted images in favor of OCI images, adds orka rbac for managing role subjects, and hardens the control plane with disruption budgets and resource reservations for Orka’s own components.If you ran the 3.7.0-alpha, everything from that preview is included here, along with the changes since.New features
VM User Data
Apple silicon only. Requires the Orka 4.0 orka-vm-tools in the VM image, which ship with this release.
orka vm deploy, and it runs inside the VM on first boot, against the same unmodified image every other VM uses.userdata field of the deploy request.How it behaves:- The script runs as root, in the background, and never delays the VM becoming available. The VM is reachable while the script runs.
- It runs once per VM. Completion is recorded after the script finishes, whether it succeeded or failed, so a failed run does not retry on the next boot. A VM that reboots or stops mid-script has not completed, and re-runs the script on its next boot, so write scripts that are safe to re-run.
- A VM deployed from an image that was saved or pushed after its own User Data ran still runs its own script. The run-once record is tied to the deployment, not the image.
- There is no timeout by default. Set
ORKA_USERDATA_TIMEOUTinside the image if you want one. - Output is written to
/var/log/orka/userdata.loginside the VM. - The base64-encoded script can be up to 64 KiB. For anything larger, have a small User Data script download the real payload.
orka vm list -o wide, which adds a USERDATA-PHASE column (pending, success, failed, skipped, or timeout). The same value is returned as userdataPhase in API responses, so automation that needs a “ready to use” signal can wait for a terminal phase. The phase is reported by the guest, so treat it as a progress signal rather than proof that the work was done, and don’t use it as a security control.Orka never returns the script in API responses. It is still visible to anyone with Kubernetes-level read access to the VM’s VirtualMachineInstance resource or pod, so if other users or service accounts can read pods in your namespace, prefer short-lived credentials (for example, MDM enrollment invitations) or have the script pull secrets from your own secret store.For script guidance, see Bootstrap VMs with User Data.Android emulators are generally available
Android emulator support, introduced as early access in 3.7.0-alpha, is generally available in Orka 4.0.0. Orka runs the emulator on the same Apple silicon host as the VM it’s paired with, connected over an ADB relay bridge, so from inside the VM youadb connect exactly as you would in any other Android CI setup. That means iOS and Android tests can share a single job without standing up separate Android infrastructure.Deploy, list, and delete emulators with orka emulator or the /api/v1/namespaces/{namespace}/emulators/android API endpoints:--platform takes the name the Android SDK uses, so platforms whose name carries a minor version work too, for example android-37.0.Emulators now follow their paired VM’s lifecycle. If the VM stops or fails, the emulator fails with reason PairedVMStopped and its ports are released for the next emulator on that node. Deploying an emulator against a VM that has already stopped fails right away with that reason, instead of retrying.For setup, connection steps, and limitations, see Android emulators on Orka.Android emulator gRPC endpoint
Pass--grpc to start the emulator’s gRPC endpoint alongside ADB, so a gRPC client can drive the emulator or stream its display, for example to mirror it in your own UI:orka emulator list, on the port in the GRPC-PORT column (ADB uses RELAY-PORT). Like the ADB endpoint, it speaks plaintext gRPC over HTTP/2 with no TLS and no authentication, and only VMs on the same host can reach it. To reach it from elsewhere, forward the port through the paired VM.Emulator configurations can turn gRPC on with orka emulator-config create ... --grpc, and a single deploy can decline it with --grpc=false. Through the API, set grpc in the deploy request or in an emulator configuration; deploy responses include grpcRelayPort, and configuration responses include grpc when the configuration sets it.Android emulator configurations
Emulator configurations do for emulators what VM configs do for VMs: define the Android platform, system image type, and (optionally) device profile once, then deploy from it by name instead of repeating the same three flags in every pipeline.- Configurations are created in the
orka-defaultnamespace and are available to every user and service account with access to it. - Any of
--platform,--image-type, and--device-profileoverride the configuration at deploy time. Pass an empty--device-profile ""to use theavdmanagerdefault instead of the configuration’s profile. - Settings are copied into the emulator when it’s deployed, so editing or deleting a configuration never affects emulators already running.
- Manage configurations with
orka emulator-config create,list, anddelete(aliasorka emc), or the/api/v1/namespaces/{namespace}/emulatorconfigs/androidAPI endpoints.
Manage role subjects with orka rbac
Admin-only.The new orka rbac command group lets administrators grant and revoke Orka roles for users and service accounts directly from the CLI:--role dev modifies the orka-dev role binding in a single namespace. --role admin is cluster-wide: subjects are added to every binding that already grants the admin role. Admin grants only apply to bindings that exist when you run the command, so after you create a new namespace, re-run add-subject for any admins who need access to it.The same operations are available through the API at /api/v1/rbac/{role}/subjects, /subjects/add, and /subjects/remove.orka rolebinding and the /api/v1/namespaces/{namespace}/rolebindings/orka-dev/subjects routes are deprecated in favor of orka rbac ... --role dev and the /api/v1/rbac routes. They still work in 4.0.0 and behave the same as before.Improvements
Control plane resilience
Orka’s own control-plane components are now better protected from disruption, so a busy or recovering cluster keeps its management plane up:- PodDisruptionBudgets protect
orka-webhooksand the HA control-plane components during node drains and maintenance. Orka creates theorka-webhooksbudget on every cluster, so don’t add one of your own: two budgets selecting the same pods make Kubernetes refuse to evict them, and a node drain during a Kubernetes upgrade hangs. See Kubernetes upgrade guide. - Kubelet resources are reserved on control-plane nodes.
- MacStadium-hosted clusters only: Orka components also run under dedicated PriorityClass tiers, with kube-vip set to
system-node-critical, and get per-component resource requests and limits. On AWS and on-prem clusters, Orka creates no priority classes, because they are cluster-wide and could preempt your own workloads, and leaves resource requests and limits empty so you can size them for your environment.
Observability
- The operator reports a pending-VM queue-depth metric and adds a
vm_namespacelabel to its metrics, giving you a leading indicator of VM deployment backlog before deploy times start to climb. - The deploy-duration histograms now use exponential buckets, so observations land in finite buckets and percentiles are meaningful. Bucket series and VM lifetime metrics are now included in the Prometheus allowlist.
orka-webhooksnow exposes a metrics endpoint that Prometheus scrapes, and previously missing control-plane metrics have been added to the scrape allowlists.
Node scheduling
Earlier releases capped every pod on an Apple silicon node (VMs, emulators, and image-cache jobs) under one shared quota of4. A node running two VMs, each with a paired emulator, was already full, so an image-cache job targeting that node could never schedule. Orka 4.0.0 replaces the shared cap with separate limits:- Image-cache and push jobs have their own per-node budget, default
2, tunable with theosx_node_orka_quota_jobAnsible variable. Jobs no longer compete with VMs or emulators for a slot. - The node pod quota is raised to
110, the Kubernetes default. It no longer limits how many VMs, emulators, and jobs run together, since VMs and jobs each have their own limit. - Emulators aren’t capped. They’re counted per node, so
kubectl describe nodeshows how many are running. - Emulators are placed by the Kubernetes scheduler on their paired VM’s node. If the scheduler can’t place one, for example because that node is cordoned, the emulator stays
Pendingwith the scheduler’s reason in its error message. After 5 minutes it fails withEmulatorUnschedulable.
osx_node_orka_quota_pod on 3.6 to make room for emulators or cache jobs, you no longer need that override.Deprecations
NFS-hosted images are deprecated. Use OCI images instead, created withorka vm push. The deprecated commands and routes still work in 4.0.0. No removal release has been set. To move existing images, see Migrate NFS Orka images to OCI format with Harbor.- CLI:
orka image(list,copy,delete,set-description),orka remote-image(list,pull),orka vm save, andorka vm commitprint a deprecation warning to stderr and are marked(Deprecated)in their help. - API: the
imagesandremoteimagesroutes andPOST /vms/{vm}/saveand/vms/{vm}/commitreturn aDeprecation: trueheader and aWarningheader naming the OCI replacement, and are marked deprecated in the API reference. orka imagecache, thecache/imagesroutes, and VM deploy aren’t affected, because they serve OCI images too.
Breaking changes
CLI renamed to orka
The CLI binary is now orka, replacing orka3. MacStadium doesn’t ship an orka3 alias.- Update every script, CI job, and integration that calls
orka3to callorka. Commands, flags, and output are otherwise unchanged, apart from the Intel removals listed below. - Download the 4.0 CLI from Orka tools, CLI downloads, and CI/CD plugins. On macOS, installing the 4.0 package leaves the 3.x
orka3binary in place, so you can keep both installed. - On macOS with Homebrew, install the 4.0 CLI with
brew install --cask orka. Theorka3cask stays on 3.x, andbrew upgradedoesn’t move you fromorka3toorka. - The 3.x CLI stays
orka3. If you manage clusters on both Orka 3.6 and 4.0, useorka3for 3.6 clusters andorkafor 4.0 clusters. orkaandorka3read the same config file and the sameorkakubeconfig context. Switching between a 3.6 cluster and a 4.0 cluster still means runningconfig set --api-urland logging in again, whichever CLI you run.
orka3 name at the 4.0 CLI to keep existing scripts working while you migrate them:- macOS and Linux:
sudo ln -sf "$(command -v orka)" /usr/local/bin/orka3 - Windows: copy
orka.exetoorka3.exein the same folder.
orka3, so don’t do it if you still manage Orka 3.6 clusters. If you installed orka3 with Homebrew, uninstall the orka3 cask first, because Homebrew still treats /usr/local/bin/orka3 as its own. On macOS and Linux, the symlink survives later 4.x CLI upgrades. On Windows, copy the file again after each CLI upgrade.When you run the 4.0 CLI as orka3, it prints a deprecation warning to stderr and then runs normally. Standard output is unchanged, so -o json output still parses. Treat this as a bridge, not a fix: help text and error messages say orka, so update scripts to call orka directly.Intel removals
Orka 4.0.0 also removes the surface that only worked on Intel nodes. Each removal below either drove Intel-only tooling (libvirt, ISO installs, empty Intel disks) or rejected Apple silicon outright, so none of it changes Apple silicon behavior. What it does change is anything that still calls it: a script runningorka3 vm stop, a pipeline posting to the ISO endpoints, or a kubectl apply of an Intel VM config will now fail instead of silently doing nothing.CLI
- Removed commands:
orka3 vm start,vm stop,vm suspend,vm resume,vm revert, andorka3 image generate. - Removed command groups:
orka3 iso(list,copy,delete,set-description) andorka3 remote-iso(list,pull). - Removed flags on
vm deployandvmc create:--iso,--gpu,--disable-net-boost,--legacy-io, and--system-serial. - Removed flags on
vm resize:--userand--password. Resize on Apple silicon works exactly as before. orka vmandorka imagenow reject unknown subcommands with a non-zero exit code. Previously, an unknown subcommand such asorka3 vm bogusprinted help and exited0. Without this change, a script still calling a removed command such asvm stopwould have read it as success.
API
The following endpoints now return404:POST /api/v1/namespaces/{namespace}/vms/{vm}/execPOST /api/v1/namespaces/{namespace}/images(image generate)POST /api/v1/namespaces/{namespace}/upload/imageandGET/HEAD /api/v1/namespaces/{namespace}/images/{image}/download. Apple silicon images move through OCI push and pull.- All
/isos,/remoteisos, andPOST /upload/isoroutes
GET /api/v1/cluster-info no longer returns gpuPassthroughEnabled. GPU passthrough was Intel-only. The other fields are unchanged.VM deploy and VM config create now return 400 if a request sets iso or systemSerial, or turns on gpuPassthrough or legacyIO. Resize returns 400 if the request includes vmUser or vmPassword. Previously these fields were silently ignored on Apple silicon. Values that already describe Apple silicon are still accepted: false, "", or null for the Intel-only fields. netBoost is accepted with any value and ignored, because net boost is always on for Apple silicon. These fields no longer appear in VM or VM config responses.Kubernetes resources
The same rules now apply when you create VMs or VM configs directly withkubectl. The operator rejects a new VirtualMachineInstance or VirtualMachineConfig that references an amd64 (Intel) image or sets any Intel-only field. Existing resources created on 3.6 can still be updated and deleted, so an upgrade doesn’t leave you with objects you can’t clean up. The Intel-only fields remain in the CRDs, marked deprecated, and will be removed in a future release.Web UI
- The VM Start, Stop, Suspend, Resume, and Revert actions have been removed. To restart a stopped VM, redeploy it.
- The Generate Image action and the ISOs page have been removed.
- The GPU, net boost, and ISO fields and columns have been removed from VM and VM config views.
- The Enable VNC checkbox has been removed from the Deploy VM and Create VM Config dialogs. It only applied to Intel configs. VM configs created from the Web UI keep VNC enabled, and deploys use the VM config’s own VNC setting.
Bug fixes
- Fixed: After a node outage, the disk sweeper could delete the disk of a VM whose pod still claimed it. VM disks are now kept for as long as a pod references them.
- Fixed: Resizing a VM could hang for up to 5 minutes and fail with a bare
DeadlineExceedederror, because the repartition request was sent before the guest tools were ready to receive it. Resize now waits for the guest tools and bounds each wait with a clear error. - Fixed: A VM deployed moments after creating its VM config could be rejected with an admission error because the config wasn’t visible to the webhook yet.
- Fixed:
orka imagecache remove --alland--tagsreturned404for nodes that didn’t have the image cached. These nodes are now skipped: the request returns207 Multi-Statuswith a202for each node. A node you name with--nodesthat doesn’t have the image cached still returns404. - Fixed: Orphaned
FailedandRemoveFailedcache entries lingered inorka imagecache infooutput. They’re now cleaned up, and removing an image with no cache record reports that clearly. - Fixed: When a pull or import was short on space, cache eviction freed the full required size rather than the shortfall, so it evicted several cached images instead of one. An operation the whole cache couldn’t make room for deleted every cached image and was rejected anyway. Eviction now frees only what’s needed and rejects up front when evicting can’t help.
- Fixed:
orka imagecache removecould stayRemoveFailedon every retry when the tag had already been deleted by an earlier, timed-out call. It now reports not found and clears the record. - Fixed: Deploying a VM to a node without enough disk space reported
Unable to deploy the VM as the underlying VM process has crashed.The VM now fails withNot enough disk space on node <NODE> to deploy the VM, followed by the space the VM needs and the space available, and the pod records aFailedCreateevent with the same error. - Fixed: Concurrent VM deployments and image pulls on the same node each checked free space without counting what the others were still writing, so a node could run out of disk mid-pull. Each operation now reserves the space it still needs until it finishes.
- Fixed: Cache eviction could delete the image a VM was being created from, so the deployment failed with
The file "disk.img" couldn't be opened. Eviction now skips images that an in-progress deployment is using. - Fixed: If a node ran out of disk space while importing an image, for example during two imports at once, Orka could keep the incomplete image instead of failing the import, and never download it again. VMs deployed from it on that node failed with
Unable to deploy the VM as the underlying VM process has crashed. Orka now fails the import, and re-imports a cached image that’s shorter than its full size. - Fixed: After a node evicted cached images to make room, the evicted images could still show as
Readyinorka imagecacheoutput until the next cache change. The node’s image list now refreshes after every deployment and after failed cache adds and removes. - Fixed: Eviction could empty the cache and still reject the operation, because macOS reports freed disk space a few seconds late. Orka now counts the space eviction reports as freed.
- Fixed: Removing a large cached image could fail with
DeadlineExceededeven though the removal completed on the node. Image removals now wait for the node to finish. - Fixed: Creating a service account token could return an unhelpful error instead of a timeout error when the token wasn’t ready in time.
- Fixed: Tagging, untagging, or changing the namespace of a node could fail with
409 Conflictif the operator updated the node at the same moment. These requests now retry against the latest node state. - Fixed: With bridged networking, a newly deployed VM could report the previous VM’s IP address, leaving it intermittently unreachable over SSH at the IP Orka returned.
- Fixed: On macOS 26.6.2 hosts, if macOS restarted its window server, the node could lose its GUI session. Running VMs kept running, but no new VMs could start until someone logged in to the node manually. Orka now restores the session before starting a VM.
- Fixed: In 3.7.0-alpha, when an emulator’s pod was removed, Orka could recreate it before the old pod finished terminating. The emulator could then be recreated more than once, or the replacement could fail to start on a port the old emulator still held.
- Fixed: After you commit changes to an existing image under the same name and tag,
orka imagecache addcould report the image as already cached on nodes where it had been cached automatically by a VM deployment, and skip re-caching it.imagecache addnow re-caches the updated image on those nodes.
Security
- Updated
golang.org/x/net(CVE-2026-78669), the Web UI’s npm dependencies, and the TLS certificate service’sproxy-addrandaxiosdependencies to address HIGH and CRITICAL vulnerabilities.
Known issues
Google Play Store system images don’t accept ADB commands. An emulator deployed with--image-type google_apis_playstore reaches Running and returns a relay port, but every adb command from the paired VM fails with device unauthorized. Play Store images enable an ADB security feature that requires a trusted public key to be authorized on the device, and because Orka emulators run headless there’s no way to approve it.Use google_apis instead. It includes Google Play services, so Firebase Cloud Messaging, Maps, Sign-In, Location and ML Kit all work. It doesn’t include the Play Store app or Play certification, so you can’t test Play Store install and update flows, Play Billing or in-app purchases, or install referrer, and Play Integrity checks behave differently.Get this release. If MacStadium hosts your cluster, request the upgrade with a support ticket, and MacStadium schedules it with you. If you run Orka Anywhere, see Upgrading Orka Anywhere or Upgrading Orka on AWS. After your cluster is on 4.0.0, install the 4.0.0
orka CLI and Orka VM Tools 4.0.0 from Orka tools, CLI downloads, and CI/CD plugins. To check which version your cluster runs, use orka version.
