Runners en Kubernetes

Por: Artiko
gitlabrunnerskuberneteshelmk8s

Runners en Kubernetes

Por que Kubernetes

Instalacion con Helm

Agregar repositorio

helm repo add gitlab https://charts.gitlab.io
helm repo update

Crear namespace

kubectl create namespace gitlab-runner

Valores de configuracion

# values.yaml
gitlabUrl: https://gitlab.com/
runnerToken: "glrt-xxxxxxxxxxxx"

runners:
  config: |
    [[runners]]
      [runners.kubernetes]
        namespace = "gitlab-runner"
        image = "alpine:latest"
        cpu_request = "250m"
        cpu_limit = "1"
        memory_request = "256Mi"
        memory_limit = "1Gi"
        service_cpu_request = "100m"
        service_memory_request = "128Mi"
        [runners.kubernetes.pod_labels]
          app = "gitlab-ci"
        [runners.kubernetes.pod_annotations]
          "prometheus.io/scrape" = "true"

concurrent: 10
checkInterval: 5

rbac:
  create: true
  clusterWideAccess: false

serviceAccount:
  create: true
  name: "gitlab-runner"

Instalar

helm install gitlab-runner gitlab/gitlab-runner \
  -n gitlab-runner \
  -f values.yaml

Verificar

kubectl get pods -n gitlab-runner
kubectl logs -f deployment/gitlab-runner -n gitlab-runner

Configuracion de recursos por job

En .gitlab-ci.yml puedes sobreescribir limites:

heavy_build:
  tags:
    - kubernetes
  variables:
    KUBERNETES_CPU_REQUEST: "2"
    KUBERNETES_CPU_LIMIT: "4"
    KUBERNETES_MEMORY_REQUEST: "2Gi"
    KUBERNETES_MEMORY_LIMIT: "4Gi"
  script:
    - make build

Volumenes

EmptyDir (temporal por job)

# values.yaml
runners:
  config: |
    [[runners]]
      [runners.kubernetes]
        [[runners.kubernetes.volumes.empty_dir]]
          name = "build-cache"
          mount_path = "/cache"

PVC (persistente entre jobs)

runners:
  config: |
    [[runners]]
      [runners.kubernetes]
        [[runners.kubernetes.volumes.pvc]]
          name = "ci-cache"
          mount_path = "/cache"

Docker-in-Docker en Kubernetes

Opcion 1: DinD con sidecar

build_image:
  image: docker:24
  services:
    - docker:24-dind
  variables:
    DOCKER_HOST: tcp://localhost:2376
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Requiere privileged = true en el runner (riesgo de seguridad).

Opcion 2: Kaniko (sin privilegios)

build_image:
  image:
    name: gcr.io/kaniko-project/executor:latest
    entrypoint: [""]
  script:
    - /kaniko/executor
      --context $CI_PROJECT_DIR
      --dockerfile Dockerfile
      --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Kaniko no necesita Docker daemon ni modo privilegiado. Es la opcion recomendada.

Troubleshooting

Pod no inicia

kubectl describe pod <pod-name> -n gitlab-runner
kubectl get events -n gitlab-runner --sort-by='.lastTimestamp'

Errores comunes

ErrorCausaSolucion
ImagePullBackOffImagen no existe o sin permisosVerificar nombre de imagen y pull secrets
OOMKilledJob excede memoriaAumentar memory_limit
EvictedNodo sin recursosAjustar requests o agregar nodos
CrashLoopBackOffRunner no conecta a GitLabVerificar URL y token

Actualizar runner

helm upgrade gitlab-runner gitlab/gitlab-runner \
  -n gitlab-runner \
  -f values.yaml

Siguiente: Capitulo 11: Monitoreo, Troubleshooting y Buenas Practicas →