Architecting GitLab Runner Infrastructure on Google Cloud Platform

The integration of GitLab Runner with Google Cloud Platform (GCP) represents a sophisticated convergence of continuous integration and continuous delivery (CI/CD) orchestration and scalable cloud infrastructure. By leveraging GCP's compute capabilities, organizations can transition from static, limited build environments to a dynamic, autoscaling fleet of runners. This architecture ensures that computational resources are provisioned on-demand to execute pipeline jobs and are decommissioned when idle, thereby optimizing both performance and cost-efficiency. The primary mechanism for this deployment involves the GitLab Runner Infrastructure Toolkit (GRIT), which streamlines the provisioning of the runner manager and the subsequent orchestration of temporary runner instances. Whether deployed via Compute Engine for virtual machine-based workloads or via Google Kubernetes Engine (GKE) for containerized orchestration, the synergy between GitLab and GCP allows for a highly resilient DevOps pipeline capable of handling massive parallelization.

Prerequisites and Access Governance

Before initiating the deployment of a GitLab Runner on Google Cloud, a stringent set of administrative permissions and environmental configurations must be satisfied. Failure to meet these requirements will result in authentication errors during the GRIT execution or the failure of the runner manager to communicate with the GitLab instance.

The following permissions are mandatory based on the scope of the runner:

  • Group Runners: The user must possess the Owner role for the specific GitLab group to ensure they have the authority to manage shared resources across multiple projects.
  • Project Runners: The user must hold at least the Maintainer role for the individual project to configure CI/CD settings and register runners.
  • Google Cloud Project: The user must be assigned the Owner IAM role within the GCP project to allow for the creation of Compute Engine instances, the management of service accounts, and the enabling of necessary APIs.

Beyond identity and access management, the following environmental components must be active:

  • GCP Billing: Billing must be explicitly enabled for the Google Cloud project. Since the runner manager and the autoscaling fleet utilize Compute Engine resources, any project without a valid billing account will fail to provision the required VM instances.
  • Gcloud CLI: A working installation of the Google Cloud CLI tool is required. This tool must be authenticated with the IAM role associated with the project to execute the setup scripts and manage cloud resources from a local terminal.
  • Terraform Environment: For the infrastructure-as-code phase, Terraform v1.5 or later must be installed. The Terraform CLI tool is essential for executing the main.tf configuration provided by GitLab.
  • Terminal Environment: A terminal with Bash installed is required to execute the initial setup scripts provided during the GitLab onboarding process.

Provisioning Project and Group Runners in Compute Engine

The process of establishing a runner on Google Cloud Compute Engine is a multi-stage workflow that begins within the GitLab UI and culminates in the execution of infrastructure-as-code on the local machine.

Initial Runner Creation in GitLab

The administrator must first define the runner's intent and metadata within the GitLab interface.

  • For Group Runners: Navigate to Build > Runners > New group runner.
  • For Project Runners: Navigate to Settings > CI/CD > Runners > New project runner.

During this configuration phase, the following parameters must be defined:

  • Tags: In the Tags field, enter specific job tags. These tags act as filters; only jobs specifying these tags will be routed to this runner. If the runner should also handle jobs that lack tags, the Run untagged option must be selected.
  • Configuration: Users may optionally add a runner description to identify the instance in a multi-runner environment or provide additional custom configurations.

Environment Specification and GRIT Integration

Once the runner is created, the platform prompts for the specific Google Cloud environment details. This data is critical as it dictates where the runner manager VM will be instantiated.

The required environment details include:

  • Google Cloud project ID: The unique identifier of the GCP project.
  • Region: The geographic area where the resources will be hosted.
  • Zone: The specific isolated location within the region.
  • Machine type: The specific VM instance size (e.g., e2-medium, n1-standard-1) which determines the CPU and RAM available for the runner manager.

