Tabla de Contenidos

7. GitHub Actions

Introducción

El despliegue continuo es desplegar las aplicaciones web lo más pronto posible: cada cambio que se sube al repositorio acaba en el servidor sin que nadie tenga que hacerlo a mano.

Para eso se usa un servidor de automatización: un programa que, cuando ocurre algo (un push a una rama, que alguien pulse un botón, una hora concreta), ejecuta solo una lista de pasos escrita de antemano. Los pasos son los que haríamos nosotros a mano:

  1. Descargar el código del repositorio.
  2. Compilarlo y pasar los tests.
  3. Construir la imagen Docker.
  4. Desplegar la nueva versión

Si un paso falla, se para ahí y avisa: lo que no compila o no pasa los tests no llega al servidor.

Existen muchas formasde hacerlo, antiguamente se hacía con una herramienta de software libre llamada Jenkins pero actualmente se usan las acciones de GitHub o GitLab , etc.

GitHub Actions es el sistema de automatización integrado en GitHub. Cada fichero YAML dentro de .github/workflows/ es un workflow, y en él se define:

Mas información:

Workflows

Un workflow es un fichero YAML dentro de la carpeta .github/workflows/ del repositorio. GitHub lee esa carpeta en cada push: no hay que darlo de alta en ningún sitio. El fichero tiene cuatro partes:

Lo que no debe estar en el repositorio (contraseñas, claves SSH, IPs) se guarda como secreto en Settings → Secrets and variables → Actions y se usa en el workflow con ${{ secrets.NOMBRE }}. GitHub lo oculta en los logs.

El runner arranca vacío: no tiene nuestro código hasta que se hace actions/checkout, y no tiene nada instalado aparte de lo que trae Ubuntu, así que lo que haga falta se instala en un paso.

Para compilar el proyecto Java y pasar sus tests cada vez que se sube algo a master, se añade al repositorio:

name: Compilar

on:
  workflow_dispatch:
  push:
    branches:
      - master

jobs:
  compilar:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v7

      - name: Instalar Java 21
        uses: actions/setup-java@v6
        with:
          distribution: temurin
          java-version: 21

      - name: Compilar y pasar los tests
        run: mvn -B package

Cada ejecución sale en la pestaña Actions del repositorio, con cada paso en verde o en rojo y su log. Si un paso falla, los siguientes no se ejecutan.

Runners

Un runner es el programa que ejecuta los jobs de un workflow: GitHub le pasa los pasos y él los va ejecutando y le devuelve el log. Dónde está el runner lo elige runs-on, y hay dos tipos:

Runner de GitHub Runner propio
Dónde se ejecutan los pasos En una máquina de GitHub En nuestro servidor
Hay que instalarlo y mantenerlo ✓
Empieza vacío en cada ejecución ✓
Ve la red del servidor ✓
Para desplegar necesita VPN, SSH y sus secretos ✓

Para compilar y pasar los tests, el runner de GitHub. Para desplegar en un servidor nuestro, un runner propio en ese servidor: los pasos se ejecutan allí mismo, así que el workflow se queda en lanzar deploy.sh.

Con el runner de GitHub

El runner está en Internet y el servidor en el instituto, así que para desplegar tendría que entrar por VPN y SSH, con las claves guardadas como secretos:

Con el runner de GitHub: crea el runner y entra en el servidor por VPN y SSH

La clave privada SSH para entrar en el servidor (Proyecto 1) se guarda como secreto SSH_KEY, y el usuario y el servidor como SSH_USER y SSH_HOST. El workflow entra por SSH y ejecuta deploy.sh, que está en el home del usuario en el servidor:

name: Desplegar

on:
  workflow_dispatch:
  push:
    branches:
      - master

jobs:
  desplegar:
    runs-on: ubuntu-24.04
    steps:
      - name: Desplegar
        run: |
          echo "${{ secrets.SSH_KEY }}" > clave
          chmod 600 clave
          ssh -i clave -o StrictHostKeyChecking=accept-new ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "~/deploy.sh"

Solo funciona si el servidor acepta SSH desde Internet. Si está detrás del router del instituto o de la empresa, antes hay que conectar la VPN en otro paso, con más secretos. O quizás ni se pueda si no hay una VPN

Con un runner propio

El runner está dentro del servidor. Es él quien pregunta a GitHub si hay trabajo, por HTTPS, como un navegador: no hace falta abrir ningún puerto ni VPN, y funciona aunque el servidor esté detrás del router del instituto.

Con un runner propio: el runner pregunta a GitHub por HTTPS y ejecuta el job en local

Instalar un runner propio en Linux

Un runner se registra en un repositorio y solo ejecuta sus workflows. Se instala en el servidor con el usuario que va a desplegar, no con root:

  1. En el repositorio, Settings → Actions → Runners → New self-hosted runner, con Linux y x64. GitHub muestra las órdenes de los pasos siguientes: se copian de esa página, porque la de config.sh lleva el token.
  2. Descargarlo:
    mkdir actions-runner && cd actions-runner
    curl -O -L https://github.com/actions/runner/releases/download/v2.338.2/actions-runner-linux-x64-2.338.2.tar.gz
    tar xzf ./actions-runner-linux-x64-2.338.2.tar.gz
    
  3. Registrarlo en el repositorio. --url es el repositorio y --token un token de registro que GitHub genera al abrir la página de New self-hosted runner: está en la orden config.sh del apartado Configure de esa página. Pregunta el grupo, el nombre y las etiquetas: con Enter se queda lo que propone.
    ./config.sh --url https://github.com/lgonzalezmislata/Facturas --token AXQKZ7MBV3LN2RCYEUHJ4PDTD6Y2W
    
  4. Dejarlo como servicio, para que siga en marcha al cerrar la sesión SSH y arranque solo al reiniciar el servidor:
    sudo ./svc.sh install
    sudo ./svc.sh start
    sudo ./svc.sh status
    
  5. En Settings → Actions → Runners tiene que salir como Idle.
El token de registro no es un token personal de GitHub ni hay que crearlo: lo da esa página, solo sirve para registrar el runner una vez y caduca en una hora. Si config.sh dice que el token no vale, se recarga la página y se copia el nuevo.

Configurar un workflow para usar un runner

El workflow es el mismo que con el runner de GitHub, pero sin SSH: el runner ya está en el servidor y ejecuta deploy.sh allí mismo.

name: Desplegar

on:
  workflow_dispatch:
  push:
    branches:
      - master

jobs:
  desplegar:
    runs-on: self-hosted
    steps:
      - name: Desplegar
        run: ~/deploy.sh

Lo que hace que el job se ejecute en nuestro servidor es runs-on: self-hosted. Los pasos se ejecutan con el usuario que instaló el runner

Más información:

Ejercicios

Ejercicio 1

Añade a tu repositorio de Java el workflow compilar.yml. Comprueba en Actions que sale en verde; luego haz fallar un test, súbelo y comprueba que sale en rojo y en qué paso.

Ejercicio 2