Migrate from Docker Machine runners to Docker Autoscaler

A planned move off the deprecated Docker Machine executor, mapping each config.toml setting to Docker Autoscaler or the Instance executor and cutting over one runner tag at a time before GitLab 20.0.

On this page

How to migrate from Docker Machine runners before GitLab 20.0

If your CI fleet runs on Docker Machine, you need to move it before GitLab removes that executor in GitLab 20.0, which the maintenance policy plans for May 2027. The work is a config mapping, a pilot and a tag-based cutover, and its size depends on how many runner pools, cache setups and deploy paths your fleet has. This is an infrastructure change with a fixed deadline, and it leaves pipeline code alone when jobs already select runners by tag, so the .gitlab-ci.yml files should need little or no change. Confirm the exact removal behavior and any deprecation warnings against the current GitLab Runner documentation before you set internal dates.

Start with an inventory of every config.toml on your runner managers. For each [[runners]] block, record the executor, the machine and cloud settings, the idle and maximum counts, the autoscaling schedule, concurrency, tags and any cache configuration. Each Docker Machine setting then maps to one of two targets: the Docker Autoscaler executor, where a fleeting plugin manages a pool of cloud instances, or the Instance executor, where jobs need the whole host. The provisioning model changes, so each setting needs a named equivalent or a documented reason it no longer applies. Your platform team or a partner working under a written scope pays for this analysis and the pilot. The recurring costs are the runner VMs, the manager host and cache storage, and they keep running after the cutover.

Run the new fleet beside the old one. Register new runners with new tags, pilot them on low-risk projects, then move projects tag by tag, leaving deployment jobs for last and keeping them on protected-branch runners. Watch for caches that existed only on the old machines, secrets scoped to the old runner registrations, and runner versions that must match your GitLab version, since the documentation advises keeping Runner major and minor versions aligned with GitLab. Keep the Docker Machine managers online until they have no active jobs, then remove them. Before you request a quote, gather the list of runner pools, pipeline volume per pool, cache usage and each deploy path, because those four items drive most of the effort. Confirm the mapping for each setting in the GitLab Runner documentation.

Which Docker Machine config.toml settings map cleanly to Docker Autoscaler

This table compares common Docker Machine settings in config.toml with their Docker Autoscaler or Instance executor equivalents, and flags the ones whose meaning changes. Read each row as a starting point: confirm every key against the Runner configuration reference for the version you are running, because several settings move into a different section or change how capacity is held.

Docker Machine settingDocker Autoscaler or Instance equivalentMigration note
Machine options (driver, cloud size, image, network)Fleeting plugin settings and the instance template or group configuration in the autoscaler sectionChanges meaning: instances are provisioned by a fleeting plugin for your cloud, so driver-specific options must be rewritten for that plugin. Confirm the plugin's own options.
IdleCountAutoscaler idle count and idle scale settingsChanges meaning: idle capacity is held by the autoscaler against the fleet, not by a Docker Machine pool. Test how many idle instances you actually keep warm and what that costs.
IdleTimeAutoscaler idle time settingClosest match, but confirm units and the point at which idle instances are removed in your version.
MaxBuildsMax use count or equivalent limit on jobs per instanceNot always one-to-one. Confirm whether your version limits builds per instance and how that interacts with instance replacement.
Capacity per machine (limit)Capacity per instance under the autoscaler sectionKeep the value in step with instance size and your job concurrency. Do not assume the Docker Machine value carries over unchanged.
Cache volumes and cache locationDocker volumes plus distributed cache settings, typically in object storageChanges meaning: fresh instances start empty, so a local cache on the old machine does not carry over. Plan a shared cache, such as the S3-compatible cache, before cutover.
Privileged modePrivileged setting in the Docker executor section of the Runner configKeep the same intent, but review it. Privileged jobs on autoscaled instances should run only on runners limited to trusted projects.
Registry mirrors and pull settingsDocker registry and pull policy settings, plus any mirror configured on the instance imageConfirm how the image and registry credentials reach new instances, since they no longer come from a pre-built Docker Machine host.
Runner tags and executor typeSame tags on the new runner, with executor set to Docker Autoscaler or InstanceTags are the basis of a parallel cutover. Register new runners with separate tags first, then move jobs over once they pass.

Documented paths for the runner move

The runner move is a reconfiguration and re-registration exercise, not an import. Each card below names a documented piece the team will work with, so the cutover can be planned against published behavior rather than memory of the old setup. Use them together, in the order the migration plan needs them.

Executor and config.toml reference

