diff --git a/.forgejo/workflows/build-container.yaml b/.forgejo/workflows/build-container.yaml index 6ed1be8..59291f0 100644 --- a/.forgejo/workflows/build-container.yaml +++ b/.forgejo/workflows/build-container.yaml @@ -15,7 +15,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: k8s steps: - name: Parse tag id: parse diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 12f3259..20281ec 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -1,5 +1,3 @@ self-hosted-runner: labels: - - docker-builder - - ubuntu-latest - - ubuntu-22.04 + - k8s diff --git a/ansible/playbooks/indri.yml b/ansible/playbooks/indri.yml index 44afe2d..9ea46eb 100644 --- a/ansible/playbooks/indri.yml +++ b/ansible/playbooks/indri.yml @@ -61,23 +61,6 @@ no_log: true tags: [forgejo] - # Forgejo runner token (for indri-based runner) - - name: Fetch forgejo runner token - ansible.builtin.command: - cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get w3663ffnvkewbftncqxtcpeavy --fields runner_reg --reveal - delegate_to: localhost - register: _forgejo_runner_token - changed_when: false - no_log: true - check_mode: false - tags: [forgejo_runner] - - - name: Set forgejo runner token fact - ansible.builtin.set_fact: - forgejo_runner_token: "{{ _forgejo_runner_token.stdout }}" - no_log: true - tags: [forgejo_runner] - # Caddy Gandi token for ACME DNS-01 challenges - name: Fetch Gandi PAT for Caddy ansible.builtin.command: @@ -114,7 +97,5 @@ tags: minikube_metrics - role: plex_metrics tags: plex_metrics - - role: forgejo_runner - tags: forgejo_runner - role: caddy tags: caddy diff --git a/ansible/roles/forgejo_runner/defaults/main.yml b/ansible/roles/forgejo_runner/defaults/main.yml deleted file mode 100644 index 75cbd0c..0000000 --- a/ansible/roles/forgejo_runner/defaults/main.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -# Forgejo Runner - host execution mode -# -# The runner daemon runs directly on indri and executes jobs on the host. -# This avoids container networking complexity since it can reach Forgejo -# at localhost:3001 directly. - -forgejo_runner_binary: /Users/erichblume/code/3rd/forgejo-runner/forgejo-runner -forgejo_runner_data_dir: /Users/erichblume/.forgejo-runner -forgejo_runner_config_dir: /Users/erichblume/.config/forgejo-runner -forgejo_runner_log_dir: /Users/erichblume/Library/Logs - -# Runner registration - use localhost since we're running on indri -forgejo_runner_instance_url: "http://localhost:3001" -forgejo_runner_name: "indri-host-runner" - -# Labels format for host execution: label:host -# Jobs run directly on the host, not in containers -forgejo_runner_labels: "ubuntu-latest:host,ubuntu-22.04:host" - -# Runner config -forgejo_runner_capacity: 2 -forgejo_runner_timeout: 3h diff --git a/ansible/roles/forgejo_runner/handlers/main.yml b/ansible/roles/forgejo_runner/handlers/main.yml deleted file mode 100644 index 8ace37c..0000000 --- a/ansible/roles/forgejo_runner/handlers/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Restart forgejo-runner - listen: Restart forgejo-runner - ansible.builtin.shell: | - launchctl unload ~/Library/LaunchAgents/mcquack.forgejo-runner.plist 2>/dev/null || true - launchctl load ~/Library/LaunchAgents/mcquack.forgejo-runner.plist - changed_when: true diff --git a/ansible/roles/forgejo_runner/tasks/main.yml b/ansible/roles/forgejo_runner/tasks/main.yml deleted file mode 100644 index 0f28d88..0000000 --- a/ansible/roles/forgejo_runner/tasks/main.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- -# Forgejo Runner - host execution mode -# -# The runner daemon runs directly on indri using a locally compiled binary. -# Jobs execute on the host, reaching Forgejo at localhost:3001. - -- name: Ensure forgejo-runner directories exist - ansible.builtin.file: - path: "{{ item }}" - state: directory - mode: '0755' - loop: - - "{{ forgejo_runner_data_dir }}" - - "{{ forgejo_runner_config_dir }}" - -- name: Deploy forgejo-runner config - ansible.builtin.template: - src: config.yaml.j2 - dest: "{{ forgejo_runner_config_dir }}/config.yaml" - mode: '0644' - notify: Restart forgejo-runner - -- name: Check if runner is registered - ansible.builtin.stat: - path: "{{ forgejo_runner_data_dir }}/.runner" - register: forgejo_runner_registered - -- name: Register runner with Forgejo - ansible.builtin.command: - cmd: > - {{ forgejo_runner_binary }} register - --instance "{{ forgejo_runner_instance_url }}" - --token "{{ forgejo_runner_token }}" - --name "{{ forgejo_runner_name }}" - --labels "{{ forgejo_runner_labels }}" - --no-interactive - chdir: "{{ forgejo_runner_data_dir }}" - when: not forgejo_runner_registered.stat.exists - changed_when: true - -- name: Deploy forgejo-runner launchd plist - ansible.builtin.template: - src: forgejo-runner.plist.j2 - dest: ~/Library/LaunchAgents/mcquack.forgejo-runner.plist - mode: '0644' - notify: Restart forgejo-runner - -- name: Check if forgejo-runner is loaded - ansible.builtin.command: launchctl list mcquack.forgejo-runner - register: forgejo_runner_launchctl_check - changed_when: false - failed_when: false - -- name: Load forgejo-runner if not loaded - ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.forgejo-runner.plist - when: forgejo_runner_launchctl_check.rc != 0 - changed_when: true diff --git a/ansible/roles/forgejo_runner/templates/config.yaml.j2 b/ansible/roles/forgejo_runner/templates/config.yaml.j2 deleted file mode 100644 index 07bdb8d..0000000 --- a/ansible/roles/forgejo_runner/templates/config.yaml.j2 +++ /dev/null @@ -1,13 +0,0 @@ -# {{ ansible_managed }} -log: - level: info - -runner: - file: {{ forgejo_runner_data_dir }}/.runner - capacity: {{ forgejo_runner_capacity }} - timeout: {{ forgejo_runner_timeout }} - -# Even in host execution mode, some actions run in containers. -# Use host networking so containers can access localhost services. -container: - network: "host" diff --git a/ansible/roles/forgejo_runner/templates/forgejo-runner.plist.j2 b/ansible/roles/forgejo_runner/templates/forgejo-runner.plist.j2 deleted file mode 100644 index e04fa0d..0000000 --- a/ansible/roles/forgejo_runner/templates/forgejo-runner.plist.j2 +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - Label - mcquack.forgejo-runner - ProgramArguments - - {{ forgejo_runner_binary }} - daemon - --config - {{ forgejo_runner_config_dir }}/config.yaml - - WorkingDirectory - {{ forgejo_runner_data_dir }} - EnvironmentVariables - - PATH - /Users/erichblume/.local/share/mise/shims:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin - HOME - /Users/erichblume - - RunAtLoad - - KeepAlive - - StandardOutPath - {{ forgejo_runner_log_dir }}/mcquack.forgejo-runner.out.log - StandardErrorPath - {{ forgejo_runner_log_dir }}/mcquack.forgejo-runner.err.log - - diff --git a/argocd/apps/forgejo-runner.yaml b/argocd/apps/forgejo-runner.yaml new file mode 100644 index 0000000..5bca762 --- /dev/null +++ b/argocd/apps/forgejo-runner.yaml @@ -0,0 +1,17 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: forgejo-runner + namespace: argocd +spec: + project: default + source: + repoURL: https://forge.ops.eblu.me/eblume/blumeops.git + targetRevision: main + path: argocd/manifests/forgejo-runner + destination: + server: https://kubernetes.default.svc + namespace: forgejo-runner + syncPolicy: + syncOptions: + - CreateNamespace=true diff --git a/argocd/manifests/forgejo-runner/configmap.yaml b/argocd/manifests/forgejo-runner/configmap.yaml new file mode 100644 index 0000000..dd3c3ef --- /dev/null +++ b/argocd/manifests/forgejo-runner/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: forgejo-runner-config + namespace: forgejo-runner +data: + config.yaml: | + log: + level: info + + runner: + file: /data/.runner + capacity: 2 + timeout: 3h + # Set DOCKER_HOST in job containers so they can run docker commands + envs: + DOCKER_HOST: tcp://127.0.0.1:2375 + + container: + # Use our custom job execution image with Node.js + Docker CLI + network: "host" + # Connect to DinD sidecar via TCP (not socket) + docker_host: tcp://127.0.0.1:2375 diff --git a/argocd/manifests/forgejo-runner/deployment.yaml b/argocd/manifests/forgejo-runner/deployment.yaml new file mode 100644 index 0000000..28d2c65 --- /dev/null +++ b/argocd/manifests/forgejo-runner/deployment.yaml @@ -0,0 +1,77 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: forgejo-runner + namespace: forgejo-runner + labels: + app: forgejo-runner +spec: + replicas: 1 + selector: + matchLabels: + app: forgejo-runner + template: + metadata: + labels: + app: forgejo-runner + spec: + containers: + # Forgejo runner daemon + - name: runner + image: code.forgejo.org/forgejo/runner:6.3.1 + env: + - name: DOCKER_HOST + value: tcp://localhost:2375 + command: + - /bin/sh + - -c + - | + # Wait for DinD to be ready + echo "Waiting for Docker daemon..." + while ! wget -q -O /dev/null http://localhost:2375/_ping 2>/dev/null; do + sleep 1 + done + echo "Docker daemon ready" + + # Register if not already registered + if [ ! -f /data/.runner ]; then + echo "Registering runner..." + forgejo-runner register \ + --instance "$FORGEJO_URL" \ + --token "$RUNNER_TOKEN" \ + --name "$RUNNER_NAME" \ + --labels "$RUNNER_LABELS" \ + --no-interactive + fi + + # Start daemon + exec forgejo-runner daemon --config /config/config.yaml + envFrom: + - secretRef: + name: forgejo-runner-env + volumeMounts: + - name: data + mountPath: /data + - name: config + mountPath: /config + + # Docker-in-Docker sidecar + - name: dind + image: docker:27-dind + securityContext: + privileged: true + env: + - name: DOCKER_TLS_CERTDIR + value: "" + volumeMounts: + - name: dind-storage + mountPath: /var/lib/docker + + volumes: + - name: data + emptyDir: {} + - name: dind-storage + emptyDir: {} + - name: config + configMap: + name: forgejo-runner-config diff --git a/argocd/manifests/forgejo-runner/namespace.yaml b/argocd/manifests/forgejo-runner/namespace.yaml new file mode 100644 index 0000000..19441b1 --- /dev/null +++ b/argocd/manifests/forgejo-runner/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: forgejo-runner diff --git a/argocd/manifests/forgejo-runner/secret.yaml.tpl b/argocd/manifests/forgejo-runner/secret.yaml.tpl new file mode 100644 index 0000000..b24029a --- /dev/null +++ b/argocd/manifests/forgejo-runner/secret.yaml.tpl @@ -0,0 +1,17 @@ +# Forgejo Runner Environment Secret +# This template is processed by `op inject` to resolve 1Password references. +# +# Usage: +# op inject -i secret.yaml.tpl | kubectl --context=minikube-indri apply -f - +# +apiVersion: v1 +kind: Secret +metadata: + name: forgejo-runner-env + namespace: forgejo-runner +type: Opaque +stringData: + FORGEJO_URL: "https://forge.ops.eblu.me" + RUNNER_NAME: "k8s-runner" + RUNNER_LABELS: "k8s:docker://registry.ops.eblu.me/blumeops/forgejo-runner:v2.1.7" + RUNNER_TOKEN: "{{ op://vg6xf6vvfmoh5hqjjhlhbeoaie/w3663ffnvkewbftncqxtcpeavy/runner_reg }}" diff --git a/containers/forgejo-runner/Dockerfile b/containers/forgejo-runner/Dockerfile new file mode 100644 index 0000000..dcdcc78 --- /dev/null +++ b/containers/forgejo-runner/Dockerfile @@ -0,0 +1,41 @@ +# Forgejo Actions Job Execution Image +# +# This image is used as the job execution environment for Forgejo Actions. +# The host runner daemon creates containers from this image to run workflow steps. +# +# Includes: Node.js (for GitHub Actions), Docker CLI, git, and common CI tools. +# +# Usage: Configure runner with label like: +# docker:docker://registry.ops.eblu.me/blumeops/forgejo-runner:latest + +FROM debian:bookworm-slim + +ARG TARGETARCH + +# Install base dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + git \ + jq \ + gnupg \ + lsb-release \ + xz-utils \ + && rm -rf /var/lib/apt/lists/* + +# Install Node.js 20.x (required for actions/checkout@v4 and other GitHub Actions) +RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ + && apt-get install -y --no-install-recommends nodejs \ + && rm -rf /var/lib/apt/lists/* + +# Install Docker CLI (for container builds - daemon accessed via socket mount) +RUN install -m 0755 -d /etc/apt/keyrings \ + && curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc \ + && chmod a+r /etc/apt/keyrings/docker.asc \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends docker-ce-cli \ + && rm -rf /var/lib/apt/lists/* + +# Default to bash +CMD ["/bin/bash"]