Este proyecto implementa un flujo CI/CD completo con Jenkins, Docker Hub y Kubernetes (Minikube) para desplegar automáticamente una aplicación Flask + Postgres.
El pipeline:
- Clona el repositorio desde GitHub
- Construye y publica la imagen en Docker Hub
- Despliega la nueva versión en Kubernetes
- Realiza una prueba automática (
/ping
) para validar el despliegue
- Docker 28.5.0
- kubectl 1.34.1
- Minikube 1.37.0
- Git 2.43.0
- Jenkins LTS
- Python 3.12 (Flask)
pipeline {
agent any
options { timestamps() }
environment {
IMAGE = "inventosfer/flask-postgres-compose:latest"
DOCKERFILE = "parte1/Dockerfile"
CONTEXT = "parte1"
MANIFESTS = "parte2/k8s"
NAMESPACE = "parte2"
}
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Sanity') {
steps {
sh '''bash -lc
set -euo pipefail
echo "--- Raíz del repo ---"; pwd
echo "--- Dockerfile(s) ---"; find . -maxdepth 3 -iname Dockerfile -print || true
echo "--- YAMLs ---"; find . -maxdepth 3 -name "*.yaml" -print | head -n 100 || true
'''
}
}
stage('Docker Build & Push') {
steps {
withCredentials([usernamePassword(
credentialsId: 'dockerhub',
usernameVariable: 'DOCKER_USER',
passwordVariable: 'DOCKER_PASS'
)]) {
sh '''bash -lc
set -euo pipefail
echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin
docker build -t ${IMAGE} -f ${DOCKERFILE} ${CONTEXT}
docker push ${IMAGE}
'''
}
}
}
stage('Kube Deploy') {
when { expression { return fileExists(env.MANIFESTS) } }
steps {
sh '''bash -lc
set -euo pipefail
echo ">>> kubeconfig: $KUBECONFIG | context: $(kubectl config current-context) <<<"
kubectl get ns || true
# Asegura el namespace
kubectl get ns ${NAMESPACE} || kubectl create ns ${NAMESPACE}
# Quita metadata.namespace por seguridad
find ${MANIFESTS} -name "*.yaml" -exec sed -i '/^[[:space:]]*namespace:/d' {} \\;
# Aplica manifests y fuerza imagen de la API
kubectl -n ${NAMESPACE} apply -f ${MANIFESTS}
kubectl -n ${NAMESPACE} set image deploy/flask-api flask-api=${IMAGE} || true
kubectl -n ${NAMESPACE} rollout status deploy/flask-api --timeout=180s
# Estado
kubectl -n ${NAMESPACE} get all
'''
}
}
stage('Stabilize Pods') {
steps {
sh '''bash -lc
set -euo pipefail
# Espera a que todo quede en Running
for i in {1..18}; do
pending=$(kubectl -n ${NAMESPACE} get pods --no-headers | awk '$3!="Running"{c++} END{print c+0}')
[ "$pending" -eq 0 ] && break
echo "Esperando estabilización... (pendientes=$pending)"
sleep 5
done
echo "--- Estado final de pods ---"
kubectl -n ${NAMESPACE} get pods
'''
}
}
stage('Check Pods & Services') {
steps {
sh '''bash -lc
set -euo pipefail
chmod +x ./check.sh || true
./check.sh
'''
}
}
} // stages
post {
success { echo ' Pipeline OK — listo para el pantallazo' }
failure { echo ' Falló — revisar el final del log' }
always { echo 'Pipeline finalizado.' }
}
}
Comprobación final de la aplicación desplegada:
curl -fsS http://192.168.58.2:30476/ping
Respuesta:
{"status":"ok"}
Autor: Fernando C.C GitHub: https://github.com/inventosfer