The GitLab Runner documentation defines each executor and the config.toml keys that control it. Map every [runners.machine] setting in your current file to its equivalent under [runners.docker.autoscaler] or the Instance executor settings, and mark any key with no clear match as a decision for the team. Confirm each key against the reference for the Runner version you will deploy, since names and defaults change between releases.

Current runner registration flow

New runners are registered with the authentication flow GitLab documents for the release you run, not by reusing old registration commands. Confirm which token type your instance accepts, how automation such as configuration management or the Helm chart supplies that token, and where the token is stored. Check this before the first new runner is registered, because the old workflow can be disabled on a different schedule than your cutover.

Fleeting plugins for instance groups

Docker Autoscaler and the Instance executor provision cloud VMs through fleeting plugins, which manage instance groups on the target cloud. Confirm which plugin your provider supports, what permissions the runner manager needs to create and delete instances, and how the plugin reports capacity. Plan the instance group as its own resource with its own tags, so it can be tested in isolation before any production job reaches it.

Runner tags for job routing

Tags are how a job asks for a particular runner, so they are the mechanism for a parallel cutover. Run the new fleet under a tag set that no production job uses yet, then move jobs in small groups by changing the tags keyword in their pipeline definitions. Keep a written list of which projects and branches moved on which date, so a rollback is a tag change rather than a search through pipelines.

Runner and GitLab version alignment

GitLab's Runner guidance is to keep the Runner major and minor versions aligned with the GitLab instance. Before you choose the Runner version for the new fleet, check it against the GitLab version you run, and record the pairing in the change plan. Because GitLab's major release and upgrade stops also affect Runner support, schedule any GitLab upgrade and Runner upgrade in the same change window rather than leaving them to drift.

Backup of existing runner configuration

Before any change, copy the current runner configuration files, the registered runner list, and the Docker Machine provisioning settings, and store them outside the runner host. Keep the old fleet running until every project has moved and a rollback test has passed, so the backup is a working fallback and not only a record. Note that the backup covers the runner configuration, not the instance backup procedure, which is a separate task.

Sequence from inventory to decommissioning the Docker Machine pool

This sequence moves CI jobs from Docker Machine runners to a Docker Autoscaler pool in controlled stages, so each tag group is proven before the old machines are retired. Each gate has a named check, and the old pool is removed only after the new one has carried real work.

  1. Inventory every runner and its dependencies

    The platform or runner owner records each runner's config.toml section, registered tags, executor and autoscaling settings, cache configuration and the projects or groups that rely on it. Include runners registered at instance, group and project level, since a missing entry is the usual reason a project breaks after cutover. The step is done when every Docker Machine runner has a row in an inventory that lists its tags and dependent projects, and someone has confirmed that list against the GitLab runner pages in the admin area.

  2. Choose the target executor per workload

    For each tag group, decide whether Docker Autoscaler fits the job pattern or whether the workload needs the Instance executor because it requires the whole host, operating system or attached devices. Record the reason next to each group, along with any settings that do not map directly from the old machine options. Confirm the decision with the teams that own the workloads. The step closes when each tag group has a named target executor and a short list of settings that need review.

  3. Build the Docker Autoscaler pool on a pilot tag

    Create the new autoscaling pool on a tag that no production pipeline uses, mapping config.toml settings to the Docker Autoscaler configuration and confirming the fleeting plugin, machine capacity, cache location and cleanup behavior. Run a pilot project that exercises builds, services and the cache. Check job success, cache restores on fresh instances and whether idle instances are removed after the configured idle period. The step is done when the pilot runs repeatably and the team can explain every setting it changed from the original.

  4. Run both pools in parallel by tag group

    Keep the Docker Machine runners active and register the new pool under its own tags. Move one tag group at a time by updating the .gitlab-ci.yml tags for a small set of projects, starting with low-risk workloads. Watch queue times, failed jobs and runner logs for each group before moving the next one. Record cache hit behavior and any jobs that fail on the new executor. The step is done when each moved group has run for a period the team judges sufficient and shows no unexplained failures.

  5. Cut over remaining tags after queue and failure checks

    Move the rest of the tag groups to the Docker Autoscaler pool, verifying at each batch that queue lengths are acceptable, that instances scale up and back down, and that job logs show clean cleanup between jobs. Confirm that protected-branch and deployment jobs still reach the runners they are meant to use. Stop the cutover if failure patterns appear and return the affected group to its previous tags. The step is done when no project still points at the Docker Machine tags and the inventory shows zero active dependencies.

  6. Decommission the old machines and remove credentials

    Once no jobs are routed to the old runners, stop the Docker Machine runner services, remove their registrations from GitLab, and delete the stored credentials, cloud access keys and any machine-level secrets the old pool used. Revoke access that existed only for that pool and update the runner inventory and monitoring. Ask your team to confirm the list of retired credentials against the cloud provider's access records. The step is done when the old runners no longer appear in the GitLab interface, no cloud resources remain for them and the credential removal is recorded.

