From 3c8aab4cc5acb651b5327d955cb84e6e179bd5b5 Mon Sep 17 00:00:00 2001 From: domverse Date: Sat, 20 Jun 2026 12:30:35 +0200 Subject: [PATCH] ci: migrate to Portainer Git stack + registry-pushed images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Compose: build → image (Gitea registry ci namespace) for backend + frontend - Workflow: build + push both + POST Portainer webhook (3-attempt retry) - Drop docker compose up on host - Add crowdsec@file to middlewares chain Repo secrets required: REGISTRY_TOKEN, PORTAINER_WEBHOOK_URL. Rollback branch: pre-portainer-migration. --- .gitea/workflows/deploy.yml | 69 +++++++++++++++------------- flight-comparator/docker-compose.yml | 22 +++------ 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 91c0c78..b1a3200 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -1,27 +1,11 @@ -# ────────────────────────────────────────────────────────────────────────────── # Flight Radar — Gitea Actions CI/CD # -# PREREQUISITES (one-time setup — see README for full instructions): +# Build backend + frontend images, push to Gitea registry, trigger Portainer +# redeploy via webhook. Stack managed by Portainer (type=git). # -# 1. Add the act_runner service to your Gitea Portainer stack. -# -# 2. Pre-create the runner config file on the host: -# /srv/docker/traefik/stacks/gitea/volumes/act_runner/config.yaml -# (see content in the README / deployment docs) -# -# 3. Start the runner, then grab the registration token from: -# Gitea → Site Administration → Runners → Create Runner -# Add ACT_RUNNER_TOKEN to Portainer stack environment variables. -# -# 4. Give the runner access to Docker (socket mounted via config.yaml). -# -# PIPELINE BEHAVIOUR: -# • Triggers on every push to the default branch (main). -# • Builds both Docker images on the server (no registry needed). -# • Brings the app up with docker compose; only changed services restart. -# • If the build fails the old containers keep running — no downtime. -# • Prunes dangling images after a successful deploy. -# ────────────────────────────────────────────────────────────────────────────── +# Repo secrets required: +# REGISTRY_TOKEN ci user token, scope write:package +# PORTAINER_WEBHOOK_URL POST URL from Portainer stack auto-update setting name: Deploy @@ -29,25 +13,48 @@ on: push: branches: - main - workflow_dispatch: + workflow_dispatch: + env: - COMPOSE_PROJECT: flight-radar - COMPOSE_FILE: flight-comparator/docker-compose.yml + BACKEND_IMAGE: git.domverse-berlin.eu/ci/ciaovolo/backend + FRONTEND_IMAGE: git.domverse-berlin.eu/ci/ciaovolo/frontend + CONTEXT: flight-comparator jobs: deploy: - runs-on: ubuntu-latest # resolved to catthehacker/ubuntu:act-22.04 by runner config + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Deploy with docker compose + - name: Login to Gitea registry + run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.domverse-berlin.eu -u ci --password-stdin + + - name: Build and push backend run: | - echo "=== Deploying commit ${{ gitea.sha }} to ${{ gitea.ref_name }} ===" - docker compose -f "$COMPOSE_FILE" -p "$COMPOSE_PROJECT" up --build -d --remove-orphans + docker build -f "$CONTEXT/Dockerfile.backend" \ + -t "$BACKEND_IMAGE:latest" -t "$BACKEND_IMAGE:${{ gitea.sha }}" \ + "$CONTEXT" + docker push "$BACKEND_IMAGE:latest" + docker push "$BACKEND_IMAGE:${{ gitea.sha }}" + + - name: Build and push frontend + run: | + docker build -f "$CONTEXT/Dockerfile.frontend" \ + -t "$FRONTEND_IMAGE:latest" -t "$FRONTEND_IMAGE:${{ gitea.sha }}" \ + "$CONTEXT" + docker push "$FRONTEND_IMAGE:latest" + docker push "$FRONTEND_IMAGE:${{ gitea.sha }}" + + - name: Trigger Portainer redeploy (retry on transient pull-lease failure) + run: | + for i in 1 2 3; do + code=$(curl -sk -X POST -o /dev/null -w '%{http_code}' "${{ secrets.PORTAINER_WEBHOOK_URL }}") + echo "attempt $i -> $code" + [ "$code" = "204" ] && exit 0 + sleep 5 + done + exit 1 - name: Prune dangling images run: docker image prune -f - - - name: Show running containers - run: docker compose -f "$COMPOSE_FILE" -p "$COMPOSE_PROJECT" ps diff --git a/flight-comparator/docker-compose.yml b/flight-comparator/docker-compose.yml index e6accbe..75d2f6a 100644 --- a/flight-comparator/docker-compose.yml +++ b/flight-comparator/docker-compose.yml @@ -1,10 +1,8 @@ -name: flight-radar # pins the project name — must match COMPOSE_PROJECT in .gitea/workflows/deploy.yml +name: flight-radar services: backend: - build: - context: . - dockerfile: Dockerfile.backend + image: git.domverse-berlin.eu/ci/ciaovolo/backend:${TAG:-latest} container_name: flight-radar-backend restart: unless-stopped environment: @@ -16,37 +14,31 @@ services: networks: - default - domverse - # No ports exposed — only reachable by the frontend via nginx proxy frontend: - build: - context: . - dockerfile: Dockerfile.frontend + image: git.domverse-berlin.eu/ci/ciaovolo/frontend:${TAG:-latest} container_name: flight-radar-frontend restart: unless-stopped depends_on: - backend networks: - - default # shares default compose network with backend (nginx → http://backend:8000) - - domverse # Traefik discovers the container on this network + - default + - domverse labels: - # Traefik routing - "traefik.docker.network=domverse" - "traefik.enable=true" - "traefik.http.routers.flight-radar.rule=Host(`flights.domverse-berlin.eu`)" - "traefik.http.routers.flight-radar.entrypoints=https" - "traefik.http.routers.flight-radar.tls.certresolver=http" - - "traefik.http.routers.flight-radar.middlewares=authentik@docker" + - "traefik.http.routers.flight-radar.middlewares=crowdsec@file,authentik@docker" - "traefik.http.services.flight-radar.loadbalancer.server.port=80" - # AutoKuma monitoring - "kuma.flight-radar.http.name=Flight Radar" - "kuma.flight-radar.http.url=https://flights.domverse-berlin.eu" - "kuma.flight-radar.http.interval=60" - "kuma.flight-radar.http.max_retries=2" - "kuma.flight-radar.http.retry_interval=60" - # Homepage dashboard - "homepage.group=Productivity" - "homepage.name=Flight Radar" - "homepage.icon=mdi-airplane" @@ -59,6 +51,6 @@ volumes: driver: local networks: - default: {} # explicit declaration required when any service has a custom networks block + default: {} domverse: external: true