How it works
- Each Orka VM runs one Azure Pipelines agent, registered in an agent pool in your Azure DevOps organization or collection.
- The agent connects out to Azure DevOps over HTTPS and asks for jobs. Azure DevOps never connects into your network, so you don’t open any inbound ports.
- Jobs reach the agents through the pool name in your YAML. Your pipelines, logs, and the Azure DevOps UI don’t change.
- Agents can stay up across jobs, or take one job each and be deleted afterward. Orka doesn’t watch your Azure DevOps queue, so the single-job model needs your own automation to deploy and delete VMs. See Choose persistent or single-job agents.
Prerequisites
- An Orka 4.0 cluster with Apple silicon nodes, and the
orkaCLI. On Orka 3.x, useorka3in place oforka. - An agent pool in Azure DevOps. See Microsoft’s Create and manage agent pools.
- A personal access token (PAT) with the Agent Pools (read, manage) scope. Azure DevOps uses the PAT only to register an agent, not afterward, so a short-lived PAT works. See Microsoft’s Register an agent using a personal access token.
- An OCI registry for your agent image, with registry credentials in your Orka namespace. See Manage registry credentials.
Set up Orka for Azure DevOps
1
Build the agent image
Deploy a VM from a base image, then connect to it over SSH. See VM access ports for the SSH port.To register agents with User Data later, the image needs the Orka 4.0 VM Tools. MacStadium’s After the push finishes, delete the build VM with
latest tags have them; not every version tag does yet.In the VM, install Xcode and anything else your builds need. Then download the macOS ARM64 agent from the agent releases page and extract it, following Microsoft’s Download and configure the agent steps. Use a path without spaces, such as ~/myagent.Push the VM to your registry, and check the push until it finishes:orka vm delete azdo-image-build.2
Create a VM config
Create a VM config from the agent image, so every agent VM deploys with the same settings:See VM configuration templates for CPU, memory, and placement options.
3
Deploy and register agents
Deploy a VM for each agent you want. On each VM, register the agent as the VM’s user, then start it as a service. The commands use the VM’s Orka name as the agent name, read from the VM metadata, and prompt for the PAT so it doesn’t end up in your shell history:For Azure DevOps Server, use your collection URL for
--generate-name gives each VM a unique name:--url. For every config.sh option, see Microsoft’s Unattended config.To register at first boot instead of over SSH, run config.sh from a User Data script. User Data runs as root, and config.sh refuses to run as root by default, so run it as the VM’s user, for example with sudo -u. Start the agent with run.sh in the background (for example, sudo -u <USER> nohup ./run.sh &) instead of svc.sh: the svc.sh service is a LaunchAgent, and at first boot there may be no logged-in session for it to start in. At first boot, the metadata service can take a moment to answer, so retry the curl for the VM’s name until it returns one, for example until AGENT_NAME=$(curl -sf http://169.254.169.254/metadata/orka_vm_name) && [ -n "$AGENT_NAME" ]; do sleep 2; done.Anyone with Kubernetes read access to the VM’s pod or VirtualMachineInstance can read the script, so use a short-lived PAT or have the script fetch it from your secret store. Don’t print the PAT or use set -x: the script’s output goes to /var/log/orka/userdata.log in the VM. See Keep credentials safe.4
Target the pool from your pipeline
Point your macOS jobs at the pool:The rest of your pipeline stays the same.
Choose persistent or single-job agents
Persistent agents run as a service and take job after job until you delete the VM. Use them for pipelines that run often and benefit from warm caches. Clean up between jobs in your pipeline, for example withworkspace: clean: all, because each job starts where the last one left off.
The svc.sh service is a launchd LaunchAgent, which starts only after the VM’s user logs in. If an agent goes offline after its VM restarts, set up automatic login, as Microsoft describes in Automatic login and lock.
Single-job agents take one job and exit, so every job starts on a clean VM. Start the agent with ./run.sh --once instead of svc.sh, then delete the VM after the job and deploy a new one. Orka doesn’t do this for you: you need your own automation, using the orka CLI or the Orka API, to keep enough fresh agent VMs registered. Talk to MacStadium if you want help designing it.
Plan capacity
Two limits decide how many jobs run at once:- Orka capacity: each node runs at most two macOS VMs, so you can run up to two agents per node.
- Azure DevOps parallel jobs: Azure DevOps Services limits how many self-hosted jobs run at once by the parallel jobs on your organization. Extra agents beyond that sit idle. Azure DevOps Server doesn’t charge for self-hosted parallel jobs. See Microsoft’s Configure and pay for parallel jobs.
Network access
Agents only need outbound HTTPS from the VMs to Azure DevOps. Microsoft lists the domains to allow in the self-hosted macOS agent FAQ. If your cluster has VM internet isolation turned on, VMs can’t reach Azure DevOps. See VM internet isolation. To build images and deploy VMs, the machine where you run theorka CLI or your automation needs a network path to your Orka cluster: a VPN client for testing, or a site-to-site tunnel for production.
Troubleshooting
config.shprintsMust not run with sudo. By default, the agent can’t be configured as root. Runconfig.shas the VM’s user.- Two VMs show up as one agent, or an agent drops offline when another registers. Agent names must be unique in a pool. Give each VM its own
--agentname, for example the VM’s name from the VM metadata, as in Deploy and register agents. - An agent goes offline after its VM restarts. The
svc.shservice starts only after the VM’s user logs in. See Choose persistent or single-job agents. - Jobs stay queued while agents are idle. Check that the YAML names the right pool, that the agents meet the job’s demands, and that you have enough parallel jobs.

