Orchestrating Kubernetes Workloads via GitLab Runner and Kubectl Integration

The convergence of continuous integration/continuous deployment (CI/CD) and container orchestration represents the pinnacle of modern DevOps engineering. Within the GitLab ecosystem, the synergy between GitLab Runner and the kubectl command-line interface provides a robust framework for automating the lifecycle of Kubernetes-based applications. This integration is not merely about executing scripts; it is about establishing a secure, scalable, and programmable bridge between a version control system and a live orchestration engine. By leveraging the GitLab Runner Helm chart to deploy executors within a cluster and utilizing the GitLab agent for Kubernetes to provide authenticated access, organizations can achieve a seamless flow from code commit to production deployment. This deep technical exploration dissects the deployment mechanisms, security architectures, and operational workflows required to master this integration.

Deploying the GitLab Runner via Helm Chart

The deployment of a GitLab Runner into a Kubernetes environment is most effectively managed through the official GitLab Runner Helm chart. This method ensures that the runner is treated as a first-class citizen within the Kubernetes ecosystem, allowing for scalable, declarative management of the runner's lifecycle.

The GitLab Runner Helm chart is designed to work across various service tiers, including Free, Premium, and Ultimate, and is compatible with GitLab.com, GitLab Self-Managed, and GitLab Dedicated offerings. The primary function of this deployment is to configure the runner to utilize the Kubernetes executor. This specific executor type is critical because it allows the runner to provision a fresh, isolated pod within a designated Kubernetes namespace for every individual CI/CD job. This ephemeral nature ensures that every job starts with a clean slate, preventing the "poisoned runner" phenomenon where leftover artifacts or processes from a previous job interfere with the current execution.

Essential Prerequisites for Deployment

Before attempting a Helm-based installation, several environmental requirements must be satisfied to ensure a successful deployment:

  • The GitLab server's API must be reachable from the Kubernetes cluster where the runner will reside.
  • The cluster must be running Kubernetes version 1.4 or later, with beta APIs enabled.
  • The kubectl Command Line Interface (CLI) must be installed locally on the administrator's machine.
  • The administrator must be authenticated with the target Kubernetes cluster.

Helm Installation Workflow

To execute the deployment, the GitLab Helm repository must first be added to the local Helm configuration. If an administrator is utilizing the older Helm 2 architecture, an initialization step is required, whereas Helm 3 users proceed directly to installation.

The following sequence of operations outlines the standard deployment procedure:

  1. Add the official GitLab Helm repository to the local environment:
    helm repo add gitlab https://charts.gitlab.io

  2. If utilizing Helm 2, initialize the repository:
    helm init

  3. Search the repository to verify available versions:
    helm search repo -l gitlab/gitlab-runner

  4. If the desired versions are not visible, update the local repository cache:
    helm repo update gitlab

  5. Perform the installation using the desired configuration file.

For Helm 2 users, the command structure is:
helm install --namespace <NAMESPACE> --name gitlab-runner -f <CONFIG_VALUES_FILE> gitlab/gitlab-runner

For Helm 3 users, the command structure is:
helm install --namespace <NAMESPACE> gitlab-runner -f <CONFIG_VALUES_FILE> gitlab/gitlab-runner

It is vital to note that users can specify a specific chart version to ensure compatibility, especially since GitLab Runner and its Helm charts do not strictly follow the same versioning logic. To target a specific version, the following flag must be appended:
--version <RUNNER_HELM_CHART_VERSION>

Configuration via values.yaml

The values.yaml file is the central nervous system of the Helm deployment. It allows for the override of default chart settings to meet specific organizational requirements. For the runner to function correctly, certain parameters are non-negotiable.

