When the GitLab Runner Instance executor fits full-host jobs
The Instance executor runs each CI job directly on an autoscaled virtual machine, so a job gets the whole operating system, its own kernel and any devices attached to that VM. Choosing it over Docker containers depends on how much isolation and host access the job needs, not on which build tool the team prefers. If a job needs a specific kernel module, a USB or serial device, a particular Windows or non-Linux operating system, or a toolchain that cannot run inside a container, a container-based executor will not reach it, and the Instance executor is the usual candidate. Platform teams, device and firmware testing groups, and Windows or other non-container build chains are the groups that most often need it.
Before committing, confirm the behavior you depend on in the GitLab Runner documentation, which is the authoritative source for how the Instance executor provisions, reuses and removes machines, and which fleeting plugin your cloud or hypervisor requires. Ask the team whether a job truly needs host access or only needs a clean environment, because the second case is often met by Docker Autoscaler with less exposure. Map each job to the access it requires, and list the devices, kernel features and OS images involved. That list drives the VM image, the autoscaling group design and the trust boundary you must plan for, since a job running on the host can affect other work that shares that machine or image.
Comparing the GitLab Runner Instance executor with Docker Autoscaler
This table compares the Instance executor and Docker Autoscaler across isolation, host access, device support, dependencies, boot behavior and cost drivers. Read each row as a question to answer for your fleet, then use the closing note to confirm which options your Runner version and cloud support.
| Dimension | Instance executor | Docker Autoscaler |
|---|---|---|
| Isolation boundary | Each job runs directly on a full virtual machine, so the VM itself is the main boundary between jobs and the cloud account. | Each job runs in a container on an autoscaled VM, so the container is the main boundary between jobs on the same host. |
| What the job can access on the host | Jobs see the operating system, installed packages and kernel of the VM, so access is closer to a dedicated build machine. | Jobs see the container filesystem and mounted paths, with host access limited to what the Runner configuration exposes. |
| Attached devices and OS-level changes | Suited to jobs that load kernel modules, use hardware tokens, USB or GPU devices, or change system services. | Device access and kernel-level changes need extra container configuration, and some needs may not be possible at all. Confirm each device with your Runner version. |
| Image and dependency handling | Dependencies are installed on the VM image or by the job itself, so the image must be kept current and versioned. | Job images are pulled per container, which keeps tool versions in the image rather than the VM. Image pull and cache design affect job start time. |
| Boot time and idle capacity | Each new job depends on a VM being ready, so boot time and warm pool settings shape how quickly jobs start. | The same VM-level scaling applies, and container start adds a layer. Ask how idle capacity is held and what it costs in your cloud. |
| What drives cost | VM size and count, idle capacity, image build effort and the time spent maintaining OS images drive most of the spend. | VM size and count, idle capacity, registry and cache storage, and the effort to maintain job images drive most of the spend. |
| Platform and version support | Confirm which cloud plugins and Runner versions support the Instance executor in your environment before you design the fleet. | Confirm which cloud plugins and Runner versions support Docker Autoscaler in your environment before you design the fleet. |
Choosing the Instance executor or Docker Autoscaler by workload
Jobs that flash firmware, drive a test rig over USB or serial, or use a hardware token need the device visible to the process that runs the job. A container can reach a device only when the host passes it through, and that setup has to be maintained for every image. The Instance executor runs the job on the machine itself, so the device, its driver and its permissions belong to the host image that the autoscaler provisions.
- What the job needs: a stable device path, the right driver and group membership for the runner user, and a provisioning step that attaches the device before the job starts.
- What you give up: per-job isolation. If a job changes device state and the instance is reused, the next job inherits that state.
- Autoscaling fit: a newly created instance may not have the device attached. Confirm with your cloud provider or hypervisor that attachment can happen at provisioning time.
- Access control: the runner user can reach the device on every job, so limit which projects can target the runner tag.
- Cost driver: devices often tie a runner to specific hardware, which limits how far the fleet can scale down.
In a pilot, run two jobs back to back on one instance (illustrative: a flash step followed by a verify step) and confirm the device returns to a known state between them.
Some builds depend on the kernel itself: loading kernel modules, compiling eBPF programs against a specific kernel version, building boot images, or changing sysctl settings. Containers share the host kernel, so a container cannot provide a different kernel. A full instance can, which makes the Instance executor the more direct fit when the kernel is part of the build input.
- Kernel version control: the kernel comes from the instance image, so image updates become build changes that need review.
- Privileged installs: kernel work often needs root on the host. Confirm which jobs get that access and keep those jobs on a separate runner tag.
- Image pipelines: if the build also produces OS images, decide whether that work runs on the fleet or on a dedicated builder.
- Reuse risk: leftover modules, mounts or
sysctlchanges from one job can affect the next job on a reused instance. - Verification: compare the kernel version and loaded modules at job start with the versions the build expects.
In a pilot, build the same kernel module on a Docker job and on an Instance executor job, then compare the output and the kernel version each job reports. Also confirm how a failed job is cleaned up before the instance accepts new work.
Windows builds for .NET, MSVC or signing workflows, and Apple builds that need Xcode, depend on an operating system that a Linux container cannot provide. These jobs push the team toward hosts that match the target platform. The GitLab Runner documentation describes which executors and platforms are supported, and that list should be checked against the exact Runner version the team plans to deploy.
- Platform support: confirm that the executor, the autoscaler plugin and the cloud image all support the target operating system before designing the fleet.
- Apple licensing: confirm the terms for running macOS on the provider you plan to use, since Apple licensing and hardware placement can limit where those instances run.
- Signing material: certificates and signing keys must sit in a location the job can reach, with access limited to protected branches or tags.
- Version alignment: keep Runner and GitLab versions aligned, and test Windows or macOS Runner upgrades separately from the Linux fleet.
- Isolation from Linux fleets: keep desktop toolchains on their own tags so Linux jobs never land on those hosts.
In a pilot, run one representative build and one signing step on the target platform, then confirm the Runner version, the image build and the cache path all behave the same way after a fresh instance is created.
Most application builds need a language toolchain, a test service or a packaging step that can run inside a container image. For these jobs the Docker Autoscaler executor is usually the simpler fit because the image defines the environment, each job gets its own container, and the same image runs on the developer's laptop and in CI. The Instance executor remains useful when the job needs more than the container provides.
- Reproducible environments: the image pins tools and versions, which makes build results easier to compare across runs.
- Per-job isolation: each job starts in a fresh container, which limits leftover state between jobs.
- Cache design: a shared cache in object storage helps fresh instances restore dependencies. Confirm how the cache paths are set before comparing executors.
- Idle capacity: the autoscaler's idle settings determine how quickly new jobs start and how many instances stay running between jobs. Those settings drive most of the cost.
- Image maintenance: someone must rebuild and scan base images on a schedule, which is recurring work regardless of executor.
In a pilot, measure job start time and cache hit rate for a typical pipeline on each executor, then confirm that the team can maintain the images it depends on. If the pilot shows no gap in build results, the containerized option is usually the lower-effort choice.
Why Docker Machine runners are moving to the Instance executor
Fleets that run on the Docker Machine executor need a replacement plan now, because GitLab has deprecated that executor and plans to remove it in GitLab 20.0, which the company schedules for May 2027. The two supported destinations are the Instance executor, which runs each job directly on an autoscaled VM, and Docker Autoscaler, which keeps Docker as the job environment on the same kind of fleet. Choose between them by asking whether jobs need the host operating system and attached devices, or only a container. Confirm the removal date against the GitLab maintenance policy when you set your migration deadline, because the date anchors every other decision in this plan.
Start with an inventory of the existing [runners.machine] block in config.toml. Record the idle count, idle time, maximum builds per machine, cloud credentials, machine options and any cache or volume settings, then note which teams depend on each runner. Map each setting to its counterpart in the Instance executor or in the [runners.autoscaler] section used by Docker Autoscaler and its fleeting plugin. Some Docker Machine options will not have a one-to-one equivalent, so check each mapping against the GitLab Runner documentation and test it on a non-production runner before you rely on it. Ask your team to document every setting that changes behavior, not only the ones that appear in the template.
A parallel cutover reduces risk because the old and new fleets run side by side, and you move work between them by runner tag. Register the new fleet with its own tags, point a pilot group of low-risk projects at it, and then move projects in waves that match team boundaries. Keep the Docker Machine runners online until their queues drain, and remove them only after the new fleet has handled a full release cycle. The cost of this approach is duplicate capacity during the overlap, so set the overlap window in advance. Keep Runner versions aligned with your GitLab version throughout, since the Runner documentation advises matching major and minor versions.
Setting up the GitLab Runner Instance executor on an autoscaling fleet
This sequence takes a team from a compatible Runner and GitLab version to a verified autoscaling fleet that creates VMs for full-host jobs, runs a pilot job and removes idle capacity afterward.
Confirm Runner and GitLab versions match
The platform engineer checks the GitLab version on the self-managed instance and installs a GitLab Runner release with the same major and minor version. GitLab's Runner documentation advises keeping these aligned, so a mismatch is resolved before any cloud resources are created. Confirm the planned Runner version against the GitLab upgrade and maintenance guidance for your instance. The check is done when the Runner binary reports a version that matches the GitLab server version in your change record.
Choose and install the cloud fleeting plugin
The platform engineer selects the fleeting plugin for your cloud, such as the plugin for the provider where your VMs will run, and confirms it is one GitLab supports for your use case. Community plugins are not tested by GitLab, so the support owner should record that decision before going further. Install the plugin on the runner manager host and confirm the Runner can load it. The check is a successful plugin version command output on the manager, with no configuration errors in the Runner service log.
Build the VM image with required tooling
The team builds a base image or template that contains everything the full-host jobs need: the operating system packages, language toolchains, device drivers, and the Git and Runner helper prerequisites. The image should be versioned and rebuilt on a schedule that your security team approves, because each job starts on a fresh instance. Record the image identifier and the date it was built. The check is a test VM launched from that image that completes a manual Git clone and a toolchain version command.
Configure the scaling group and capacity limits
The cloud or platform engineer creates the autoscaling group or instance group, attaches the image, and sets minimum, maximum and idle capacity values in the Runner's config.toml. Keep the manager on a stable VM that is not itself a spot or preemptible instance, and confirm the network, security groups and instance role give the VMs only the access they need. The check is a dry review of the config file against the group's limits, plus a successful connection test from the manager to the group's API.
Register a test runner with a dedicated tag
The engineer registers a Runner on the manager using the Instance executor and a tag that no production project uses, such as one naming the full-host workload. Restricting the runner to that tag keeps pilot jobs away from shared pipelines. Use the authentication token workflow your instance supports, and record the runner ID. The check is that the runner appears as online under the intended scope in the GitLab UI, with the dedicated tag shown on its details page.
Run a pilot job that needs the full host
The team creates a small test project with a pipeline that requires the full VM, for example a job that loads a kernel module or reads an attached device path. The job should print the hostname, instance details and the device check output. Run it once and watch the cloud console or fleeting plugin logs to confirm a new VM is created for the job. The check is a job log line showing the expected host details and a Runner log entry recording the instance ID that matches the cloud console.
Verify job completion and scale-down
After the pilot job finishes, the engineer watches the autoscaling group until the VM created for the job is removed and idle capacity returns to the configured minimum. Confirm the job artifacts and logs were retained in GitLab, and that no secrets were left on disk in a state the next job could read. The check is an observed scale-down event in the cloud console, matched to the job's instance ID, and an idle count that matches the minimum you set.
Security controls for full-host runners
A full-host runner gives a job the whole VM, so a compromised job can reach the host, the cloud role and the network around it. The six controls below tie isolation, credentials, image hygiene, network placement, deployment limits and logging together. Each one should be settled before the first pipeline runs, and the GitLab hardening guidance for CI/CD and runner isolation is a work in progress that should be rolled out gradually.
Isolate untrusted projects
Instance executor jobs share no container boundary with the host, so a job from an untrusted project can read anything the VM can reach. Keep untrusted projects on a separate runner fleet with its own VM template, tags and cloud account, and do not register that fleet to groups that hold deployment credentials. Confirm this split in the runner registration settings before the fleet goes live.
Scope the VM role and cloud credentials
Each autoscaled VM carries an instance role that jobs can use through the metadata service. Give that role only the actions the fleet needs, such as reading the cache bucket and writing its own logs, and keep the runner manager's credentials separate from the job VM's role. Ask your team to list every permission the role holds and to remove any that a job does not need.
Harden and patch the image
The VM image is the base for every job, so its contents become every job's contents. Build it from a pinned, minimal OS image, remove tools that jobs do not need, and rebuild on a fixed schedule with security updates applied. Keep the runner version aligned with the GitLab version as the Runner documentation advises, and record which image version ran each job.
Segment the manager and job subnet
The runner manager needs to reach the GitLab instance and the cloud API, while job VMs need only the package sources and cache they use. Place them in separate subnets, allow the manager to reach job VMs on the required ports only, and block job VMs from reaching internal services such as databases and administration consoles. Test egress from a job VM before opening any path.
Limit deployment jobs to protected branches
A job that runs on a full host and holds deployment credentials can change production from any build it executes. Restrict runners that carry deployment credentials to protected branches and protected environments, and keep them off the fleet that runs merge request pipelines. Confirm how your GitLab version applies these restrictions before relying on them.
Log job activity on the VM
Full-host jobs can change system settings, start services and open connections, and the job log alone does not show that. Forward system and audit logs from each VM to a store outside the fleet before the VM is terminated, and set a retention period that matches your review obligations. Ask your team to confirm that logs survive scale-in events.
What drives the cost of full-host autoscaling runners
The cost of a full-host autoscaling runner fleet is set by a handful of recurring line items and a smaller set of one-time engineering tasks, and the largest recurring line is usually compute for instances that boot, run jobs and terminate. Those instances are billed by your cloud provider, and the idle capacity you hold for faster starts is billed whether or not a job is running. Storage for VM images and the shared cache, network egress for pulling dependencies and pushing artifacts, and the host that runs the runner manager all recur as well. The runner manager must stay on a dedicated, always-on machine, so it adds a fixed monthly cost that does not shrink when the fleet is idle. One-time costs are the engineering effort to build and test the VM image, the pilot that proves job times and cache behavior on your workloads, and the cutover that moves projects to the new runner tags.
Cost rises with long job durations, because each instance is billed for the full time it is busy, and with large VM sizes, because you pay for every vCPU and memory gigabyte on each boot. A high minimum idle count multiplies the idle cost across the fleet, so confirm how many warm instances each runner tag actually needs at peak and at quiet hours. Image maintenance is a recurring cost that teams often underestimate: every operating system patch, toolchain update and attached-device driver change requires a rebuild, a test run and a rollout. Ask whether the image pipeline is versioned so a bad build can be rolled back without an outage.
When you request a quote, ask for each scope item to be listed separately: the image design and build, the pilot on representative jobs with measured queue and start times, the cutover plan by runner tag, and the ongoing support window with what it covers for patching, runner version alignment and incident response. Ask which cloud accounts, network paths and attached devices the work assumes, and what the vendor needs from you, such as access, test workloads and approval gates. Confirm which costs you will pay directly to the cloud provider and which go to the implementation partner, so the total cost of ownership can be compared with building the capability in-house.
What to confirm before choosing the GitLab Runner Instance executor
The Instance executor gives each job a full virtual machine, which changes how images, scaling and licensing behave. The checks below connect the platform choice to the constraints that tend to surface only after a fleet is built, so each one should be confirmed in GitLab's documentation or in a short pilot on your own accounts.
Runner and plugin platform support
Confirm that your target cloud or hypervisor is supported by the Runner release you plan to run and by the fleeting plugin that provisions machines for it. Keep the Runner's major and minor versions aligned with your GitLab instance, and check whether the plugin you choose is maintained by GitLab or by the community, since support terms differ. Record the exact versions in your pilot so the same combination is what you later operate.
Behavior on your OS image
Test the executor on the exact Windows or Linux image you intend to ship, not a generic base image. Verify that the Runner service starts at boot, that the job user has the permissions the build needs, and that disks, agents and build tools behave as expected after the machine is replaced. Images that depend on manual steps at first boot are the most common source of failed scale-ups.
Boot and scale-up times
Measure how long a new VM takes from request to a job starting in your region, including image pull, Runner registration and any configuration management run at boot. Ask how idle capacity is kept and what it costs to keep it warm. These timings decide whether developers accept the wait, and they determine how many idle machines you need to hold for peak pipeline activity.
Quota and instance-type availability
Check that your cloud account has vCPU and instance-family quota in the regions and zones you plan to use, and that the instance types you select are available there. Scale-up can fail at peak demand when quota is exhausted, so request increases before go-live and confirm whether spot or preemptible capacity is suitable for workers but not for the manager.
Licensing of baked-in software
Review the license of every operating system, runtime and build tool included in your machine image, including commercial compilers, Windows and Apple toolchains and any proprietary agents. Confirm that the terms allow automated, repeated use on autoscaled machines. Runner itself is MIT licensed, but the software you bake into images carries its own terms and must be cleared by your legal or procurement team.
GitLab tier and support coverage
Confirm that your GitLab edition and support plan cover the runner setup you intend to operate, and that your internal team has the access and runbooks needed to troubleshoot fleet issues. Check which features your tier includes for CI/CD and whether priority support applies to self-managed installations. Put these answers in writing before you commit to the executor.
Questions buyers ask about the GitLab Runner Instance executor
How much effort does setting up the Instance executor take?
Effort depends on how many distinct VM images, operating systems and attached devices your jobs need, and on how much autoscaling logic you want to build around them. A single Linux image with one job profile is a small build. Each additional image, a Windows or macOS target, or a device passthrough requirement adds design, testing and documentation work. Ask any partner to split the estimate into runner configuration, cloud or hypervisor provisioning, image build pipelines, and verification of job isolation, so you can see where the hours go.
What does our team need to provide for the engagement?
You will need named access to the cloud account, data center or hypervisor where runners will live, a network path from runners to your GitLab instance, and a person who can approve images, instance sizes and IAM or role permissions. Your security team should review the trust model before build starts, because full-host jobs can reach whatever the VM can reach. Your CI owners should list the jobs that need the whole host, the devices they touch and the tools they install, so the scope in the written agreement matches real workloads.
Can our own platform team build and run this in-house?
A capable platform team can, provided it has experience with GitLab Runner configuration, autoscaling groups or fleeting plugins, and image lifecycle management. The harder parts are usually not the first deployment but the ongoing work: keeping Runner versions aligned with your GitLab version, rebuilding images after patches, and handling capacity limits and failed scale-outs. Compare the internal time against a fixed-scope engagement that includes documentation and handover, and decide whether you want the knowledge to stay with your team after the build.
How long does a pilot take?
The duration depends on scope, meaning the number of job profiles, cloud or hypervisor targets, operating systems and the compliance evidence you need. No duration is given here. A pilot usually covers one job profile on one platform so that provisioning, job isolation and teardown can be checked before you expand. Ask for a timeline in the written scope that lists each milestone and what you must approve at each one.
What does it cost to run, and what drives the bill?
Recurring cost is mostly compute: the instances that run jobs, the manager that schedules them, and the idle capacity you keep warm to avoid slow starts. Storage for images and caches, network egress and any licensed software on the images also add to it. One-time costs include design, image builds and handover. Ask any quote to separate these lines and to state which costs you pay directly to the cloud or hypervisor provider and which are professional services. Idle capacity and instance size are the two settings most likely to move the bill.
When should we choose Docker Autoscaler instead?
Choose Docker Autoscaler when jobs can run in containers and do not need the full host, a specific kernel module, a particular operating system version or a directly attached device. Containers give a cleaner default isolation boundary, faster job startup on shared images and a simpler image pipeline. The Instance executor fits jobs that need the whole VM, such as device testing, OS-level builds or hardware-bound workloads. Many organizations run both, separated by runner tags, so the choice is made per job profile rather than for the whole fleet. See the GitLab Runner documentation for the current executor list.
How is migration from the Docker Machine executor handled?
Docker Machine is deprecated and is scheduled for removal in GitLab 20.0, so existing fleets need a plan. The usual approach maps current config.toml settings to either Docker Autoscaler or the Instance executor, then runs the new fleet in parallel and moves jobs across by runner tags. Your scope should list each runner, its job types and the cutover order, and it should include a rollback path. Confirm the exact removal timing with the GitLab documentation for your target version before you set deadlines.
Do we need GitLab Premium or Ultimate to run this?
The Instance executor is a GitLab Runner feature, and GitLab Runner is distributed under the MIT license, so the runner itself does not depend on a paid GitLab tier. Your tier choice depends on the rest of your GitLab use, such as advanced CI/CD, priority support, security scanning or compliance features. Premium lists advanced CI/CD and priority support, while Ultimate adds security and compliance features. Confirm the tier for your instance against the GitLab pricing page and make sure the runner version matches your GitLab version.
How DeployOpen scopes and delivers full-host GitLab runners
DeployOpen plans, builds, documents and supports GitLab Runner Instance executor fleets inside your own cloud accounts, data centers or air-gapped networks. We start from the jobs that need the whole host, then agree the scope, build the fleet and hand over the runbooks your team needs to operate it.
How we scope
- Inventory every job that needs the full VM, operating system or attached device, and record why Docker isolation is not enough.
- Confirm the target cloud or hypervisor, the fleeting plugin, image pipeline and the GitLab and Runner versions to be aligned.
- Agree the written scope, deliverables and timeline before work starts, since most engagements are fixed-scope.
How we build
- Build the manager placement, autoscaling group or instance template, and the golden image for instance-based jobs.
- Configure runner tags, protected-branch restrictions and cache settings so privileged jobs stay on the intended hosts.
- Test scale-out, scale-in, job cleanup and device attachment against representative pipelines before cutover.
How we hand over
- Document the fleet design, configuration files, image build steps, IAM permissions and the rollback path to your team.
- Walk your engineers through patching, Runner version alignment and how to replace an instance image safely.
- Deliver a verification record showing which jobs ran, which hosts they used and how cleanup was confirmed.
How we support
- Keep the fleet current with GitLab Runner releases as part of a support retainer, where scope and frequency are agreed in writing.
- Review instance hardening, image contents and scaling limits on a schedule your team sets.
- Ask us to quote ongoing support from your written scope, since DeployOpen does not publish a price list.

