GitLab Runner autoscaling on Azure and Google Cloud

Autoscaling GitLab Runners on Azure Virtual Machine Scale Sets in Uniform mode and Google Cloud instance groups, using GitLab's fleeting plugins, with the runner manager kept on a stable VM.

On this page

GitLab Runner autoscaling on Azure and Google Cloud for self-managed CI/CD

Autoscaling GitLab Runner on Azure or Google Cloud is the setup to choose when your self-managed GitLab team runs CI jobs in bursts, such as a merge request wave in the morning or nightly builds, and you want build capacity to grow and shrink without keeping idle virtual machines running. The runner manager is a long-lived GitLab Runner process that polls your GitLab instance for jobs. When work arrives, it asks a cloud integration to start instances, registers them, sends jobs to them and removes them when they go idle. The *fleeting plugin* is the layer that talks to the cloud: it creates and deletes machines in an Azure Virtual Machine Scale Set in Uniform mode or in a Google Cloud instance group. The *autoscaled instances* are the disposable build hosts that run the jobs themselves. GitLab Runner is distributed under the MIT license, and the Runner documentation advises keeping its major and minor versions aligned with your GitLab instance, so plan Runner upgrades alongside your GitLab upgrade stops.

Keep the runner manager on a standard, non-spot VM. A spot or preemptible machine can be reclaimed by the cloud at short notice, and if it is the manager, running jobs lose their coordinator, cached registrations and scaling state mid-pipeline. Spot capacity is better suited to the autoscaled build instances, where a interrupted job can be retried. Confirm the current spot and preemption behavior for your chosen Azure and Google Cloud regions and VM families with each provider, since eviction rules and pricing change over time. Also decide how the manager authenticates to the cloud. Use a managed identity or a workload identity on the manager rather than long-lived keys stored in config.toml, and scope the role to the one scale set or instance group it controls.

Choosing between Azure and Google Cloud for the runner fleet

On Azure, the fleeting plugin scales a Virtual Machine Scale Set in Uniform mode. The runner manager asks for a number of instances, and the scale set creates or removes identical VMs from one model. Confirm which scaling behavior and instance naming the plugin expects, because these details affect how you troubleshoot stuck or orphaned instances.

  • Resources managed: the scale set and its VM instances, each of which takes jobs under the autoscaler's control. Keep the scale set in a resource group that holds nothing else.
  • Identity: a managed identity or service principal with rights only on the scale set and its instances, not on the subscription. Document each role assignment so your access review can trace it.
  • Networking: a virtual network and subnet that let the instances reach GitLab, your package mirrors and the cache store, with outbound paths defined in advance.
  • Images: a versioned custom image built from a hardened base, with the executor and Runner dependencies preinstalled, so you can roll back a bad build.

Confirm in the current plugin documentation which Azure resource types it creates, which role assignments it requires and whether it supports Uniform mode with your Runner version.

Why the runner manager must not run on a spot VM

The runner manager, the gitlab-runner process that polls GitLab for jobs and asks the cloud to create and remove job VMs, should run on a standard on-demand VM, never on a spot or preemptible VM. The manager holds the runner registration, decides when capacity is needed, and cleans up the instances it created. If the cloud reclaims that VM partway through a scaling decision, the job VMs it already requested may keep running with nothing tracking them, and jobs it had accepted may stall until something restarts the manager. Either outcome costs money, delays pipelines, or both.

Spot and preemptible pricing is a sensible cost choice for the job VMs, because a job that is interrupted can usually be retried and the instances are disposable. The manager is different: it is small, always on, and its loss affects the whole fleet, not one job. Keep the manager on a regular VM in Azure or Google Cloud, and apply spot pricing only to the scale set or instance group that the fleeting plugin manages. Confirm in your own environment which instance type, availability zone and restart mechanism (such as a VM with an auto-restart policy or an Azure VM with a recovery plan) you will use for the manager, and document who is alerted when it stops.

Before go-live, test the failure path rather than assuming it. Stop the manager during a burst of queued jobs, then check that the cloud VMs it created are either reclaimed or reattached once it returns, and that queued jobs start without manual cleanup. Also confirm that the job VMs' scale set or instance group limits, which are set in the plugin and runner configuration, are low enough that orphaned capacity cannot grow unnoticed. The GitLab Runner documentation covers the autoscaling settings to review with your platform team.

Configuration options and when each fits

This table compares the autoscaling settings you will set for a GitLab Runner fleet on Azure Virtual Machine Scale Sets or Google Cloud instance groups. Read each row as a decision: the setting, when it fits your workload, and what it costs you in capacity, speed, or operational effort. Confirm exact option names and defaults against the current plugin documentation for your runner version.

SettingWhen it fitsTrade-off to weigh
Scale set or instance group targetAzure Uniform scale sets or Google Cloud managed instance groups, chosen to match the cloud account and networking your platform team already operatesEach target ties the fleet to one cloud's provisioning model, so moving clouds later means rebuilding the autoscaling layer
Idle countTeams with frequent short jobs where waiting for a new VM to boot would slow merge request feedbackIdle VMs are paid for while they wait, so a higher idle count trades job start speed for standing cost
Maximum instancesCaps that protect your subscription or project quotas and limit runaway pipelines from consuming the whole budgetA low cap queues jobs during peaks, while a high cap can let one busy project starve others unless runners are split by tag
Capacity per instanceSmall jobs that can share one VM safely, where packing several jobs per host reduces VM countShared hosts widen the blast radius of a bad job and make noisy-neighbor contention and cache collisions more likely
Spot or preemptible job VMsNon-deployment jobs that can be retried after an interruption, such as unit tests and lintingInterrupted jobs fail or retry, so pipelines for release or deployment paths should stay on standard capacity. Keep the runner manager off spot capacity in all cases
Image and disk choicePinned, hardened images built from your baseline, with disk sized for container layers and build cachesCustom images add a build pipeline to maintain, and oversized disks raise cost on every instance the fleet creates
Cache locationShared object storage for dependency caches when fresh instances must still restore packagesRemote caches add network transfer and latency, and cache scope settings must be reviewed so teams do not read each other's artifacts

Setup sequence for autoscaled runners on Azure or Google Cloud

This sequence takes a team from confirmed versions and a chosen fleeting plugin to a runner manager that scales cloud instances up and down for CI/CD jobs and cleans them up afterward. Each step closes with a check so problems surface before the fleet is trusted with production pipelines.

  1. Confirm versions and the fleeting plugin

    Confirm the GitLab version, the GitLab Runner version and the fleeting plugin for your target cloud, and keep the Runner major and minor versions aligned with GitLab, as the Runner documentation advises. Check whether your cloud has a plugin that GitLab supports or a community plugin, and decide now how you will support it. Output: a written version matrix signed off by the platform owner. Check: the plugin's documented requirements match the Runner version you plan to install, and the Runner documentation for your chosen executor is the version you are reading.

  2. Place the runner manager on a non-spot VM

    Create the VM that will run the GitLab Runner manager on a standard, non-spot instance type, in the same network that can reach your GitLab instance. The manager holds the autoscaling logic and the credentials for the fleet, so an interruption on a spot VM can strand jobs and leave cloud instances running without an owner. Output: a manager VM with a fixed identity and outbound access to GitLab and the cloud APIs. Check: the VM is not marked as spot or preemptible, and it can reach the GitLab URL and the cloud control plane endpoints.

  3. Create the scale set or instance group and identities

    Create the Azure Virtual Machine Scale Set in Uniform orchestration mode, or the Google Cloud managed instance group that the plugin will drive. Create a dedicated identity for the manager with only the roles needed to create, read and delete instances in that group, and attach it to the manager VM rather than storing keys on disk. Output: a scale set or instance group with a known name, region and machine image, plus a least-privilege identity. Check: the manager identity can list and scale the group but cannot modify unrelated resources in the subscription or project.

  4. Configure config.toml with the plugin

    Edit the runner configuration file, config.toml, to select the autoscaling executor, point it at the fleeting plugin, and set the scale set or instance group name, capacity limits, idle policy and the machine image or template reference. Keep the limits conservative for the first run so that cost exposure is bounded while you test. Output: a reviewed config.toml stored under version control with secrets referenced rather than inlined. Check: the runner process starts without configuration errors and the plugin reports that it can reach the scale set or instance group.

  5. Register runners with authentication tokens

    Create the runner in GitLab with the authentication token workflow, which issues tokens beginning with glrt-, rather than using the legacy registration token flow. Attach tags that match the workload you intend to route to this fleet, and restrict the runner to the projects or groups that should use it. Output: a registered runner visible in the GitLab runner list with its tags and scope recorded. Check: the runner shows as online in GitLab and the tags match the pipeline jobs you plan to test.

  6. Run test jobs to verify scale-up

    Trigger a small set of test pipelines that carry the runner tags and observe the fleet respond. Confirm that the manager requests new instances, that the instances register and pick up jobs, and that the jobs complete with the expected logs and artifacts. Output: a short test record with job IDs, instance names and the timing you observed. Check: jobs start on newly created cloud instances, not on the manager, and the instance count rises and falls with the queue.

  7. Verify scale-down and cleanup

    After the test jobs finish, watch the fleet drain. Confirm that idle instances are removed after the configured idle policy, that no orphaned disks, network interfaces or scale set instances remain, and that the manager does not leave instances in a failed state. Review the cloud billing or resource list for anything still running. Output: a clean resource inventory matching the configured limits. Check: the instance count returns to the expected baseline and the cloud resource list shows no leftover resources from the test run.

  8. Document the fleet and set alerts

    Record the final configuration, identities, version matrix, plugin owner and rollback steps in the operations runbook, then add monitoring for the manager process, failed instance creation and unexpected instance counts. Ask your cloud and GitLab administrators to confirm which alerts they already receive. Output: a runbook and alert list approved by the platform team. Check: an on-call engineer can follow the runbook to pause the fleet and identify the manager host without help from the original builders.

