apiVersion: apps/v1 kind: Deployment metadata: labels: app: gitea-runner name: gitea-runner namespace: gitea spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: gitea-runner strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: annotations: kubectl.kubernetes.io/restartedAt: '2026-05-05T09:17:26Z' labels: app: gitea-runner spec: containers: - args: - --host=tcp://0.0.0.0:2375 - --tls=false env: - name: DOCKER_TLS_CERTDIR image: docker:24.0.9-dind imagePullPolicy: IfNotPresent livenessProbe: exec: command: - docker - info failureThreshold: 3 initialDelaySeconds: 20 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 1 name: dind resources: limits: cpu: '2' memory: 4Gi requests: cpu: 500m memory: 2Gi securityContext: privileged: true terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/lib/docker name: dind-storage - mountPath: /etc/docker/daemon.json name: docker-daemon-config subPath: daemon.json - mountPath: /etc/buildkit/buildkitd.toml name: buildkitd-config subPath: buildkitd.toml - args: - | until nc -z localhost 2375 2>/dev/null; do sleep 1; done exec /usr/local/bin/run.sh command: - /bin/sh - -c env: - name: GITEA_INSTANCE_URL value: http://gitea.gitea.svc.cluster.local:3000 - name: GITEA_RUNNER_NAME value: k8s-runner - name: CONFIG_FILE value: /etc/act_runner/config.yaml - name: GITEA_RUNNER_REGISTRATION_TOKEN valueFrom: secretKeyRef: key: GITEA_RUNNER_REGISTRATION_TOKEN name: gitea-runner-secret-infisical - name: DOCKER_HOST value: tcp://localhost:2375 image: gitea/act_runner:0.6.1 imagePullPolicy: Always name: runner resources: limits: cpu: '1' memory: 512Mi requests: cpu: 100m memory: 128Mi terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /data name: runner-data - mountPath: /etc/act_runner name: runner-config # Recolector de imágenes huérfanas. El emptyDir de dind está capado a 10Gi, # pero el GC de dockerd y el de buildkit calculan su umbral contra el disco # del nodo (913G), así que no saltan nunca antes del desalojo. El 2026-08-12 # el pod fue desalojado tras 21 días por eso. Lo que se acumula son imágenes # sin tag: cada vez que upstream republica catthehacker/ubuntu:act-22.04, la # anterior (1,5G) queda colgada y nadie la borra. # prune SIN -a a propósito: borra solo las dangling, jamás una imagen con tag, # así que no vacía la caché de act ni la de buildkit y los builds no se frenan. # Además deja el uso del volumen en su propio log cada vuelta. El emptyDir # muere con el pod, así que tras un desalojo no queda nada que inspeccionar: # el 2026-08-12 hubo que deducir la causa por descarte. Con esto, la próxima # vez `kubectl logs -c janitor` da la curva de crecimiento ya medida. # Prometheus no vale para esto: kubelet_volume_stats_* solo cubre PVCs. - args: - | sleep 30 while true; do antes=$(du -sm /dind 2>/dev/null | cut -f1) docker image prune -f >/dev/null 2>&1 || true ahora=$(du -sm /dind 2>/dev/null | cut -f1) echo "[janitor] $(date -Iseconds) dind ${ahora}MB de 10240MB (antes del barrido ${antes}MB)" sleep 21600 done command: - /bin/sh - -c env: - name: DOCKER_HOST value: tcp://localhost:2375 image: docker:24.0.9-cli imagePullPolicy: IfNotPresent name: janitor resources: limits: cpu: 100m memory: 64Mi requests: cpu: 10m memory: 32Mi volumeMounts: - mountPath: /dind name: dind-storage readOnly: true dnsPolicy: ClusterFirst nodeSelector: kubernetes.io/hostname: chemavx-k8 restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 volumes: - emptyDir: {} name: runner-data - configMap: defaultMode: 420 name: gitea-runner-config name: runner-config - emptyDir: sizeLimit: 10Gi name: dind-storage - configMap: defaultMode: 420 name: docker-daemon-config name: docker-daemon-config - configMap: defaultMode: 420 name: buildkitd-config name: buildkitd-config