# ----------------------------------------------------------------------------- # Gitea act_runner + Docker-in-Docker (DinD) sidecar, running on a k3s node. # # - The `dind` container runs a full dockerd (privileged) and exposes it over # TLS on localhost:2376. Its TLS client certs are shared via an emptyDir. # - The `runner` container registers with Gitea and dispatches each job to the # dockerd inside the same pod, so `docker build` / `docker push` "just work". # # NOTE: DinD requires a privileged container. Keep this in its own namespace # and consider pinning it to a dedicated build node (see nodeSelector). # ----------------------------------------------------------------------------- apiVersion: apps/v1 kind: Deployment metadata: name: act-runner namespace: gitea-runner labels: app: act-runner spec: # Keep at 1: the registered runner state lives in the runner PVC. replicas: 1 strategy: type: Recreate selector: matchLabels: app: act-runner template: metadata: labels: app: act-runner spec: # --- Optionally pin builds to a dedicated node ------------------------- # nodeSelector: # ci-build: "true" # label a node: kubectl label node ci-build=true # tolerations: # - key: "ci-build" # operator: "Exists" # effect: "NoSchedule" # ---------------------------------------------------------------------- containers: # ===================================================================== # Docker-in-Docker daemon # ===================================================================== - name: dind image: docker:27-dind securityContext: privileged: true env: - name: DOCKER_TLS_CERTDIR value: /certs args: - "--host=tcp://0.0.0.0:2376" - "--tlsverify" - "--tlscacert=/certs/ca/cert.pem" - "--tlscert=/certs/server/cert.pem" - "--tlskey=/certs/server/key.pem" volumeMounts: - name: docker-certs mountPath: /certs - name: docker-storage mountPath: /var/lib/docker readinessProbe: exec: command: ["docker", "-H", "tcp://localhost:2376", "--tlsverify", "--tlscacert=/certs/ca/cert.pem", "--tlscert=/certs/client/cert.pem", "--tlskey=/certs/client/key.pem", "info"] initialDelaySeconds: 15 periodSeconds: 10 resources: requests: cpu: "250m" memory: "512Mi" limits: cpu: "2" memory: "4Gi" # ===================================================================== # Gitea Actions runner # ===================================================================== - name: runner image: gitea/act_runner:0.2.11 env: # Registration data (from the Secret). - name: GITEA_INSTANCE_URL valueFrom: secretKeyRef: name: act-runner-registration key: GITEA_INSTANCE_URL - name: GITEA_RUNNER_REGISTRATION_TOKEN valueFrom: secretKeyRef: name: act-runner-registration key: GITEA_RUNNER_REGISTRATION_TOKEN - name: GITEA_RUNNER_NAME valueFrom: fieldRef: fieldPath: metadata.name # Point the runner at the DinD daemon over TLS. - name: DOCKER_HOST value: "tcp://localhost:2376" - name: DOCKER_CERT_PATH value: "/certs/client" - name: DOCKER_TLS_VERIFY value: "1" # Path to the mounted act_runner config. - name: CONFIG_FILE value: "/config/config.yaml" volumeMounts: - name: docker-certs mountPath: /certs readOnly: true - name: runner-config mountPath: /config readOnly: true - name: runner-data mountPath: /data resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "1" memory: "1Gi" volumes: # Shared TLS certs between dockerd and the runner/job containers. - name: docker-certs emptyDir: {} # dockerd image/layer storage (ephemeral; use a PVC for a persistent cache). - name: docker-storage emptyDir: {} - name: runner-config configMap: name: act-runner-config # Persists the runner registration (.runner) across restarts. - name: runner-data persistentVolumeClaim: claimName: act-runner-data --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: act-runner-data namespace: gitea-runner spec: accessModes: - ReadWriteOnce resources: requests: storage: 2Gi # k3s default storage class (local-path). Change if you use another provisioner. # storageClassName: local-path