Choosing Docker Autoscaler or the Instance executor for each pool

Most build and test jobs compile code, run unit tests and package artifacts inside a container image. Docker Autoscaler starts a Docker engine on each cloud VM or instance group member, and the runner creates a container for each job. Jobs share the host kernel, but each job's dependencies stay separate from the next job's.

  • Isolation boundary: Jobs are isolated at the container level and share the host kernel. Confirm that your trust model accepts this boundary for every project placed in the pool.
  • Privileged work: Jobs that build images or request privileged mode widen the boundary. Confirm whether those jobs belong in a separate pool with tighter access.
  • Fresh-VM caching: New VMs start without local state, so dependency restore depends on a shared cache. Confirm the cache location and access rules before cutover.
  • Operating model: Your team maintains the VM image with Docker, the runner manager and the fleeting plugin configuration. Confirm who patches the image and on what schedule.

Check whether these jobs need only a container image, and whether your trust model accepts shared-kernel isolation for them.

What drives the effort and duration of the migration

This table lists the factors that change how much work the move from Docker Machine to Docker Autoscaler takes, the direction each factor pushes the effort, and who typically carries the cost. Read it before requesting a quote, and use the last column to see what to put in writing. No durations or prices are given because the answer depends on your fleet.

DriverEffect on effortWho paysWhat to ask for in a quote
Number of runner pools and config.toml sectionsMore pools mean more sections to map, test and cut over. Effort rises with each pool.Internal staff review the inventory. Partner converts and tests each pool.A per-pool mapping of config.toml sections to Docker Autoscaler or Instance executor settings.
Projects and tags tied to each poolEvery tag a pool serves needs a test job and a cutover step. Shared tags raise coordination work.Internal staff own the project owners and sign-off. Partner builds the tag test matrix.A list of tags and projects per pool, and the cutover order for each.
Privileged modePrivileged containers need a separate security review and may change the executor choice. Effort rises when many jobs depend on it.Internal security team approves the risk. Partner documents the settings.A written review of which pools need privileged mode and the isolation plan for each.
Custom volumes and host-level dependenciesJobs that mount host paths, devices or preinstalled tools must be rebuilt or moved to images. This is often the largest unknown.Internal teams fix their own pipelines. Partner reproduces host dependencies in the new fleet.An inventory of host paths, devices and installed packages, with an owner for each.
Cache designA shared cache in object storage must be configured and tested before cutover. A local cache on fresh instances can slow jobs and surprise teams.Cloud provider bills storage. Internal staff or partner configures the cache.The cache location, retention policy, access rules and a test that a job restores dependencies on a new instance.
Cloud and network placement of the managerThe manager must reach GitLab and the cloud API. Firewall, proxy and private endpoint rules add review cycles and test time.Internal network team approves changes. Cloud provider charges for network resources.A network diagram, the required outbound endpoints and the team that approves firewall changes.
Deployment runners tied to protected branchesDeploy jobs need the same protection rules after the move. Errors here affect production, so validation takes longer.Internal release owners verify. Partner tests protected-branch behavior.A test plan showing each protected branch and environment runs on the expected runner.
Change-control and approval cadenceEach change window adds scheduling time. Fewer, larger windows make the parallel cutover slower to finish.Internal change board and service owners. Partner prepares change records.The change calendar, approval steps and the rollback procedure for each window.
Staffing familiarity with the cloudTeams new to autoscaling groups, instance templates and cloud IAM need more time to learn and verify. Familiar teams move faster.Internal staff carry the learning cost. Partner adds capacity if skills are missing.Named engineers on each side, and whether knowledge transfer and runbooks are included.

What usually goes wrong during a runner executor migration

Most failed runner migrations fail in predictable ways: a rushed cutover, a version mismatch, lost caches, weaker isolation, leftover credentials and jobs that no longer match a runner. Each card below names one risk, the step that prevents it and what to check before moving the next team.

Flag-day cutover strands jobs

Switching every project from Docker Machine to Docker Autoscaler in one change leaves in-flight and queued jobs with no runner that accepts them. Keep both pools registered at once and move one tag group at a time, starting with low-risk projects. Confirm that the old pool still drains its running jobs before you retire any machine. Run both pools in parallel until each tag group has passed a full working week of jobs.