Upon submitting these details, GitLab provides the Setup instructions. This phase utilizes the GitLab Runner Infrastructure Toolkit (GRIT). GRIT is designed to automate the registration and provisioning process using a runner authentication token. This token is assigned during creation and is used by the GRIT Terraform script to register the runner and by the runner itself to authenticate with the GitLab job queue.

Execution of Provisioning Scripts

The setup process involves two primary technical steps:

  1. Bash Script Execution: The user must run the provided bash script (often saved as setup.sh). This script is responsible for enabling the required Google Cloud services, creating the necessary service accounts, and assigning the appropriate IAM permissions.
  2. Terraform Deployment: A main.tf file must be created using the configuration code provided in the GitLab modal. The user then executes the Terraform commands to apply the configuration.
Tool Purpose Requirement
Bash Execution of setup.sh Standard Linux/macOS shell
Terraform Infrastructure deployment via main.tf v1.5 or later
OpenTofu Alternative to Terraform Compatible with Terraform code
gcloud CLI GCP Project authentication Authenticated IAM Owner

If the user prefers OpenTofu over Terraform, the same code from the main.tf file can be used, provided the Terraform commands are adjusted to the OpenTofu CLI equivalents.

Operationalizing the Runner Manager and Autoscaling

Once the scripts are executed, a runner manager is deployed to GCP. This manager does not execute the jobs itself but acts as an orchestrator that creates temporary runners on-demand.

Verification of Deployment

After the provisioning process, the status of the runner in the GitLab UI will initially appear as Never contacted. This is expected behavior. The runner manager may take up to one minute to establish a connection with the GitLab server using the authentication token. Once the connection is successful, the status will update to online.

Cost Management and Autoscaling Optimization

By default, the runner configuration may be set to maintain VM instances continuously, which can lead to excessive GCP costs. To mitigate this, the administrator must manually tune the autoscaling behavior.

The configuration file on the manager instance contains a [runners.machine] section. To optimize for cost, the following parameters should be adjusted:

  • IdleCount: Defines the number of runners that are kept running even when there are no jobs in the queue. Reducing this to 0 ensures no VMs run during idle periods.
  • IdleTime: Specifies how long a runner stays active after completing a job before being terminated.
  • Instance Limits: Sets the maximum number of concurrent runner instances allowed to prevent unexpected billing spikes.

Integrating GitLab Runner with Google Kubernetes Engine (GKE)

For organizations requiring higher density and container-native orchestration, GitLab Runner can be configured to operate within a Google Kubernetes Engine (GKE) cluster. This setup utilizes the Kubernetes Operator to manage the lifecycle of the runners.

Environment Setup and Cluster Connectivity

The prerequisite for GKE integration is the installation of the Google Cloud CLI and kubectl. The gcloud tool is used to authenticate and connect to the cluster, while kubectl serves as the primary interface for communicating with the remote Kubernetes API.

The Kubernetes Operator Deployment Flow

The deployment of the runner on GKE follows a specific sequence of manifest applications to ensure security and proper registration.

First, a certificate issuer must be established to handle the webhook server's security. The following manifest is applied:

```yaml
metadata:
name: gitlab-runner-serving-cert
namespace: gitlab-runner-system
spec:
dnsNames:
- gitlab-runner-webhook-service.gitlab-runner-system.svc
- gitlab-runner-webhook-service.gitlab-runner-system.svc.cluster.local
issuerRef:
kind: Issuer
name: gitlab-runner-selfsigned-issuer

secretName: webhook-server-cert

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: gitlab-runner-selfsigned-issuer
namespace: gitlab-runner-system
spec:
selfSigned: {}
```

The administrator executes the application of this issuer using the following command:

kubectl create -f certificate-issuer-install.yaml

Second, the runner registration token must be stored securely as a Kubernetes Secret. The following process is used to create the secret:

cat > gitlab-runner-secret.yml << EOF
yaml apiVersion: v1 kind: Secret metadata: name: gitlab-runner-secret type: Opaque stringData: runner-token: YOUR_RUNNER_AUTHENTICATION_TOKEN
EOF

