Saltar a contenido

Forgejo Actions — CI/CD de SmallCountry

Sistema de integración continua y despliegue automatizado

Cada push a main con cambios en la documentación lanza un pipeline que compila, valida y despliega el sitio en Caddy. Todo corre dentro de una imagen Docker personalizada alojada en el registro OCI de Forgejo, sin depender de internet.


1. Arquitectura

flowchart LR
    Push["git push<br/>rama main"] --> Forgejo["Forgejo instance<br/>forgejo-sc.duckdns.org"]
    Forgejo --> Workflow["Busca workflow<br/>.forgejo/workflows/docs-ci.yml"]
    Workflow --> Runner["Asigna tarea al<br/>casita-runner"]
    Runner --> Docker["Arranca contenedor<br/>forgejo-sc.duckdns.org/smallcountry/ci-docs:latest"]
    Docker --> Steps["Ejecuta 6 pasos<br/>Checkout → Build → Deploy → Links → Metadata → Huérfanas"]
    Steps --> Deploy["Copia web/site/*<br/>al directorio servido por Caddy"]
    Deploy --> Caddy["Caddy sirve el sitio<br/>https://tonatiuh.duckdns.org"]
    Steps --> Report["Reporta resultado<br/>a Forgejo"]
Componente Dónde está Qué hace
Forgejo Docker (localhost:3000) Recibe pushes, asigna tareas al runner
Runner /home/tonatiuh/forgejo/forgejo-runner Ejecuta las tareas en contenedores Docker
Config runner /home/tonatiuh/forgejo/runner-data/config.yml Define cómo ejecuta los jobs
Registro runner /home/tonatiuh/forgejo/runner-data/.runner Token y UUID que vinculan runner ↔ Forgejo
Imagen CI forgejo-sc.duckdns.org/smallcountry/ci-docs:latest Contenedor con Python, MkDocs y lychee preinstalados
Workflow .forgejo/workflows/docs-ci.yml Define los pasos del CI (versionado en git)
Scripts CI scripts/validate_metadata.py, scripts/check_orphan_pages.py Validaciones ejecutadas en el CI

2. El workflow (docs-ci.yml)

El archivo que define el pipeline está en .forgejo/workflows/docs-ci.yml. Es versionado en git, por lo que cualquier cambio que se le haga se guarda en el historial.

Contenido actual

name: Docs Validation & Deploy
on:
  push:
    branches:
      - main
    paths:
      - 'docs/**'
      - 'mkdocs.yml'
      - 'overrides/**'
      - '.forgejo/**'
  pull_request:
    paths:
      - 'docs/**'
      - 'mkdocs.yml'
      - 'overrides/**'
      - '.forgejo/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    container:
      image: forgejo-sc.duckdns.org/smallcountry/ci-docs:latest
      options: --volume /home/tonatiuh/SmallCountry/web:/web
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Build MkDocs
        run: properdocs build --strict

      - name: Deploy to Caddy
        run: |
          rm -rf /web/site/*
          cp -r site/* /web/site/

      - name: Check links with lychee
        continue-on-error: true
        run: lychee --config lychee.toml --base https://tonatiuh.duckdns.org 'site/**/*.html' || echo "Link check incomplete"

      - name: Validar metadatos
        run: python3 /usr/local/bin/validate_metadata.py docs

      - name: Buscar páginas huérfanas
        run: python3 /usr/local/bin/check_orphan_pages.py

Los 6 pasos

# Paso Comando Falla si...
1 Checkout actions/checkout@v4 El repo no es accesible
2 Build MkDocs mkdocs build --strict Hay enlaces rotos internos, errores de compilación
3 Deploy a Caddy rm -rf /web/site/* && cp -r site/* /web/site/ El volumen /web no está montado o valid_volumes no incluye el directorio
4 Lychee lychee --config web/lychee.toml --base https://tonatiuh.duckdns.org 'web/site/**/*.html' (continue-on-error) Hay links externos rotos
5 Metadatos python3 /usr/local/bin/validate_metadata.py web/docs Algún .md carece de status: o layer: válido
6 Huérfanas python3 /usr/local/bin/check_orphan_pages.py Hay .md en docs/ no incluidos en el nav de mkdocs.yml