Parameter Description Requirement
gitlabUrl The full URL of the GitLab server (e.g., https://gitlab.example.com) Mandatory
runnerToken The authentication token generated from the GitLab UI Mandatory
rbac.create Determines if RBAC rules should be created for pod provisioning Mandatory (typically true)
serviceAccount.create Determines if a new service account should be created Optional

If an organization prefers to use an existing service account rather than allowing the chart to create a new one, the configuration must reflect this:
yaml rbac: create: false serviceAccount: create: false name: your-service-account

The runnerToken can be provided directly within this file or, for enhanced security, stored within a Kubernetes secret and referenced accordingly.

Managing the Runner Lifecycle

Once deployed, the runner must be managed through standard Helm commands. To update the runner to a specific version, the upgrade command is utilized:
helm upgrade --version <RUNNER_HELM_CHART_VERSION> gitlab-runner -f <CONFIG_VALUES_FILE>

To decommission the runner, it is a best practice to first pause the runner within the GitLab UI. This ensures that all currently running jobs complete successfully and prevents authorization errors during job teardown. Once the runner is paused, the following command removes the deployment:
helm delete --namespace <NAMESPACE> <RELEASE-NAME>

The GitLab Agent for Kubernetes and kubectl Integration

While the GitLab Runner executes the code, the GitLab Agent for Kubernetes provides the secure communication channel that allows kubectl to interact with the cluster. This agent acts as a proxy, enabling CI/CD pipelines to perform cluster operations like deploying manifests, scaling deployments, or managing services.

Secure Connection Architecture

The integration relies on a distinct security model. Each agent possesses its own unique Kubernetes context (kubecontext). Access is restricted by default; only the specific project where the agent is configured has the inherent right to access the cluster. This "least privilege" approach ensures that a compromise in one project does not automatically grant access to the cluster via the agent.

To enable wider access, administrators can configure instance-level authorization. This is a feature available for GitLab Self-Managed instances.

Enabling Instance-Level Authorization

To allow the agent to be accessed by all projects within a GitLab instance, an administrator must follow these steps:

  1. Navigate to the Admin area.
  2. Select Settings > General.
  3. Expand the "GitLab agent for Kubernetes" section.
  4. Enable "Enable instance level authorization".
  5. Save the changes.
  6. Update the application setting:
    organization_cluster_agent_authorization_enabled=true

Once instance-level authorization is enabled, the agent's configuration file (config.yaml) must be modified to permit access. Under the ci_access keyword, the instance attribute must be added:
yaml ci_access: instance: {}

After this configuration is applied, all CI/CD jobs across every project in the instance are authorized to access the agent. For fine-grained control, GitLab provides RBAC-based impersonation to restrict or grant specific access levels even when instance-level authorization is active.

Executing kubectl Commands in CI/CD

When a job is authorized to use an agent, GitLab automatically injects a kubeconfig file into the runner's environment. This file contains the necessary contexts for every shared agent connection authorized for that job. The location of this file is dynamically assigned to the $KUBECONFIG environment variable.

To utilize kubectl within a .gitlab-ci.yml pipeline, the user must explicitly select the agent's context. The syntax for this selection is:
<path/to/agent/project>:<agent-name>

Pipeline Configuration Example

A typical .gitlab-ci.yml file designed to deploy a manifest to a Kubernetes cluster using the agent would look like the following:

yaml deploy_job: stage: deploy script: - kubectl config use-context path/to/my-agent-project:my-agent-name - kubectl apply -f deployment.yaml

In this workflow, the first command in the script section is critical; it switches the kubectl client from its default state to the specific context provided by the GitLab agent. This transition is what enables the subsequent kubectl commands to target the correct Kubernetes API server.

Comparative Analysis of Runner and Agent Roles

Understanding the distinction between the Runner and the Agent is fundamental to troubleshooting and designing CI/CD architectures. While they work together, their responsibilities are mutually exclusive.

Feature GitLab Runner GitLab Agent for Kubernetes
Primary Purpose Executes the CI/CD job scripts and logic. Provides a secure tunnel/context for cluster access.
Execution Location Can be anywhere (Local, Cloud, or in the Cluster). Must be installed within the target Kubernetes cluster.
Kubernetes Interaction Uses the Kubernetes executor to spawn pods. Provides the kubeconfig and kubectl context.
Security Boundary Isolated by namespaces and pod security policies. Isolated by project authorization and RBAC.

The Runner is the "muscle" that performs the computation, while the Agent is the "gateway" that provides the authorization to touch the cluster infrastructure. It is a common misconception that the Runner must reside in the same cluster as the Agent; in reality, the Runner can be hosted on a completely different infrastructure, provided it has the authorized kubeconfig to communicate with the Agent.

Technical Analysis of Operational Security and Troubleshooting

The integration of kubectl and GitLab Runner introduces several layers of complexity regarding security and connectivity.

RBAC and Service Account Permissions

When the Runner is deployed using the Helm chart, the rbac.create: true setting is pivotal. This setting instructs Helm to create the necessary ClusterRoles and RoleBindings that allow the Runner's service account to interact with the Kubernetes API. Specifically, the service account needs permission to create, list, and delete pods within its namespace to facilitate the Kubernetes executor's job lifecycle.

If a user attempts to use an existing service account, they must ensure that the existing account has been pre-configured with sufficient permissions. Failure to do so will result in the Runner being unable to spin up job pods, leading to "permission denied" errors in the Runner logs.

Troubleshooting Connection Failures

If kubectl commands fail within a CI/CD pipeline, the investigation should follow a structured path:

  1. Context Verification: Check if the kubectl config use-context command was successful. If the context name is incorrect, the runner will not find the agent.
  2. Environment Variable Validation: Verify that the $KUBECONFIG variable is present and points to a valid file.
  3. Authorization Check: Ensure the project has been granted access to the agent via the config.yaml or instance-level settings.
  4. Network Connectivity: Confirm that the Runner (wherever it is hosted) can reach the Kubernetes API server through the Agent's tunnel.

Advanced Implementation Considerations

For large-scale enterprise environments, the deployment of GitLab Runners and Agents requires moving beyond default configurations toward highly optimized, secure patterns.

Scaling the Runner via Kubernetes Executor

The Kubernetes executor is inherently scalable. As CI/CD demand increases, the Kubernetes scheduler handles the distribution of runner pods across the available nodes in the cluster. To optimize this, administrators should consider:

  • Resource Requests and Limits: Defining precise CPU and memory requests/limits in the values.yaml to prevent runner pods from consuming excessive cluster resources or being evicted due to OOM (Out of Memory) events.
  • Node Selectors and Affinity: Using nodeSelector or affinity within the Helm configuration to ensure that runner pods are scheduled on specific node pools (e.g., high-memory nodes or nodes with specific GPU capabilities).

Secure Secret Management

While the runnerToken can be placed in values.yaml, this is not a best practice for production environments. A more secure approach involves:

  • Kubernetes Secrets: Storing the runnerToken in a Kubernetes secret and configuring the Helm chart to pull the token from that secret rather than a plaintext value.
  • GitLab CI/CD Variables: Using masked and protected variables in GitLab to pass sensitive information to the runner during job execution.

Conclusion

The integration of GitLab Runner and kubectl through the GitLab Agent for Kubernetes creates a powerful, unified pipeline for modern cloud-native development. By utilizing the Helm chart for deployment, organizations gain the ability to manage runners as scalable, ephemeral entities that leverage the full power of the Kubernetes executor. The subsequent use of the GitLab Agent provides a controlled, secure, and highly granular method for executing kubectl commands, moving away from the risks of long-lived, manually managed credentials.

Successfully mastering this workflow requires a deep understanding of the interplay between Helm configuration, Kubernetes RBAC, and the agent's authorization model. As organizations move toward more complex microservices architectures, the ability to programmatically and securely orchestrate cluster workloads via GitLab's integrated CI/CD ecosystem becomes a critical competency for DevOps engineers. The shift from manual cluster management to an automated, agent-based deployment model represents the transition from traditional operations to a true GitOps paradigm.

Sources

  1. GitLab Runner Helm chart
  2. Using GitLab CI/CD with a Kubernetes cluster

Related Posts