Runner version out of step

A new Docker Autoscaler runner paired with an older or newer GitLab can behave differently from the fleet you tested. The GitLab Runner documentation advises keeping Runner major and minor versions aligned with GitLab, so check the Runner version against your instance before registering the new pool. Record the versions in your change ticket so an auditor or on-call engineer can see what ran each job.

Cache lost on fresh instances

Docker Machine hosts often kept dependency caches that autoscaled Docker Autoscaler instances do not have, so builds that relied on warm caches slow down or fail to restore packages. Decide where the shared cache lives before cutover, typically in object storage, and test a cold job on a brand new instance. Measure job duration on the new pool against the old one so you know whether the cache design holds.

Deployment jobs on weaker isolation

Moving a deployment job from a dedicated, protected Docker Machine pool to a shared autoscaled pool can expose production credentials to untrusted code from other projects. Review which jobs need protected-branch access and keep those jobs on runners that only serve protected refs. Confirm the executor and tag setup isolate privileged jobs before any deployment pipeline points at the new fleet.

Credentials active on the retired pool

Runner tokens and cloud credentials attached to the retired Docker Machine manager stay valid after its machines are deleted, so anyone who still holds them can keep registering or pulling jobs. Once a tag group has moved, revoke the old runner tokens and remove the cloud access keys the manager used. Record each revocation so the migration can be audited later.

Missing tags leave jobs queued

A job tagged for a runner type that no longer exists will sit in the queue without an error that points to the cause. Map every existing tag in your pipelines to the new pool before you disable the old one, and watch queue time per tag during cutover. Alert on jobs waiting longer than your usual baseline so a missing tag shows up within the first day rather than in a release week.

Why a parallel cutover by runner tags avoids a flag day

A parallel cutover by runner tags lets you move one workload group at a time instead of switching every job at once. The tag is the control point. Each job in .gitlab-ci.yml names the tags it needs, and a runner only picks up jobs whose tags it advertises. If the old Docker Machine runners and the new Docker Autoscaler runners both register with the same tag, GitLab can route work to either pool. Moving a group of jobs then becomes a change to which runners carry which tag, not a rewrite of every pipeline on the same day. Before you start, inventory the tags in use across your projects and group them by workload, such as unit tests, container builds, integration tests and deployments, so each group can be cut over and checked separately.

Tags also give you a rollback path that does not depend on the new fleet being healthy. For each group, keep the old Docker Machine runner registered until the new pool has run that group's jobs successfully for a period your team sets. If autoscaled instances fail to provision, cache restores misbehave or a build breaks on the new image, you can reassign the tag to the old pool and the next job goes back to known-good capacity. Confirm before cutover that the old manager can still start, that its config.toml is backed up and that its runner version is still supported. Check the GitLab Runner documentation for the version alignment guidance that applies to your instance, since a runner that lags far behind GitLab creates its own migration problem.

Separate build pools from deploy pools before you move anything. Build jobs are usually high volume and can run on general autoscaled capacity, while deployment jobs need credentials, network access to target environments and a narrower trust boundary. Decide now whether deployments will use protected-branch-only runners, and whether each runner is scoped to an instance, a group or a project. Those choices determine which tags the new pool advertises and who can trigger jobs on it. Changing scope during the cutover multiplies the variables you are testing at once. The design of shared fleets, including trust levels and isolating untrusted projects from privileged jobs, is covered in the sibling topic on designing a shared GitLab runner fleet, and it should be settled before the first tag moves.

Questions teams ask before moving off Docker Machine runners

How much does migrating off Docker Machine runners cost?

The cost depends on the size and shape of your runner fleet, the number of pipelines that depend on specific runner tags, the cloud accounts involved and how much testing your pipeline owners need before sign-off. The main components are planning and inventory, configuration mapping from config.toml to the new executor, building the autoscaling infrastructure in your cloud accounts, running the parallel cutover and handing over runbooks. Most of this is one-time work. Recurring costs sit mainly with your cloud provider for runner capacity and with your own team for ongoing maintenance and version alignment. To get a quote, ask for a written scope that lists the runner count, executors, cloud targets, tag routing, and the deliverables and sign-off points. DeployOpen agrees scope and deliverables in writing before work starts.

How long does a Docker Machine to Docker Autoscaler migration take?

Duration is driven by inputs rather than a fixed period. The biggest factors are how many runners and runner groups you operate, how many projects and teams route jobs by tag, how complex your existing autoscaling settings are, and how many cloud accounts or regions are involved. Change windows and the approval process for each team also set the pace, since cutover happens tag by tag while both fleets run. Confirm your removal deadline early so the plan works backward from it. Ask any partner for a timeline that lists the phases, the dependencies between them and the decisions your team must make at each step.