Security controls for the manager, job VMs and cloud identities

Autoscaled runners create three trust zones: the manager that holds registration and cloud credentials, the job VMs that run untrusted code, and the cloud identities that let the fleet grow and shrink. The controls below keep those zones apart, and each one should be checked in your own tenant before the fleet takes production jobs.

Least-privilege cloud identity for the plugin

The fleeting plugin needs permission to create, list and delete instances in one scale set or instance group, and little else. Grant a dedicated identity scoped to that resource group or project, not the subscription or project owner role. Ask your team to confirm the exact permissions the plugin version you pin requires, then test scale-out and scale-in against a non-production group before widening any role.

Manager and job VM trust separation

The runner manager holds the registration token and the cloud credentials, so it must not run the jobs it dispatches. Place the manager on its own small VM in a separate subnet, and keep job VMs unable to reach the manager's configuration or the identity that created them. A compromised job should not be able to read the config.toml or call the cloud API.

Secrets in runner configuration

The config.toml file on the manager contains runner tokens and may hold cloud and cache credentials. Restrict its file permissions, prefer managed identities over static keys where the plugin supports them, and rotate any key that was ever written into a job variable or a shared template. Confirm with your security team where these values are stored and who can read them.

Hardened job VM images

Build job VM images from a pinned base, patch them on a schedule, and remove tools that jobs do not need. Every autoscaled instance starts from the image, so an unpatched image multiplies across the fleet. Record the image version in your change records, and rebuild it when the base operating system or the runner version changes.

Network egress from job VMs

Jobs pull packages, images and sources from the internet, which makes job VMs the most exposed part of the fleet. Limit outbound traffic with network security groups or firewall rules to the registries and hosts your pipelines use, and block access to the cloud instance metadata endpoint from job workloads where your design allows it. Review the egress list with the teams that own pipelines.

Protected-branch-only deployment runners

Runners that hold deployment credentials should accept jobs only from protected branches and protected tags. Tag these runners separately, restrict them to the projects that deploy, and keep them off the shared autoscaled pool used for merge request builds. This stops an unreviewed branch from reaching production credentials.

Questions teams ask before autoscaling runners on Azure or Google Cloud

How much does autoscaling GitLab Runner on Azure or Google Cloud cost?

The cloud bill is the main recurring cost, and it depends on how much capacity you keep ready and how long jobs run. The cost components are the always-on runner manager VM, idle headroom in the scale set or instance group, job VMs billed while they run, cache and log storage, and network traffic. DeployOpen's work is quoted as a fixed scope with a one-time build and handover, and ongoing support is available as a retainer. Ask the quote to state the instance types, expected job concurrency, which pipelines move to the new fleet, and whether the manager runs on a standard VM. No cloud price figures are included here, so compare the quote against your own cloud pricing calculator.