Notas importantes

  • El paso Deploy a Caddy monta el volumen /home/tonatiuh/SmallCountry/web dentro del contenedor como /web. Esto permite copiar los archivos directamente desde el workspace al directorio servido por Caddy. Requiere que /home/tonatiuh/SmallCountry/web esté listado en container.valid_volumes del config.yml del runner (ya lo está).
  • El usuario caddy necesita poder leer los archivos desplegados. Se añadió al grupo tonatiuh para ello: sudo usermod -aG tonatiuh caddy.

3. Imagen Docker personalizada

Para que el CI funcione sin internet, todo lo necesario está preinstalado en una imagen Docker alojada en el registro OCI de Forgejo.

Contenido de la imagen

Componente Versión Propósito
Python 3.12-slim Base del contenedor
MkDocs 1.6.1 Generador del sitio estático
Material for MkDocs 9.7.6 Tema del sitio
lychee 0.24.2 Verificador de enlaces
validate_metadata.py Valida frontmatter de los .md
check_orphan_pages.py Detecta páginas no incluidas en el nav

Dockerfile

FROM node:22-bookworm

RUN apt-get update -qq && apt-get install -y -qq curl ca-certificates \
    && rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir \
    "mkdocs-material[imaging]" \
    properdocs \
    mkdocs-material==9.7.6 \
    mkdocs-material-extensions==1.3.1 \
    mkdocs-git-revision-date-localized-plugin==1.5.2 \
    mkdocs-get-deps==0.2.2

RUN curl -sSfL https://github.com/lycheeverse/lychee/releases/latest/download/lychee-x86_64-unknown-linux-musl.tar.gz \
    -o /tmp/lychee.tar.gz \
    && tar xzf /tmp/lychee.tar.gz -C /usr/local/bin/ --strip-components=1 lychee-x86_64-unknown-linux-musl/lychee \
    && rm /tmp/lychee.tar.gz

COPY scripts/validate_metadata.py /usr/local/bin/
COPY scripts/check_orphan_pages.py /usr/local/bin/

WORKDIR /workspace

Cómo construir y subir la imagen

# 1. Generar token en Forgejo:
#    https://forgejo-sc.duckdns.org → Settings → Applications → Generate Token
#    (permiso: packages:write o all)

# 2. Autenticarse en el registro OCI
docker login forgejo-sc.duckdns.org -u tonatiuh

# 3. Construir la imagen
docker build -t forgejo-sc.duckdns.org/smallcountry/ci-docs:latest web/

# 4. Subir al registro
docker push forgejo-sc.duckdns.org/smallcountry/ci-docs:latest

La imagen se almacena en el registro OCI interno de Forgejo, accesible solo desde la red local. No necesita conexión a internet ni a Docker Hub.


4. Cómo ver los resultados

Desde Forgejo (interfaz web)

https://forgejo-sc.duckdns.org → repo infra-core → pestaña "Actions"

Cada push en main con cambios en los path filters genera un nuevo run. Cada run muestra:

  • ✅ Verde: todos los pasos pasaron
  • ❌ Rojo: al menos un paso falló
  • 🟡 Amarillo: el CI sigue corriendo

Haciendo clic en un run se despliegan los logs de cada paso.

Desde el API

# Último run
curl -s "https://forgejo-sc.duckdns.org/api/v1/repos/SmallCountry/infra-core/actions/runs?limit=1"

# Últimos 5 en main
curl -s "https://forgejo-sc.duckdns.org/api/v1/repos/SmallCountry/infra-core/actions/runs?branch=main&limit=5"

Desde el runner (localhost)

# Logs del runner
tail -100 /home/tonatiuh/forgejo/runner-data/runner.log

# Logs de jobs anteriores
cat /home/tonatiuh/forgejo/runner-data/runner.log.old

5. El runner (config.yml)

El runner es un binario que corre en la máquina y ejecuta los jobs en contenedores Docker. Su configuración está fuera del repositorio (contiene tokens secretos) en /home/tonatiuh/forgejo/runner-data/config.yml.

Contenido actual

log:
  level: trace
  job_level: debug