The secret is then applied to the cluster:

kubectl apply -f gitlab-runner-secret.yml

Finally, a Custom Resource Definition (CRD) is created to define the runner's behavior and its connection to the GitLab instance:

cat > gitlab-runner.yml << EOF
yaml apiVersion: apps.gitlab.com/v1beta2 kind: Runner metadata: name: gitlab-runner spec: gitlabUrl: https://gitlab.example.com buildImage: alpine token: gitlab-runner-secret
EOF

The CRD is applied via:

kubectl apply -f gitlab-runner.yml

Google Artifact Registry Integration

To maximize the efficiency of CI/CD pipelines on GCP, the GitLab project should be integrated with the Google Artifact Registry. This allows the runner to push and pull container images with minimal latency and high security.

The integration process involves:

  • Navigating to Settings > CI/CD in the GitLab project.
  • Configuring the necessary policies to allow the GitLab project to interact with the Artifact Registry repository.
  • Saving the changes to establish the link.

Once configured, users can view their hosted images by navigating to Deploy > Google Artifact Registry in the GitLab sidebar. This integration is vital for the "Build" stage of the pipeline, where the runner compiles the code into a container image and pushes it to the registry before the "Deploy" stage pulls that image into the GKE cluster or Compute Engine instance.

Pipeline Implementation and Job Execution

Once the GCP runner is provisioned and online, it must be targeted within the .gitlab-ci.yml file to ensure that jobs are routed to the cloud infrastructure rather than shared GitLab.com runners.

To utilize the GCP runner, the tags keyword must be used in the job definition. For example, if the runner was created with the tag gcp-runner, the configuration would look as follows:

```yaml
stages:
- greet

hello_job:
stage: greet
tags:
- gcp-runner
script:
- echo "hello"
```

In this configuration, the hello_job is assigned to the greet stage. The tags section ensures that only a runner with the gcp-runner tag—specifically the one provisioned on GCP—will pick up the job. The script section executes the command echo "hello", verifying that the runner is successfully communicating with the GitLab instance and executing commands on the GCP VM or pod.

Analysis of Architectural Impact

The deployment of GitLab Runners on Google Cloud Platform transforms the CI/CD process from a static cost center into a scalable utility. The use of the GitLab Runner Infrastructure Toolkit (GRIT) effectively abstracts the complexity of cloud provisioning, allowing DevOps engineers to treat their build infrastructure as code.

The primary advantage of this architecture is the decoupling of the runner manager from the executor. By utilizing an autoscaling fleet, the system avoids the "noisy neighbor" effect common in shared runner environments and eliminates the waste of paying for idle compute. However, the flexibility of this system requires diligent monitoring of the [runners.machine] settings; without strict IdleCount and IdleTime configurations, the cost of maintaining a "warm" fleet of VMs can quickly escalate.

Furthermore, the GKE-based implementation offers a higher degree of granularity. By using the Kubernetes Operator, the lifecycle of each job is encapsulated within a pod, providing total isolation and the ability to define resource requests and limits (CPU/RAM) at the pod level. This is a significant upgrade over the Compute Engine approach for teams running high-density, containerized workloads.

The integration with Google Artifact Registry completes the ecosystem, creating a closed-loop system where code is committed in GitLab, built on GCP Compute/GKE, stored in Artifact Registry, and deployed back to GKE. This minimizes data egress costs and reduces the time spent in the "push/pull" cycles of the pipeline, resulting in a significantly lower Mean Time to Recovery (MTTR) and faster deployment cycles.

Sources

  1. Provision group runners with Google Cloud Platform and GitLab CI
  2. Provision runners in Google Cloud Compute Engine
  3. Configure GitLab Runner to use the Google Kubernetes Engine
  4. Set up GitLab Google Integration

Related Posts