How long does a runner autoscaling project usually take?

Duration depends on the number of runner tags and teams, how much network access the runners need, whether approved machine images already exist, and how many pipelines must be proven before cutover. Most engagements are fixed-scope, so the timeline is agreed in writing before work starts. Ask for milestones that separate network and identity setup, the first working scale set or instance group, load testing with real pipelines, and the cutover plan. Also ask which items you must deliver first, because waiting on cloud approvals or image sign-off is a common reason schedules slip.

What does our team need to provide during the engagement?

Your team supplies the cloud access and decisions that only you can make. That includes a subscription or project where the team can create scale sets or instance groups, a managed identity or service account for the runner manager with limited permissions, and network routes from the manager to your GitLab instance. A GitLab administrator must create the runner authentication tokens, and someone must approve the machine images and instance sizes. You also need a named owner for the fleet after handover, plus access to logs and billing data so that cost and failures can be checked.

Can our own platform team build and run this without a partner?

Yes, if your team already runs infrastructure as code on Azure or Google Cloud and has operated GitLab Runner before. The hard parts are the fleeting plugin configuration, testing scale-in and scale-out behavior under load, building images that register cleanly, and reviewing the identity and network design. Ongoing work includes keeping the Runner version aligned with your GitLab version, which the Runner documentation advises, and patching images on a schedule. Assess your team against those tasks honestly before choosing. A partner can build the first version and hand over runbooks, or support you on a retainer.

Is it safe to run the GitLab Runner manager on a spot VM?

No. The runner manager should run on a standard VM, not a spot VM. The manager holds the connection to your GitLab instance and creates and removes job machines. If the platform evicts it during scaling, running jobs can fail, and machines it created may be left running and billed because nothing remains to clean them up. Spot capacity is a reasonable choice for job machines when jobs can be retried and the plugin handles interruptions. Confirm the eviction behavior for your chosen plugin and cloud before you enable spot pricing on any part of the fleet.

How do we move from Docker Machine runners to Docker Autoscaler on these clouds?

Plan the move as a parallel cutover rather than a single switch. Docker Machine is deprecated, so confirm in the GitLab Runner documentation which release removes it before you set a deadline. Map the settings in your config.toml file to the Docker Autoscaler configuration, including capacity limits, idle counts, and cache settings. Then run the new fleet beside the old one, route a small set of jobs to it by runner tag, compare results, and move the remaining tags in stages. Keep the old runners available until the last pipeline has moved and rollback is no longer needed.

Are community fleeting plugins supported for runner autoscaling?

Support status depends on who maintains the plugin you choose. Before you commit, check whether the plugin is maintained by GitLab or by the community, and read what each owner says about testing, releases and compatibility with your Runner version. A community plugin may work well, but your team or your support provider then carries more of the testing and upgrade risk. Ask the quote to name the plugin, its version, who tests it against your GitLab release, and who fixes it if a cloud API change breaks scaling. DeployOpen can support the plugin under a retainer when that is included in the written scope.

Limits to confirm in your environment before you build

Autoscaling runners on Azure and Google Cloud depends on details that vary by cloud account, region and release line. The cards below list what to confirm with the plugin maintainers, the cloud provider and your own tenant before you commit to a design.

Fleeting plugin support for your cloud

Confirm which fleeting plugin version supports the Azure or Google Cloud target you plan to use, and whether that plugin is maintained for the GitLab Runner version you run. Plugins for different clouds are versioned separately, so a plugin that works on one cloud does not prove support on another. Ask for the supported release matrix in writing and record the plugin version in your build notes so upgrades can be tested against it.

Scale set and instance group quotas

Check the vCPU, VM count, public IP and disk quotas for the subscription or project, in the region you intend to use. Autoscaling fails quietly when a quota is reached, so jobs queue without an obvious error. Request quota increases before go-live and note who in your organization approves them, since increases can take time to process.

Supported images and operating systems

