initial commit

This commit is contained in:
2026-08-27 10:46:36 +02:00
commit 993e5c7327
11 changed files with 591 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: gitea-runner
labels:
app.kubernetes.io/name: gitea-act-runner
app.kubernetes.io/part-of: ci-cd
+23
View File
@@ -0,0 +1,23 @@
# -----------------------------------------------------------------------------
# Gitea act_runner registration secret.
#
# 1. Copy this file: cp 10-runner-secret.yaml.example 10-runner-secret.yaml
# 2. Fill in the two stringData values below.
# 3. Apply: kubectl apply -f 10-runner-secret.yaml
#
# GITEA_INSTANCE_URL : Base URL of your Gitea server (no trailing /actions).
# GITEA_RUNNER_REGISTRATION_TOKEN :
# Token from Gitea -> (Site Admin | Org | Repo) -> Actions -> Runners
# -> "Create new Runner".
#
# The runner registers itself on first start using these values.
# -----------------------------------------------------------------------------
apiVersion: v1
kind: Secret
metadata:
name: act-runner-registration
namespace: gitea-runner
type: Opaque
stringData:
GITEA_INSTANCE_URL: "https://gitea.example.com"
GITEA_RUNNER_REGISTRATION_TOKEN: "REPLACE_WITH_REGISTRATION_TOKEN"
+38
View File
@@ -0,0 +1,38 @@
# -----------------------------------------------------------------------------
# act_runner configuration, mounted into the runner container as config.yaml.
# Docs: https://docs.gitea.com/usage/actions/act-runner
# -----------------------------------------------------------------------------
apiVersion: v1
kind: ConfigMap
metadata:
name: act-runner-config
namespace: gitea-runner
data:
config.yaml: |
log:
level: info
runner:
# Max parallel jobs this runner will execute.
capacity: 2
timeout: 3h
# Labels advertise which job environments this runner provides.
# The workflow selects one with `runs-on:`.
labels:
- "ubuntu-latest:docker://catthehacker/ubuntu:act-22.04"
- "ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04"
- "dind:docker://catthehacker/ubuntu:act-22.04"
cache:
enabled: true
container:
# Talk to the DinD sidecar over TCP (TLS) instead of a mounted socket.
docker_host: "tcp://localhost:2376"
# Job containers join the default docker network created by dockerd.
network: "host"
# Keep pulled images between jobs to speed builds up.
force_pull: false
# Give job containers access to the DinD TLS certs.
valid_volumes:
- "**"
+153
View File
@@ -0,0 +1,153 @@
# -----------------------------------------------------------------------------
# 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 <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
+29
View File
@@ -0,0 +1,29 @@
# -----------------------------------------------------------------------------
# OPTIONAL: cluster-side Harbor pull secret.
#
# This is NOT needed for the CI build/push (that uses Gitea Actions secrets).
# Create it only if the same k3s cluster must *pull* the private images that the
# pipeline pushes to Harbor (e.g. when you later deploy those images here).
#
# Easiest way to create it (recommended over editing this file by hand):
#
# kubectl create secret docker-registry harbor-pull \
# --namespace <your-app-namespace> \
# --docker-server=harbor.example.com \
# --docker-username='robot$ci' \
# --docker-password='REPLACE_WITH_ROBOT_TOKEN'
#
# Then reference it from your workloads:
# spec.imagePullSecrets: [{ name: harbor-pull }]
#
# The manifest below is the equivalent declarative form (base64 dockerconfigjson).
# -----------------------------------------------------------------------------
apiVersion: v1
kind: Secret
metadata:
name: harbor-pull
namespace: default
type: kubernetes.io/dockerconfigjson
data:
# echo -n '{"auths":{"harbor.example.com":{"username":"robot$ci","password":"TOKEN","auth":"<base64 user:pass>"}}}' | base64 -w0
.dockerconfigjson: REPLACE_WITH_BASE64_DOCKERCONFIGJSON