CI/CD con GitHub Actions: Automatización Completa de DevOps
En el desarrollo moderno de software, la Integración Continua (CI) y el Despliegue Continuo (CD) son pilares fundamentales para entregar software de calidad de manera rápida y confiable. GitHub Actions ha revolucionado este espacio ofreciendo una plataforma integrada, potente y accesible para automatizar todos los aspectos del ciclo de vida del desarrollo.
¿Qué es CI/CD?
Integración Continua (CI)
La Integración Continua es una práctica de desarrollo donde los desarrolladores integran su código en un repositorio compartido frecuentemente. Cada integración se verifica mediante una build automatizada que incluye pruebas para detectar errores rápidamente.
Beneficios de CI:
- Detección temprana de errores
- Reducción de problemas de integración
- Mejora la calidad del código
- Facilita la colaboración en equipo
Despliegue Continuo (CD)
El Despliegue Continuo extiende CI automatizando el proceso de entrega de software a producción. Puede referirse a:
- Continuous Delivery: Automatización hasta el punto de despliegue (requiere aprobación manual)
- Continuous Deployment: Automatización completa incluyendo el despliegue a producción
GitHub Actions: Conceptos Fundamentales
Arquitectura de GitHub Actions
GitHub Actions utiliza varios componentes clave:
- Workflows: Procesos automatizados que se ejecutan en respuesta a eventos
- Jobs: Conjuntos de pasos que se ejecutan en el mismo runner
- Steps: Tareas individuales que pueden ejecutar acciones o comandos
- Actions: Aplicaciones reutilizables que realizan tareas específicas
- Runners: Servidores que ejecutan los workflows
Sintaxis Básica de un Workflow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| name: CI/CD Pipeline
# Eventos que desencadenan el workflow
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
# Variables de entorno globales
env:
NODE_VERSION: '18'
REGISTRY: ghcr.io
# Trabajos del workflow
jobs:
test:
name: Tests and Quality Checks
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: $
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run linting
run: npm run lint
|
Workflows Esenciales para Diferentes Tecnologías
Node.js/JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| name: Node.js CI/CD
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v4
- name: Use Node.js $
uses: actions/setup-node@v4
with:
node-version: $
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run coverage
run: npm run coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: $
- name: Build application
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
- name: Deploy to production
run: |
# Comandos de despliegue
echo "Deploying to production..."
|
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
| name: Python CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
steps:
- uses: actions/checkout@v4
- name: Set up Python $
uses: actions/setup-python@v4
with:
python-version: $
- name: Cache pip packages
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: $-pip-$
restore-keys: |
$-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Lint with flake8
run: |
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest --cov=./ --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install security tools
run: |
python -m pip install --upgrade pip
pip install bandit safety
- name: Run Bandit security scan
run: bandit -r . -f json -o bandit-report.json
- name: Check dependencies for vulnerabilities
run: safety check --json --output safety-report.json
|
Docker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| name: Docker CI/CD
on:
push:
branches: [ main ]
tags: [ 'v*' ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: $
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: $
username: $
password: $
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: $/$
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern=
type=semver,pattern=.
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: $
labels: $
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: $/$:latest
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
|
Estrategias Avanzadas
Matrix Builds
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| jobs:
test:
runs-on: $
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
include:
- os: ubuntu-latest
node-version: 18
coverage: true
exclude:
- os: windows-latest
node-version: 16
steps:
- uses: actions/checkout@v4
- name: Setup Node.js $
uses: actions/setup-node@v4
with:
node-version: $
- name: Run tests
run: npm test
- name: Upload coverage
if: matrix.coverage
run: npm run coverage
|
Conditional Jobs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| jobs:
changes:
runs-on: ubuntu-latest
outputs:
frontend: $
backend: $
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: changes
with:
filters: |
frontend:
- 'frontend/**'
backend:
- 'backend/**'
frontend-tests:
needs: changes
if: $
runs-on: ubuntu-latest
steps:
- name: Test frontend
run: echo "Testing frontend changes"
backend-tests:
needs: changes
if: $
runs-on: ubuntu-latest
steps:
- name: Test backend
run: echo "Testing backend changes"
|
Deployment Environments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- name: Deploy to staging
run: echo "Deploying to staging environment"
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
run: echo "Deploying to production environment"
|
Seguridad y Mejores Prácticas
Gestión de Secrets
1
2
3
4
5
6
7
8
9
10
11
| jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy with secrets
env:
API_KEY: $
DATABASE_URL: $
run: |
# Usar las variables de entorno de forma segura
curl -H "Authorization: Bearer $API_KEY" https://api.example.com
|
Security Scanning
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run CodeQL Analysis
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: $
with:
command: test
args: --severity-threshold=high
|
Artifact Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build application
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: production-files
path: dist/
retention-days: 30
- name: Upload test results
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results
path: test-results.xml
|
Monitoring y Observabilidad
Workflow Notifications
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| jobs:
notify:
runs-on: ubuntu-latest
if: always()
needs: [test, build, deploy]
steps:
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: $
channel: '#deployments'
webhook_url: $
- name: Update deployment status
if: github.ref == 'refs/heads/main'
run: |
curl -X POST \
-H "Authorization: token $" \
-H "Content-Type: application/json" \
-d '{"state":"success","description":"Deployment successful"}' \
https://api.github.com/repos/$/deployments
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| jobs:
performance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Lighthouse CI
run: |
npm install -g @lhci/cli@0.11.x
lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: $
- name: Run load tests
run: |
docker run --rm -i loadimpact/k6 run - <loadtest.js
|
Optimización de Workflows
Caching Strategies
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Cache de dependencias
- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: $-node-$
restore-keys: |
$-node-
# Cache de Docker layers
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: $-buildx-$
restore-keys: |
$-buildx-
|
Parallel Jobs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Lint code
run: npm run lint
test-unit:
runs-on: ubuntu-latest
steps:
- name: Run unit tests
run: npm run test:unit
test-integration:
runs-on: ubuntu-latest
steps:
- name: Run integration tests
run: npm run test:integration
build:
needs: [lint, test-unit, test-integration]
runs-on: ubuntu-latest
steps:
- name: Build application
run: npm run build
|
Troubleshooting Común
Debug de Workflows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| jobs:
debug:
runs-on: ubuntu-latest
steps:
- name: Debug information
run: |
echo "GitHub context:"
echo "$"
echo "Runner context:"
echo "$"
echo "Environment variables:"
env | sort
- name: Setup tmate session
if: failure()
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15
|
Logs y Diagnósticos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy with detailed logging
run: |
set -x # Enable debug mode
echo "Starting deployment..."
# Comandos de deployment con logging detallado
- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v3
with:
name: deployment-logs
path: |
deployment.log
error.log
|
Conclusión
GitHub Actions ha transformado la manera en que implementamos CI/CD, ofreciendo una plataforma integrada, poderosa y accesible. Las ventajas clave incluyen:
- Integración nativa con GitHub
- Ecosistema rico de actions reutilizables
- Flexibilidad para casos de uso complejos
- Escalabilidad desde proyectos pequeños hasta empresariales
- Seguridad robusta con manejo de secrets y permisos granulares
Implementar CI/CD efectivo requiere:
- Planificación cuidadosa de los workflows
- Pruebas exhaustivas en múltiples etapas
- Monitoreo continuo y alertas
- Optimización constante para mejorar tiempos
- Seguridad como prioridad en todo el pipeline
Con GitHub Actions, puedes crear pipelines de CI/CD robustos que mejoren significativamente la calidad, velocidad y confiabilidad de tus entregas de software.
Andrés Nuñez - t4ifi