Confirm which machine images the plugin and the Docker Autoscaler executor accept on Azure Uniform scale sets and Google Cloud instance groups. Check whether custom images, hardened base images and the required Docker engine version can be referenced in your tenant. Image changes often break cached dependencies and runner registration, so test a new image in a non-production pool first.

Regional and service availability

Verify that the VM series you need, Uniform orchestration mode for scale sets and the instance group features you rely on are available in your chosen region and zones. Some sizes and zone combinations are restricted by region. Confirm this in your own subscription or project, because a region that works for a sandbox account can differ from a regulated production account.

Compatibility with your GitLab version and upgrade stops

Keep the Runner major and minor versions aligned with the GitLab version you run, as the Runner documentation advises. GitLab requires upgrades to pass through required upgrade stops, so plan Runner upgrades alongside each stop rather than after it. Recheck the plugin, Runner and image combination at every stop, and keep the previous combination available for rollback.

Runner manager placement and spot instances

Confirm that the runner manager runs on a standard, non-spot VM in a separate scale set or instance group. Azure Spot and Google Cloud preemptible or Spot capacity can be reclaimed at short notice, which would interrupt the manager and every job it dispatches. Ask your provider to confirm the eviction behavior for the VM series you choose.

Running and upgrading the autoscaling fleet

A Runner fleet on Azure Virtual Machine Scale Sets or Google Cloud instance groups needs the same day-two attention as the rest of your GitLab estate. Start by monitoring two signals together: scale events (how often the fleet adds and removes machines) and the job queue (how long jobs wait for a machine). A growing queue with flat scale events usually points to a capacity limit or a tag mismatch rather than demand. Ask your fleeting plugin and cloud provider for logs on scale-out failures, quota errors and instances that fail to register, and alert on them before developers notice slow pipelines.

Keep the runner manager on the same major and minor version as the GitLab instance it serves. The GitLab Runner documentation advises aligning these versions, so plan a Runner upgrade in the same change window as each GitLab minor upgrade. The cloud-side image is a separate lifecycle: rebuild and roll the Scale Set or instance group image on a fixed schedule so that patched operating system packages, the Docker engine and the Runner helper reach new instances. Confirm with your image pipeline how old instances are drained, since jobs running on a machine being replaced must finish or be retried.

GitLab ships a minor release on the third Thursday of each month and patch releases twice a month, so budget a recurring upgrade slot rather than treating upgrades as occasional projects. The maintenance policy backports bug fixes only to the current stable release, but security fixes go to the previous two monthly releases as well. That gap means a fleet that lags several minor versions may still receive security patches but miss bug fixes that affect autoscaling. Check the GitLab maintenance policy and plan the required upgrade stops before each major change.

How DeployOpen works on this

DeployOpen scopes GitLab Runner autoscaling on Azure and Google Cloud as a written, fixed-scope engagement inside your own cloud accounts. We design the runner manager, fleeting plugin configuration, scaling settings and network path, then hand over documented runners your team can operate.

How we scope

  • Review your GitLab version, job volume, team trust levels and existing runner tags before design starts
  • Agree in writing which Azure or Google Cloud resources, plugins and executors are in scope
  • Define the runner manager placement, which must stay off spot or preemptible VMs
  • Record acceptance criteria, deliverables and timelines in the written scope before work begins

How we build

  • Configure the runner manager with the fleeting plugin for Azure Virtual Machine Scale Sets in Uniform mode or Google Cloud instance groups
  • Set idle capacity, maximum instance counts and scale-in behavior against your measured job pattern
  • Connect the shared cache and runner registration using authentication tokens
  • Test scale-out, scale-in and job failure handling in a non-production project before cutover

How we hand over

  • Deliver infrastructure definitions, runner configuration files and network diagrams in your repositories
  • Document the runner version alignment process so runners stay on versions matched to GitLab
  • Walk your platform team through restore steps, image rebuilds and troubleshooting runbooks
  • Provide a list of open items and the decisions your team owns after handover

How we support

  • Offer ongoing support, upgrades and runner image maintenance as a retainer after handover
  • Scope retainer work in writing, including which GitLab and runner upgrades are covered
  • Re-test autoscaling behavior after GitLab upgrades that change runner or plugin requirements
  • Ask your team to confirm current plugin and cloud API support status before each engagement

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.