Install GitLab Runner with the Kubernetes executor via Helm: helm repo add gitlab https://charts.gitlab.io && helm install gitlab-runner gitlab/gitlab-runner --set gitlabUrl=https://gitlab.com --set runnerToken=<TOKEN> --namespace gitlab-runner
Configure config.toml (via Helm values runners.config) to set [runners.kubernetes] with namespace, image, cpu_request, cpu_limit, memory_request, memory_limit for the build container
Set namespace_per_job = true (or per_job_namespace_labels) in the runner config so each CI job receives an isolated Kubernetes namespace, enabling resource cleanup via namespace deletion
In .gitlab-ci.yml set resource_group: <env> on deploy jobs to serialize concurrent deployments to the same environment without manual locking
Define image: and services: at the job level to override the default executor image; the Kubernetes executor launches services as additional containers in the same pod
Use variables: KUBERNETES_CPU_REQUEST, KUBERNETES_MEMORY_LIMIT etc. at the job or pipeline level to override executor resource settings per job without changing runner config
Known gotchas
The Kubernetes executor does not support Docker-in-Docker (dind) with the default container runtime unless privileged mode is enabled on the runner pod; use Kaniko or BuildKit in rootless mode for image builds instead
namespace_per_job requires the runner's ServiceAccount to have permission to create and delete namespaces; missing ClusterRole bindings for this are a common misconfiguration
GitLab CI timeout defaults to 1 hour at the project level; if a job exceeds this, the runner signals the pod to terminate but Kubernetes may not clean up the namespace immediately, leaving orphaned resources
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp