Tabla de Contenidos
¡Esta es una revisión vieja del documento!
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:
- Descargar el código del repositorio.
- Compilarlo y pasar los tests.
- Construir la imagen Docker.
- 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:
- Cuándo se ejecuta: al hacer un push, cuando tú decidas o a una hora programada.
- Qué se ejecuta: las tareas (jobs), como compilar, pasar los tests o desplegar. Cada job se compone de pasos (steps), que pueden ser órdenes de shell o actions reutilizables hechas por otros.
- Dónde se ejecuta: en un runner, el programa que ejecuta los jobs. Puede estar en una máquina virtual de GitHub o en una máquina tuya (Runners).
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:
on: cuándo se ejecuta.pushconbranchescuando se sube algo a esa rama;workflow_dispatchañade un botón Run workflow en la pestaña Actions para lanzarlo a mano.jobs: los trabajos que hay que hacer.runs-on: el runner en el que se ejecuta cada trabajo. Conubuntu-24.04, un Ubuntu que GitHub crea para la ocasión y tira al acabar; conself-hosted, un runner propio (Runners). Siempre con la versión puesta, nuncaubuntu-latest: cuando GitHub cambia la versión a la que apunta, los scripts que funcionaban pueden dejar de funcionar sin haber tocado nada.steps: los pasos de cada trabajo, en orden. Cada paso tiene unnamey hace una de dos cosas:run: órdenes de shell, como en una terminal. Con|se ponen varias líneas.uses: una acción ya hecha por otros, comoactions/checkout@v7, que descarga el código del repositorio en el runner.
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.
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
actions/setup-java: el Ubuntu del runner no trae la versión de Java del proyecto; esta acción la instala.mvn -B package: compila y pasa los tests. Si falla un test, el workflow sale en rojo.-Bes el modo no interactivo, sin colores ni barras de progreso en el log.
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 (
runs-on: ubuntu-24.04): una máquina virtual que GitHub crea para cada job y tira al acabar. Es el del workflow de arriba. - Runner propio (
runs-on: self-hosted): el mismo programa, pero instalado por nosotros en un servidor nuestro. Se queda siempre en marcha esperando trabajo.
| 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:
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 allí deploy.sh:
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
echoychmod:sshlee la clave de un fichero, así que se escribe el secreto en uno.StrictHostKeyChecking=accept-new: el runner es nuevo y no conoce el servidor. Sin esto,sshpregunta si se fía de él y el workflow se queda parado esperando la respuesta../deploy.sh: la orden que se le pasa asshdetrás del servidor se ejecuta en el servidor, no en el runner.
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.
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.
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:
- En el repositorio, Settings → Actions → Runners → New self-hosted runner, con Linux y x64. GitHub muestra las órdenes de los pasos siguientes con el token ya puesto. El token caduca en una hora.
- 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
- Registrarlo en el repositorio. 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
- 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
- En Settings → Actions → Runners tiene que salir como Idle.
Configurar un workflow para usar un runner
El workflow de despliegue, en el repositorio del proyecto, se queda en clonar el repositorio de despliegue y lanzar deploy.sh:
name: Desplegar
on:
workflow_dispatch:
push:
branches:
- master
jobs:
desplegar:
runs-on: self-hosted
steps:
- name: Desplegar
run: |
rm -rf DesplegarFacturasDocker
git clone https://github.com/lgonzalezmislata/DesplegarFacturasDocker.git
cd DesplegarFacturasDocker && ./deploy.sh
Con el runner de GitHub había que entrar por SSH; aquí no, porque el runner ya está en el servidor y ejecuta las órdenes allí mismo. 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 y sin terminal para escribir la contraseña de sudo, así que si deploy.sh usa Docker, ese usuario tiene que estar en el grupo docker (sudo usermod -aG docker $USER y reiniciar el servicio). Además, el runner propio no empieza vacío: lo que deja una ejecución sigue ahí en la siguiente, en actions-runner/_work, y por eso el workflow borra la carpeta antes de clonar. Y solo se usa en repositorios privados: en uno público, cualquiera que abra un pull request puede hacer que ejecute su código en tu servidor.
Más información:
- About self-hosted runners: qué son y requisitos.
- Configure the self-hosted runner application:
svc.shen Linux.
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
- Instala un runner propio para tu repositorio de Java en tu servidor como en Instalar un runner propio en Linux, como servicio, y comprueba que sale Idle.
- Añade el workflow
desplegar.ymladaptado a tu proyecto. Se ejecutará manualmente y cuando haya un cambio enmaster. Sube un cambio y comprueba que llega desplegado al servidor.


