cb12d68fbeacdd697c97fec0445e8b97628872d9
CI Pipeline / HTML Lint (push) Successful in 7s
Deploy QA / Build and Push (push) Successful in 13s
CI Pipeline / Build Docker Image (push) Failing after 28m28s
CI Pipeline / Security Scan (push) Has been skipped
Deploy QA / Deploy to QA (push) Failing after 1s
CI Pipeline / Generate Summary (push) Failing after 0s
Deploy QA / Notification (push) Failing after 1s
Replace nginx config environment variable substitution from envsubst to sed to eliminate the gettext package dependency, reducing the final container image size. Remove unused export statements from the docker-entrypoint.sh script.
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%