Configuring GitLab Runner with the Docker-Windows Executor for Windows Containerized Environments

The orchestration of continuous integration and continuous delivery (CI/CD) pipelines within Windows-based ecosystems requires a sophisticated understanding of how GitLab Runner interacts with the Windows container subsystem. Unlike Linux-based environments where the Docker executor is the standard for containerized workloads, Windows environments introduce specific architectural requirements, particularly regarding the distinction between the docker and docker-windows executors. Achieving a functional, scalable, and reliable pipeline necessitates precise configuration of the runner, the Docker daemon, and the underlying Windows host, as the interplay between host OS versions, Docker engine capabilities, and GitLab helper images is highly sensitive to version mismatches and configuration errors.

Architectural Divergence of Docker Executors in Windows Environments

A critical point of confusion for many DevOps engineers transitioning from Linux to Windows environments is the existence of two distinct executor types: docker and docker-windows. While the standard docker executor is the industry standard for Linux-based GitLab Runners, its application on a Windows host results in an entirely different execution context.

When a GitLab Runner is installed on a Windows host, the choice of executor dictates the operating system of the resulting container. The following table delineates the supported and unsupported configurations for these executors, illustrating the rigid boundaries of the architecture.

Runner Installation OS Executor Type Container Operating System Status
Windows docker-windows Windows Supported
Windows docker Linux Supported
Linux docker Linux Supported
macOS docker Linux Supported
Linux docker-windows Linux Unsupported
ly docker Windows Unsupported
Linux docker-windows Windows Unsupported
Windows docker Windows Unsupported
Windows docker-windows Linux Unsupported

The docker-windows executor is specifically designed to facilitate the orchestration of Windows containers. While some users have reported that the plain docker executor functions correctly for Windows container workloads in certain versions (such as GitLab Runner 17.3.1 using nanoserver or servercore images), the official documentation explicitly mandates the use of docker-windows for Windows container workloads. The primary distinction lies in the orchestration of the environment preparation and the handling of the Windows container lifecycle. Using the correct executor ensures that the runner is optimized for the Windows-specific requirements of container creation and cleanup.

The Critical Role of Windows Helper Images

The GitLab Runner does not simply run scripts directly within a container; it utilizes a "helper image" to perform essential tasks such as cloning the repository, downloading artifacts, and uploading caches. In a Windows containerized pipeline, the helper image must be compatible with the specific Windows version of the host and the target container.

The helper image is responsible for the "Post-job" phase, which includes creating caches and uploading artifacts to the GitLab server. If the helper image's architecture or Windows version does not align with the job's requirements, the pipeline will fail during the environment preparation stage.

The following list identifies the available variants of the GitLab Runner helper images that can be utilized to ensure compatibility across different Windows generations:

  • gitlab/gitlab-runner-helper:x86_64-vXYZ-nanoserver21H2
  • gitlab/gitlab-runner-helper:x86_64-vXYZ-servercore21H2
  • gitlab/gitlab-runner-helper:x86_64-vXYZ-nanoserver1809
  • gitlab/gitlab-runner-helper:x86_64-vXYZ-servercore1809

A significant aspect of Windows container management is backward compatibility. For instance, Windows Server 2025 (version 24H2) possesses the capability to utilize the 21H2 (Windows Server 2022) helper images. This compatibility allows for slightly more flexibility in infrastructure upgrades, but it remains vital to select a helper image based on the specific shell requirements (such as PowerShell versions) needed for the build scripts.

Configuration and Registration of the Docker-Windows Executor

Registering a GitLab Runner for Windows container workloads involves a precise sequence of command-line arguments. A common approach is to use a PowerShell script to automate the registration process, ensuring that all parameters like the registration token, executor type, and volume mappings are applied correctly.

