GitHub Actions desde cero: workflows, jobs, steps y runners
Introducción
GitHub Actions es la plataforma de integración continua (CI) y entrega continua (CD) que viene integrada con GitHub. Permite automatizar el flujo de trabajo completo de desarrollo de software: desde la ejecución de pruebas y la construcción del código hasta la implementación en servidores o la publicación en el ecosistema de GitHub. Aunque al principio puede parecer un poco intimidante, una vez que entendés los cuatro pilares básicos —workflows, jobs, steps y runners—, podés crear tuberías de CI/CD flexibles y potentes a medida que avanzas.
Este artículo está pensado para desarrolladores, ingenieros de confiabilidad, equipos DevOps y cualquier persona que quiera llevar su flujo de trabajo más allá del sistema de CI local. Al final, tendrás un workflow mínimo en YAML, una explicación clara de cada componente y un diagrama visual que conecta todo. Además, verás algunas prácticas recomendadas y consejos para evitar errores comunes.
Conceptos básicos
Qué es un workflow
En GitHub Actions, un workflow es el archivo YAML principal que define toda la tubería. Se guarda en el repositorio bajo .github/workflows/. Un workflow puede tener uno o más jobs, cada uno de los cuales representa una tarea independiente (por ejemplo, ejecutar tests, construir una imagen Docker, implementar un sitio web).
Un workflow puede activarse por diferentes eventos:
- push – cuando se sube nuevo código a un branch.
- pull_request – cuando se crea o actualiza una solicitud de incorporación de cambios.
- schedule – ejecución periódica (por ejemplo, cada hora o diaria).
- workflow_dispatch – permite una ejecución manual a pedido.
El archivo del workflow debe tener una extensión .yml o .yaml, un nombre único y una sección on que describa el desencadenador.
Jobs: tareas paralelas
Un job representa una unidad de trabajo que se ejecuta en un runner. Los jobs pueden ser:
- Secuenciales – los jobs posteriores esperan a que los anteriores terminen.
- Paralelos – múltiples jobs se ejecutan a la vez (útil para pruebas en paralelo).
- Matriz – un solo job que se ejecuta múltiples veces con diferentes entradas (framework, versión de Node, parámetros de prueba).
Cada job tiene:
runs-on: el tipo de runner a usar (por ejemplo,ubuntu-latest).strategy: permite matrix y ejecución en paralelo.steps: un ordenado listado de acciones y comandos para ejecutar.
Steps: el trabajo detallado
Un step es la parte más pequeña de ejecución. Puede ser:
- Ejecutar un comando directamente con
run:(shell, PowerShell, etc.). - Usar una acción (
uses:) – una pieza reutilizable de código, por ejemplo,actions/checkout@v4para traer el código al runner. - Composición o reutilización con
usesdesde una acción compuesta.
Los steps se ejecutan en el orden en que aparecen, y cada paso puede depender del éxito/fallo de pasos anteriores.
Runners: donde se ejecuta el trabajo
Un runner es un servidor (proveído por GitHub o auto-alojado) que ejecuta los steps de un job. GitHub ofrece:
- ubuntu-latest (Linux)
- windows-latest (Windows)
- macOS-latest (macOS)
También puedes configurar tu propio runner (auto-alojado) si necesitas un entorno con herramientas especializadas, acceso a red local o hardware específico.
Construyendo tu primer workflow
Paso a paso
A continuación tenés un archivo .github/workflows/hello-world.yml mínimo. No hay necesidad de instalar nada extra; solo necesitás un repositorio en GitHub.
name: Hello World Workflow
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
jobs:
hello:
runs-on: ubuntu-latest
steps:
- name: Mostrar el evento de GitHub
run: |
echo "Evento: ${{ github.event_name }}"
echo "Rama: ${{ github.ref }}"
- name: Verificar el código
uses: actions/checkout@v4
- name: Mostrar archivos
run: find . -type f -maxdepth 2Explicación
name:– título legible para humanos del workflow.on:– tres desencadenadores: push amain, pull_request amainy ejecución manual.jobs.hello:– un solo job llamadohello.runs-on:– selecciona un runner Linux de GitHub.steps:– tres pasos:- Mostrar el evento de GitHub – imprime el tipo de evento y la rama.
- Verificar el código – usa la acción oficial
actions/checkoutpara bajar el código fuente al runner. - Mostrar archivos – recorre archivos en el árbol (útil para depuración).
Puedes subir este archivo a un repositorio, hacer un commit y ver el workflow en acción en la pestaña Actions. Cada ejecución creará un run, que contiene un job y pasos que se ejecutan en un runner.
Ejecutar el workflow manualmente
Después de hacer push del archivo, podés probar el workflow sin modificar el código. Haz clic en Actions → busca el workflow → haz clic en Run workflow (si está disponible gracias al desencadenador workflow_dispatch). La interfaz mostrará logs en vivo:
Ejecutando "Hello World Workflow" #123
Ejecutando job "hello"
Paso 1: Mostrar el evento de GitHub
Evento: workflow_dispatch
Rama: refs/heads/main
Paso 2: Verificar el código
Descargando el código... (100%)
Paso 3: Mostrar archivos
.
.Un ejemplo de script ejecutable
Para demostrar un paso que realmente imprime algo, podés incluir un pequeño script Bash:
echo "¡Hola desde el runner!"
echo "La versión de bash es:"
bash --versionEl bloque anterior es un ejemplo ejecutable: podés copiarlo y pegarlo en un repositorio, ejecutar el workflow y ver la salida directamente en la página de GitHub Actions.
Profundizando en jobs y steps
Strategy y ejecución en paralelo
Supongamos que querés probar una aplicación Node.js contra múltiples versiones de Node. Usás un matrix dentro de strategy:
strategy:
matrix:
node-version: [16, 18, 20]Y luego referenciar matrix.node-version en cada job:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- name: Configurar Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Instalar dependencias
run: npm ci
- name: Ejecutar tests
run: npm testAhora el job test se ejecuta tres veces en paralelo (a menos que agregues max-parallel). Cada iteración obtiene su propio runner.
Paso compuesto vs. reusable
GitHub Actions soporta acciones compuestas (YAML dentro de uses) y workflows reutilizables (workflow_call). Las primeras son útiles dentro de un workflow; las segundas permiten compartirlibrerías entre repositorios. Ambas ayudan a evitar la duplicación de código.
Salida y condiciones
Los pasos pueden exponer valores usando id + set-output (legacy) o GITHUB_OUTPUT. Ejemplo:
- name: Calcular versión
id: version
run: |
VERSION=$(date +%Y.%m.%d)
echo "version=$VERSION" >> $GITHUB_OUTPUTLuego usás ${{ steps.version.outputs.version }} en cualquier paso posterior o en toda la matriz.
Las condiciones (if:) permiten saltar un paso basándose en variables de entorno, resultados anteriores o cadenas de edición. Ejemplo para solo ejecutar un paso si el branch es main:
- name: Despliegue solo en main
if: github.ref == 'refs/heads/main'
run: ./deploy.shManejo de errores y reintentos
Añadí continue-on-error: true si querés que el job continúe a pesar de que un paso falle, o retries: dentro de strategy para reintentos automáticos en pasos fallidos.
Runners: eligiendo el runner adecuado
GitHub-hosted
Los runners alojados son administrados por GitHub. Ofrecen un entorno limpio y actualizado para cada job. La tabla a continuación resume las imágenes disponibles:
| OS | Imagen | Uso típico |
|---|---|---|
| Linux | ubuntu-latest |
Construcción multiplataforma, pruebas de contenedores |
| Windows | windows-latest |
Construcción .NET, scripts PowerShell |
| macOS | macos-latest |
Aplicaciones iOS, scripts Ruby/Bundler |
También podés seleccionar una versión específica (ubuntu-22.04) si necesitás un entorno exacto.
Auto-hosted (on-premise)
Un runner auto-alojado es un servidor que controlas. Ventajas:
- Instalación de dependencias especializadas (JDKs, bases de datos, drivers).
- Acceso a recursos de red o hardware no disponibles en runners GitHub (por ejemplo, dispositivos IoT, GPU).
- Control de costos si ejecutas jobs pesados en tu propio infraestructura.
Configurarlo implica:
- Crear un token de registro en GitHub (
settings > Actions > Runners). - Descargar el script de configuración (
./config.sh). - Ejecutarlo con
runner-group-id,work-foldery el token.
Una vez registrado, podés asignar el runner a uno o más grupos para restringir qué repositorios pueden usarlo.
Runners personalizados
Si los runners estándar no cubren tus necesidades, podés crear un runner personalizado con cualquier sistema operativo (por ejemplo, Alpine Linux, containers base). Esto te permite empaquetar dependencias en una imagen Docker y usar container: en un job:
jobs:
build:
runs-on: ubuntu-latest
container:
image: myregistry/custom-builder:1.2
steps:
- uses: actions/checkout@v4
- run: npm run buildEl contenedor actúa como el shell del runner, dándote un entorno aislado y reproducible.
Diagrama: relacionando todo
A continuación tenés un diagrama Mermaid que visualiza la relación entre cada concepto. Funciona en GitHub y en cualquier visor compatible con Markdown.
graph TD
A[Workflow] --> B[Job 1]
A --> C[Job 2]
B --> D[Step 1]
B --> E[Step 2]
C --> F[Step 1]
D --> G[Runner]
E --> G
F --> G
G --> H[Ejecutar comandos o acciones]El diagrama muestra:
- Un workflow que activa dos jobs.
- Cada job contiene uno o más steps.
- Todos los steps se ejecutan en un runner (alojado o auto-alojado).
Visualizar esto ayuda a entender que un workflow es la estructura, un job es una tarea, un step es el trabajo detallado y el runner es el entorno de ejecución.
Mejores prácticas
1. Mantener el YAML limpio
- Usa espacios consistentes (2 espacios).
- Agrupa las secciones lógicamente:
name,on,jobs. - Agrega comentarios para jobs o steps de mayor nivel.
2. Caché de dependencias
Si tu workflow instala npm, pip o bundles de gems, agrega un paso actions/cache@v4 para evitar reconstruir desde cero:
- name: Caché de npm
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-3. Uso seguro de secrets
Los secrets (claves API, tokens) están cifrados y disponibles solo en el runner. Distribuye el menor número posible de secrets; prefiere los repository secrets sobre environment secrets a menos que necesites separación por entorno.
4. Least privilege y GitHub Tokens
Los workflows usan un token de GitHub para realizar acciones en nombre del usuario que disparó el workflow. Considera restringir los permisos (por ejemplo, solo contents:read si no necesitas escribir). Puedes editar permissions: dentro del job:
jobs:
build:
permissions:
contents: read
packages: write
...5. Manejo de errores y reintentos
continue-on-error: truepara pasos que fallan ocasionalmente (por ejemplo, tests de red).retries: 3dentro de unstep(anteactions/setup-nodeorun) si fallan por razones transitorias.
6. Etiquetar runs para mejor depuración
Agrega if: always() a pasos de registro para que siempre aparezcan, incluso si pasos anteriores fallan.
Errores comunes y cómo evitarlos
| Síntoma | Causa probable | Solución |
|---|---|---|
| Los pasos no se ejecutan en el orden deseado | Asumir que la paralelización es implícita | Usa IDs explícitos (needs: y if) para controlar la ejecución. |
El workflow falla con Error: Invalid environment |
Intentar usar container: en un runner Windows |
Asegúrate de que la imagen del contenedor sea compatible con el SO del runner. |
| Las ejecuciones se detienen después de un timeout | No hay límite de tiempo en steps largos | Agrega timeout-minutes: en cada job o step. |
| La caché nunca se restablece | Clave incorrecta que no cambia entre commits | Actualiza la clave con hashFiles('**/*.lock'). |
| Token expira o tiene permisos insuficientes | Reutilizar un token personal en lugar de un token generado por GitHub | Usa GITHUB_TOKEN y limita los permisos. |
Conclusión
GitHub Actions se construye sobre cuatro conceptos clave:
- Workflows – el archivo YAML principal y el disparador.
- Jobs – tareas independientes que pueden ser paralelas o en matriz.
- Steps – acciones atómicas (comando o acción reutilizable).
- Runners – servidores donde realmente se ejecutan los steps (alojados, auto-alojados o en contenedor).
Una vez que comprendés estas piezas y las relacionas con el diagrama, crear una tubería de CI/CD compleja es solo una cuestión de composición. Recuerda mantener el YAML legible, implementar estrategias de caché, proteger secrets y aplicar el principio de least privilege. Con estas bases, podés avanzar hacia despliegues avanzados, notificaciones y reutilización entre repositorios.
Próximos pasos
- Explora GitHub Pages y environment protection rules.
- Prueba workflows reutilizables (
workflow_call) para compartir bibliotecas entre equipos. - Integra notificaciones usando
actions/github-scriptpara comentar en PRs o enviar Slack/Teams.
Con una comprensión sólida de workflows, jobs, steps y runners, estás listo para automatizar cualquier flujo de desarrollo. ¡Empieza a escribir tus primeros workflows hoy y observa cómo tu flujo de trabajo se vuelve más rápido e inteligente!
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.