From feac66dcd053cbb52fa3ffd7f8ca2f788350a623 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 8 Mar 2026 19:46:46 -0400 Subject: [PATCH] Scope CI/CD to build+test only; clean up runner infra MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove automated deploy — Portainer handles deployments for now. build.yml: deploy job removed, only builds and pushes image to registry. infra/runner-compose.yml: clean standalone Portainer stack for act_runner, no swarm network dependency, uses external Forgejo URL. infra/runner-swarm.yml: removed (replaced by runner-compose.yml). Co-Authored-By: Claude Sonnet 4.6 --- .forgejo/workflows/build.yml | 42 +++---------- infra/act-runner-config.yml | 20 +++---- infra/runner-compose.yml | 25 ++++++++ infra/runner-swarm.yml | 113 ----------------------------------- 4 files changed, 43 insertions(+), 157 deletions(-) create mode 100644 infra/runner-compose.yml delete mode 100644 infra/runner-swarm.yml diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index d5965b6..a0b0cf6 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -1,13 +1,15 @@ # Runs only on pushes to main. +# Builds the Docker image and pushes it to the Forgejo container registry. +# Registry-side layer caching means unchanged layers (npm install, pip install) +# are reused between builds — typically cuts build time from ~4 min to ~45 sec. # -# The runner runs in the same swarm as Forgejo with /var/run/docker.sock mounted, -# so it can build images and update swarm services directly — no SSH needed. +# The resulting image can then be deployed manually via Portainer. # # Required secrets (repo → Settings → Secrets → Actions): -# REGISTRY_USER — your Forgejo username -# REGISTRY_TOKEN — Forgejo PAT with write:packages scope -# DEPLOY_SERVICE — full swarm service name, e.g. fabledassistant_app -name: Build & Deploy +# REGISTRY_USER — your Forgejo username +# REGISTRY_TOKEN — Forgejo PAT with write:packages scope (create at +# git.fabledsword.com → Settings → Applications → Generate Token) +name: Build & push image on: push: @@ -19,7 +21,7 @@ env: jobs: build: - name: Build & push image + name: Build & push runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -42,31 +44,5 @@ jobs: tags: | ${{ env.IMAGE }}:latest ${{ env.IMAGE }}:${{ github.sha }} - # Registry-side layer cache — unchanged layers (npm install, pip install) - # are reused between builds. Cuts typical build time from ~4 min to ~45 sec. cache-from: type=registry,ref=${{ env.IMAGE }}:cache cache-to: type=registry,ref=${{ env.IMAGE }}:cache,mode=max - - deploy: - name: Deploy - needs: build - runs-on: ubuntu-latest - steps: - - name: Log in to registry - run: | - echo "${{ secrets.REGISTRY_TOKEN }}" | \ - docker login git.fabledsword.com -u "${{ secrets.REGISTRY_USER }}" --password-stdin - - - name: Update swarm service - # --with-registry-auth forwards the login credentials to all swarm nodes - # so they can pull the new image. --detach=false waits for the rollout to - # complete before the job finishes (shows progress in the Actions log). - run: | - docker service update \ - --image ${{ env.IMAGE }}:${{ github.sha }} \ - --with-registry-auth \ - --detach=false \ - ${{ secrets.DEPLOY_SERVICE }} - - - name: Clean up old images - run: docker image prune -f diff --git a/infra/act-runner-config.yml b/infra/act-runner-config.yml index 103577a..9199a87 100644 --- a/infra/act-runner-config.yml +++ b/infra/act-runner-config.yml @@ -1,15 +1,12 @@ -# act_runner configuration — stored as a Docker Swarm Config object. -# Referenced in runner-swarm.yml under configs.act_runner_config. -# -# After changing this file, update the swarm config: -# docker config rm act_runner_config -# docker stack deploy -c forgejo-stack.yml forgejo (or docker compose up -d) +# act_runner configuration. +# Place this file at: /nfs/data/fabledsword/act_runner/config.yml +# It is bind-mounted read-only into the runner container. log: level: info runner: - capacity: 2 # concurrent jobs + capacity: 2 # max concurrent jobs timeout: 30m cache: @@ -17,11 +14,12 @@ cache: dir: /data/.cache container: - # bridge: job containers get internet access via NAT but are isolated from - # each other and the swarm overlay. Sufficient for npm/pip/docker push. + # Job containers use bridge networking — they get outbound internet access + # (needed to pull npm/pip packages and push to the registry) but are isolated + # from each other and the host. network: bridge - # Whitelist of host paths that workflow steps are allowed to bind-mount. - # The Docker socket is required for the build and deploy jobs. + # Paths the runner is allowed to bind-mount into job containers. + # The Docker socket is required for the build job (docker buildx). valid_volumes: - /var/run/docker.sock diff --git a/infra/runner-compose.yml b/infra/runner-compose.yml new file mode 100644 index 0000000..3b9fbc8 --- /dev/null +++ b/infra/runner-compose.yml @@ -0,0 +1,25 @@ +# Forgejo Actions runner — deploy as a standalone Portainer stack. +# The runner connects outbound to Forgejo to receive jobs; no inbound ports needed. +# /var/run/docker.sock is mounted so the build job can run Docker Buildx. +# +# Setup: see the walkthrough at infra/RUNNER_SETUP.md + +services: + act_runner: + image: gitea/act_runner:latest + restart: unless-stopped + environment: + - GITEA_INSTANCE_URL=https://git.fabledsword.com + - GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN} + - GITEA_RUNNER_NAME=swarm-runner + # Maps the runs-on: ubuntu-latest label used in workflow files to a Docker image. + - GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bullseye + - CONFIG_FILE=/config/config.yml + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - act_runner_data:/data + - /nfs/data/fabledsword/act_runner/config.yml:/config/config.yml:ro + # No network needed — runner only makes outbound HTTPS connections to Forgejo. + +volumes: + act_runner_data: diff --git a/infra/runner-swarm.yml b/infra/runner-swarm.yml deleted file mode 100644 index 74ad399..0000000 --- a/infra/runner-swarm.yml +++ /dev/null @@ -1,113 +0,0 @@ -# Forgejo Actions runner — add these services to your existing Forgejo stack. -# -# Since the runner is in the same swarm as Forgejo it can: -# - Reach Forgejo at http://forgejo:3000 (no Traefik hop) -# - Use the host Docker socket (manager node) to build images and update services -# - Deploy the app via `docker service update` — no SSH needed -# -# The runner MUST run on a swarm manager node so it can call the Docker service API. -# On a single-node swarm this is automatic. On multi-node, the placement constraint -# below ensures it. -# -# One-time setup: -# 1. Get a registration token: -# https://git.fabledsword.com → Site Administration → Runners → Create Runner -# -# 2. Add RUNNER_TOKEN to your stack's env file (same .env Forgejo uses): -# echo 'RUNNER_TOKEN=your_token_here' >> /path/to/forgejo.env -# -# 3. Redeploy the Forgejo stack to pick up the new services: -# docker stack deploy -c forgejo-stack.yml --with-registry-auth forgejo -# -# Docker Swarm does not support bind-mounts of /var/run/docker.sock via -# `docker stack deploy`. Deploy using docker compose instead (still managed, -# just not as a formal stack): -# docker compose -f forgejo-stack.yml up -d -# -# Required secrets in Forgejo (repo → Settings → Secrets → Actions): -# REGISTRY_USER — your Forgejo username -# REGISTRY_TOKEN — Forgejo PAT with write:packages scope -# DEPLOY_SERVICE — full swarm service name for the app, e.g. fabledassistant_app - -networks: - overlay_proxy: - external: true - fabled_backend: - external: true - -configs: - act_runner_config: - # Swarm Config object — stored in the swarm, injected read-only into the container. - # To update this config you must remove and recreate it: - # docker config rm act_runner_config - # then redeploy the stack. - file: ./act-runner-config.yml - -volumes: - act_runner_data: - -services: - # ── Existing Forgejo service (unchanged, shown for context) ─────────────────── - forgejo: - image: codeberg.org/forgejo/forgejo:14 - environment: - - USER_UID=1000 - - USER_GID=1000 - - FORGEJO__database__DB_TYPE=postgres - - FORGEJO__database__HOST=postgres:5432 - - FORGEJO__database__NAME=forgejo - - FORGEJO__database__USER=forgejo - - FORGEJO__database__PASSWD=${FORGEJO_DB_PW} - networks: - - overlay_proxy - - fabled_backend - volumes: - - /nfs/data/fabledsword/forgejo:/data - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - deploy: - replicas: 1 - labels: - - traefik.http.routers.fabled-git.rule=Host(`git.${BASE_DN}`) - - traefik.http.routers.fabled-git.entrypoints=websecure - - traefik.http.routers.fabled-git.tls=true - - traefik.http.routers.fabled-git.tls.certresolver=letsEncrypt - - traefik.http.services.fabled-git.loadbalancer.server.port=3000 - - traefik.http.routers.fabled-git.middlewares=chain-external-noauth@file - - traefik.enable=true - - traefik.http.services.fabled-git.loadbalancer.serversTransport=reg-xport@file - - # ── New: Forgejo Actions runner ─────────────────────────────────────────────── - act_runner: - image: gitea/act_runner:latest - environment: - # Use the internal service name — avoids Traefik and works even if TLS is down. - - GITEA_INSTANCE_URL=http://forgejo:3000 - - GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN} - - GITEA_RUNNER_NAME=swarm-runner - # Maps the `runs-on: ubuntu-latest` label in workflows to a Docker image. - # node:20-bullseye is used as a general base; the language-specific setup-* - # actions install the correct toolchain on top. - - GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bullseye - - CONFIG_FILE=/config/config.yml - configs: - - source: act_runner_config - target: /config/config.yml - mode: 0444 - volumes: - # The host Docker socket lets the runner build images and call `docker service update`. - # This REQUIRES the runner to be on a manager node (see placement below). - - /var/run/docker.sock:/var/run/docker.sock - - act_runner_data:/data - networks: - # fabled_backend lets the runner reach http://forgejo:3000 - - fabled_backend - deploy: - replicas: 1 - placement: - constraints: - # Must be a manager node to access the full Docker socket API (service updates). - - node.role == manager - restart_policy: - condition: on-failure - delay: 10s