When performing a non-interactive registration, the following parameters are essential for a robust configuration:

  • --url: The URL of the GitLab instance (e.g., https://gitlab.com/ or a private instance).
  • --registration-token: The unique token provided by the GitLab UI under the Runners section.
  • --executor: Must be set to docker-windows for Windows container workloads.
  • --docker-image: The default image to be used for the build jobs.
  • --docker-helper-image: The specific helper image tailored for the host Windows version (e.g., kdeorg/gitlab-windows-runner-helper:servercoreltsc2022).
  • --docker-volumes: Defines the mapping between the Windows host directory and the container directory using the syntax <host directory>:<directory in container>.
  • --cache-dir: Specifies the local directory on the Windows host where GitLab should store cache data.
  • --docker-memory: Sets the memory limit for the containers (e.g., 4g).
  • --docker-cpus: Defines the CPU allocation for the container (e.g., 1).

An example of a complete registration command in PowerShell is as follows:

powershell & .\gitlab-runner-windows-amd64.exe register ` --non-interactive ` --url "https://your-gitlab-url.com/" ` --registration_token "your registration token" ` --executor "docker-windows" ` --request-concurrency 2 ` --docker-image="your-created-docker-image:latest" ` --docker-helper-image "kdeorg/gitlab-windows-runner-helper:servercoreltsc2022" ` --docker-volumes "c:\your\host-dir\to\mount:c:\cache" ` --cache-dir "c:\cache" ` --docker-cpus 1 ` --docker-memory 4g ` --shell "powershell" ` --description "AWS Windows Docker MSVC Builds" ` --tag-list "some tags" ` --run-untagged="false" ` --locked="true" ` --access-level="not_protected"

Once registered, the config.toml file must be verified. A typical configuration for a Windows Docker executor might look like the following:

toml [[runners]] name = "windows-docker-2019" url = "https://gitlab.com/" token = "xxxxxxx" executor = "docker-windows" [runners.docker] image = "mcr.microsoft.com/windows/servercore:1809_amd64" volumes = ["c:\\cache"]

Troubleshooting Common Failures and Version Mismatches

Deploying GitLab Runner on Windows is prone to several specific failure modes, often stemming from the interaction between the Docker engine and the Windows kernel.

The Unsupported Windows Version Error

A recurring issue in Windows environments is the "unsupported Windows Version" error. This occurs when the GitLab Runner attempts to verify the host's capabilities by running docker info and finds that the Docker version or the reported Windows Server version is incompatible.

Specifically, Docker version 17.06 is known to be incompatible with GitLab Runner on Windows. When running docker info on a machine with Docker 17.06.2, the output may report the operating system as:

Operating System: Windows Server Datacenter

However, the Runner fails to parse or validate this version, leading to errors such as:

Preparation failed: detecting base image: unsupported Windows Version: Windows Server Datacenter

The root cause is often that Docker does not provide sufficient version detail, or the version is too old to be recognized. The resolution is to upgrade the Docker engine to a version contemporary with or newer than the Windows Server release being used.

HCS CreateComputeSystem Failures

Another catastrophic failure occurs during the "prepare environment" step of a CI/CD pipeline. Users may encounter the following error:

ERROR: Job failed (system failure): prepare environment: Error response from daemon: hcs::CreateComputeSystem <hash>: The parameter is incorrect.

This error is particularly frustrating because the container may run perfectly fine when executed manually via docker run on the same host. This indicates that the issue is not with the image itself, but with how the GitLab Runner's executor is attempting to interface with the Host Compute Service (HCS) to instantiate the container. This can occur due to misconfigurations in the .gitlab-ci.yml or discrepancies in how the docker-windows executor manages the container lifecycle compared to a manual Docker command.

Cache and Volume Mounting Issues

When configuring the Docker executor on Windows, there is a known issue regarding the use of c:\\cache as a source directory when passing the --docker-volumes or DOCKER_VOLUMES environment variable. Improperly formatted paths or attempting to mount directories that do not exist on the Windows host can cause the runner to fail during the job initialization phase. Always ensure that the host path exists and that the syntax follows the Windows-compatible pathing requirements.

Kubernetes Executor Specifics

If the GitLab Runner is deployed within a Kubernetes cluster using the Kubernetes executor, Windows-specific nodes must be explicitly identified. Failure to do so can lead to the runner attempting to schedule a Windows job on a Linux node, resulting in:

ERROR: Job failed (system failure): prepare helper image: detecting base image: unsupported Windows Version:

To resolve this, the Kubernetes nodes must be labeled appropriately, and the runner configuration must include the following node selector:

node.kubernetes.io/windows-build: <true>

Advanced Analysis of Execution Logic

The distinction between a successful job and a failed job in a Windows-based pipeline often comes down to the exit code handling within the shell. In a PowerShell-based executor, it is vital to understand how exit codes are interpreted. While exit 1 is a standard indicator of a failed job, the use of return 1 in certain script contexts may not trigger the failure state in GitLab, potentially leading to "false positive" successes where a job is marked as successful despite a mid-way termination or failure of a critical build step.

Furthermore, when managing complex dependencies—such as using Conan packages within a Windows Docker container—the complexity of the gitlab-ci.yml increases. The runner must be able to navigate private repositories and internal dependency registries, which requires the docker-windows executor to have correctly configured credentials and volume mounts to access the necessary configuration files and cache directories.

In conclusion, the deployment of GitLab Runner on Windows using the docker-windows executor is a high-precision task. Success depends on a three-way alignment between the Windows Host version, the Docker Engine version, and the GitLab Runner helper image version. Discrepancies in any of these layers, particularly regarding the Docker version or the HCS interface, will result in environment preparation failures that cannot be resolved by simply fixing the application code. Engineers must treat the infrastructure configuration as a tightly coupled system where the executor type, volume mounting, and kernel-level compatibility are the primary drivers of pipeline stability.

Sources

  1. GitLab Forum - GitLab Runner on Windows with Windows Containers
  2. GitLab Documentation - Docker Executor
  3. GitLab Forum - Windows Host GitLab Runner with Docker Desktop
  4. GitLab Forum - Running Windows Containers on Windows Host
  5. Coding with Thomas - Windows Docker Container in GitLab with Conan
  6. GitLab Documentation - Install GitLab Runner on Windows

Related Posts