runner:
  file: .runner
  capacity: 1
  envs: {}
  env_file: .env
  timeout: 3h
  shutdown_timeout: 3h
  insecure: false
  fetch_timeout: 30s
  fetch_interval: 2s
  report_interval: 1s
  labels:
    - "docker:docker"
    - "ubuntu-latest:docker"

cache:
  enabled: true
  port: 0
  dir: ""
  external_server: ""
  secret: ""
  secret_url: ""
  host: ""
  proxy_port: 0
  actions_cache_url_override: ""

container:
  network: "host"
  enable_ipv6: false
  privileged: true
  options: "--dns 8.8.8.8 --dns 1.1.1.1"
  workdir_parent: /home/tonatiuh/forgejo/runner-data/workspace
  valid_volumes:
    - /home/tonatiuh/forgejo/runner-data/workspace
    - /home/tonatiuh/SmallCountry/web
  docker_host: "automount"
  force_pull: false
  force_rebuild: false

host:
  workdir_parent: /home/tonatiuh/forgejo/runner-data/workspace

server:
  connections:
    forgejo-instance:
      url: https://forgejo-sc.duckdns.org
      uuid: 0f9f24fd-0028-450d-9c97-203822b2d5bc
      token: 0638064ed2427ef548ae9251668ee3474a0b7550
      labels:
        - "docker:docker"
        - "ubuntu-latest:docker"

Parámetros importantes

Clave Valor actual Significado
capacity 1 Solo un job a la vez
labels docker:docker, ubuntu-latest:docker Etiquetas que ofrece el runner
container.privileged true Permite Docker-in-Docker dentro del contenedor de CI
container.network host El contenedor comparte la red del host
container.valid_volumes workspace + /home/tonatiuh/SmallCountry/web Directorios que el contenedor puede montar como volúmenes

/home/tonatiuh/SmallCountry/web debe estar en valid_volumes para que el paso "Deploy to Caddy" pueda montar el directorio de salida y copiar los archivos.


6. Cómo se lanza

Automático

El CI se lanza solo al hacer git push si los cambios tocan:

Path Ejemplos
docs/** Cualquier página .md, imagen, o archivo en documentación
mkdocs.yml Configuración del sitio, navegación
overrides/** Plantillas HTML (main.html)
.forgejo/** El propio workflow de CI

Manual (forzar re-ejecución)

cd /home/tonatiuh/SmallCountry/web
git commit --allow-empty -m "ci: trigger re-run"
git push origin main

7. Cómo gestionar el runner

Estado

pgrep -la forgejo-runner

Parar

kill $(pgrep forgejo-runner)

Arrancar

cd /home/tonatiuh/forgejo/runner-data
setsid /home/tonatiuh/forgejo/forgejo-runner daemon --config config.yml > runner.log 2>&1 &
disown

Ver en Forgejo (admin)

https://forgejo-sc.duckdns.org → avatar → Admin panel → Actions → Runners

Aquí ves: nombre (casita-runner), estado (🟢/🔴), última conexión, y puedes generar nuevos tokens de registro.


8. Solución de problemas frecuentes

Síntoma Causa Solución
CI no se lanza al hacer push Los archivos tocados no coinciden con los path filters Verifica que docs/, mkdocs.yml, overrides/ o .forgejo/ estén incluidos
status=failure sin job_ids El runner no está corriendo pgrep forgejo-runner. Si no devuelve nada, arrancarlo
failed to pull image La imagen CI no se ha subido al registro docker push forgejo-sc.duckdns.org/smallcountry/ci-docs:latest
volume /deploy not allowed Falta /home/tonatiuh/SmallCountry/web en valid_volumes del runner Añadirlo al config.yml y reiniciar el runner
403 Forbidden al servir la web caddy no puede leer los archivos desplegados sudo usermod -aG tonatiuh caddy && sudo systemctl restart caddy
Runner se para solo El proceso no sobrevive al terminal Usar setsid + disown (ver comandos arriba)
Forgejo API no responde forgejo-sc.duckdns.org no alcanzable Verificar Caddy + contenedor Docker Forgejo: docker ps

Secciones relacionadas