Can our own team migrate the runners without a partner?

Yes, if your team already has working knowledge of GitLab Runner configuration, your cloud provider's compute and networking services, and the autoscaling plugins used by the Docker Autoscaler executor. You also need enough time to finish before the removal deadline and an owner who can coordinate with pipeline teams. Before deciding, confirm which executor you will use, check the current GitLab Runner documentation for supported setups, and test a parallel runner on a non-production project. If one of those skills is missing or the calendar is tight, a fixed-scope engagement can cover the gap while your team keeps ownership of the fleet.

What does the migration need from our team?

Expect to provide access and time from several groups. Platform engineers need read access to the GitLab instance and runner configuration files so the inventory can be built. Cloud administrators need to grant access to the accounts or subscriptions where new runner capacity will run, along with network and identity details. Pipeline owners must review their jobs, confirm tags and sign off on each cutover. Your change management team should agree on maintenance windows and rollback steps. Ask the partner to list each of these inputs, the named contact for each, and when each is needed in the schedule.

Should we choose the Instance executor or Docker Autoscaler?

The right choice depends on whether your jobs need the full host or can run inside containers on shared VMs. Docker Autoscaler suits jobs that run in containers and can share VMs with isolation provided by Docker. The Instance executor suits jobs that need the whole VM, its operating system or attached devices. The comparison covers isolation, cache handling, cost of idle capacity and operational effort. The tabs section on this page sets out the mapping in more detail, and you should test your heaviest pipelines on both before deciding.

What happens if we miss the Docker Machine removal deadline?

Docker Machine is deprecated, and removal is planned for GitLab 20.0. GitLab 20.0 is planned for May 2027, according to the GitLab maintenance policy. Confirm the current removal notice in the GitLab Runner documentation before you set your plan, because dates and wording can change. If removal lands before your fleet has moved, jobs that depend on those runners will stop running on upgrade. Plan a parallel cutover by runner tags so you can move pipelines in stages and keep a rollback path until each group has passed its checks.

Can DeployOpen run the runner cutover for us?

DeployOpen plans, implements, configures and documents self-hosted open-source platforms inside your own infrastructure, including GitLab Runner fleets in your cloud accounts. Most engagements are fixed-scope, so the scope, deliverables and timelines are agreed in writing before work starts. The scope would typically cover the inventory, the executor mapping, the autoscaling build, the parallel cutover by tag, and handover documentation. Ongoing support and upgrades can be added as a retainer. DeployOpen does not publish a price list, so a quote follows from the written scope.

How DeployOpen scopes, delivers and supports the runner migration

DeployOpen starts with an inventory of your existing Docker Machine runners, their config.toml settings and the jobs they serve, then agrees a written scope before any change is made. The migration is built as a parallel fleet on Docker Autoscaler or the Instance executor, cut over team by team through runner tags, with each step documented and handed over.

How we scope

  • Inventory every Docker Machine runner, its config.toml settings, registered scopes and the tags jobs depend on
  • Map each setting to its Docker Autoscaler or Instance executor equivalent and list the settings with no direct match
  • Agree which teams, projects and tags move in each cutover wave, written into the fixed-scope agreement
  • Confirm the GitLab and Runner versions in use so the target Runner stays aligned with your GitLab release

How we build

  • Stand up the new autoscaling fleet alongside the existing Docker Machine runners so both can take jobs during cutover
  • Configure cloud or hypervisor credentials, instance templates, idle capacity and cache settings to match the agreed design
  • Test representative pipelines on the new runners, including jobs that rely on Docker-in-Docker, privileged settings or caches
  • Record configuration as code and document the tag map, rollback steps and any settings that changed behavior

How we hand over

  • Hand over runbooks for adding teams, rotating runner credentials and removing old Docker Machine runners
  • Walk your platform engineers through the cutover log, test results and the decisions behind each mapped setting
  • Confirm with you that no pipelines still depend on Docker Machine tags before retiring the old fleet
  • Deliver a clear list of open items, such as settings to confirm with your cloud provider or security team

How we support

  • Ongoing support, upgrades and runner version alignment are available as a retainer after handover
  • Support can cover monitoring of the autoscaling fleet, changes to instance templates and responses to failed jobs
  • Retainer scope, response expectations and fees are agreed in writing and quoted from your environment
  • Before any future GitLab upgrade, confirm the Runner version and executor compatibility you need with your team

Sources and further reading

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.