6e72bfed41fdf94e3a243c99a934679e41f88e50
CI Pipeline / HTML Lint (push) Successful in 7s
Deploy QA / Build and Push (push) Successful in 14s
CI Pipeline / Build Docker Image (push) Successful in 57s
Deploy QA / Deploy to QA (push) Failing after 2s
CI Pipeline / Security Scan (push) Successful in 11s
Deploy QA / Notification (push) Failing after 1s
CI Pipeline / Generate Summary (push) Failing after 0s
CI/CD Multi-Environment Pipeline POC
Prueba de concepto de un pipeline CI/CD multi-ambiente con Gitea Actions, Docker y Nginx.
Arquitectura
feature/*
|
PR
|
┌───┴───┐
│ dev │ ──(push)──► CI Pipeline ──► Deploy QA
└───┬───┘ (lint, build, (puerto 8081)
│ security scan)
PR docker registry
│ │
┌───┴───┐ │
│staging│ ──(push)────────┼──► Deploy Staging
└───┬───┘ │ (puerto 8082)
│ │
PR │
│ │
┌───┴───┐ │
│ main │ ──(push)────────┴──► Deploy Production
└───────┘ (aprobación) (puerto 8083)
Ambientes
| Ambiente | URL | Puerto | Rama | Trigger |
|---|---|---|---|---|
| QA | https://practicas.qa.kubistudio.cloud | 8081 | dev |
Push autom. |
| Staging | https://practicas.staging.kubistudio.cloud | 8082 | staging |
Push autom. |
| Production | https://practicas.prod.kubistudio.cloud | 8083 | main |
Push + aprob. |
Configuración en Gitea
Secretos (Settings > Secrets)
| Secreto | Descripción |
|---|---|
TOKEN |
Token de Gitea con permisos de escritura al registry |
DEPLOY_SSH_KEY |
Clave SSH privada para acceder al servidor de deploy |
DEPLOY_USERNAME |
Usuario SSH para conexión al servidor |
DEPLOY_HOST |
Host/IP del servidor de deploy |
Variables (Settings > Variables)
| Variable | Descripción | Ejemplo |
|---|---|---|
REGISTRY_URL |
URL del Gitea Container Registry | git.kubistudio.cloud |
IMAGE_NAME |
Nombre de la imagen en el registry | kubistudio/cicd-multi-env-pipeline-poc |
Flujo de Trabajo
- Crear rama
feature/*desdedev - Desarrollar y hacer commit
- Abrir PR a
dev→ CI ejecuta lint, build, security scan - Merge a
dev→ CI + Deploy automático a QA - PR de
dev→staging→ Deploy automático a Staging - PR de
staging→main→ Requiere aprobación → Deploy a Producción
Ejecución Local
Con docker-compose
version: '3.8'
services:
cicd-qa:
build: .
ports:
- "8081:80"
environment:
APP_ENV: qa
APP_VERSION: dev-local
GIT_COMMIT: local
GIT_BRANCH: dev
BUILD_DATE: ${BUILD_DATE:-unknown}
DEPLOY_TIME: ${DEPLOY_TIME:-unknown}
BUILD_NUMBER: "0"
cicd-staging:
build: .
ports:
- "8082:80"
environment:
APP_ENV: staging
APP_VERSION: staging-local
GIT_COMMIT: local
GIT_BRANCH: staging
BUILD_DATE: ${BUILD_DATE:-unknown}
DEPLOY_TIME: ${DEPLOY_TIME:-unknown}
BUILD_NUMBER: "0"
cicd-prod:
build: .
ports:
- "8083:80"
environment:
APP_ENV: production
APP_VERSION: 1.0.0
DEPLOY_TIME: ${DEPLOY_TIME:-unknown}
Manual
# Build
docker build \
--build-arg APP_VERSION=1.0.0 \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--build-arg GIT_COMMIT=$(git rev-parse --short HEAD) \
--build-arg GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) \
-t cicd-poc:latest .
# Run
docker run -d \
--name cicd-qa \
-p 8081:80 \
-e APP_ENV=qa \
-e APP_VERSION=dev-local \
-e GIT_COMMIT=$(git rev-parse --short HEAD) \
-e GIT_BRANCH=dev \
-e BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
-e DEPLOY_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
-e BUILD_NUMBER="1" \
cicd-poc:latest
# Test
curl http://localhost:8081/health
Variables de Entorno del Contenedor
| Variable | Obligatorio | Default | Descripción |
|---|---|---|---|
APP_ENV |
No | development |
Ambiente: qa, staging, production |
APP_VERSION |
No | 0.0.0 |
Versión de la aplicación |
BUILD_DATE |
No | (vacío) | Fecha ISO del build |
GIT_COMMIT |
No | (vacío) | SHA corto del commit |
GIT_BRANCH |
No | (vacío) | Rama de git |
DEPLOY_TIME |
No | (vacío) | Timestamp del deploy |
BUILD_NUMBER |
No | (vacío) | Número de build de la pipeline |
Rollback Manual
Production
ssh user@deploy-host
# Rollback a stable tag
docker stop cicd-prod && docker rm cicd-prod
docker run -d \
--name cicd-prod \
--restart unless-stopped \
-p 8083:80 \
-e APP_ENV=production \
-e APP_VERSION=rollback \
-e DEPLOY_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
registry-url/image-name:stable
# O con un SHA específico
docker run -d \
--name cicd-prod \
--restart unless-stopped \
-p 8083:80 \
-e APP_ENV=production \
-e APP_VERSION=rollback \
-e DEPLOY_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
registry-url/image-name:sha-SHA_DEL_COMMIT
QA / Staging
# QA
docker stop cicd-qa && docker rm cicd-qa
docker run -d --name cicd-qa -p 8081:80 ... registry-url/image-name:sha-SHA_ANTERIOR
# Staging
docker stop cicd-staging && docker rm cicd-staging
docker run -d --name cicd-staging -p 8082:80 ... registry-url/image-name:sha-SHA_ANTERIOR
Endpoints
| Endpoint | Descripción |
|---|---|
/ |
Aplicación web |
/health |
Health check (JSON) |
Ejemplo /health
{
"status": "ok",
"env": "production",
"version": "release-a1b2c3d",
"timestamp": "2024-01-15T14:23:00+00:00"
}
Estructura del Proyecto
.
├── src/
│ └── index.html # App web (UI completa self-contained)
├── .gitea/workflows/
│ ├── ci.yml # CI: lint + build + security scan
│ ├── deploy-qa.yml # Deploy a QA (push a dev)
│ ├── deploy-staging.yml # Deploy a Staging (push a staging)
│ └── deploy-prod.yml # Deploy a Producción (push a main + aprobación)
├── docker-entrypoint.sh # Entrypoint que genera env-config.js en runtime
├── Dockerfile # Multi-stage build
├── healthcheck.sh # Script de health check
├── nginx.conf # Configuración de nginx
└── README.md # Este archivo
Languages
HTML
84.9%
Dockerfile
8.9%
Shell
6.2%