Construye tu primer Pipeline Declarativo de Jenkins para CI/CD

Construye un primer Pipeline Declarativo de Jenkins con etapas, agentes, checkout, pruebas, compuertas de despliegue, credenciales y acciones posteriores.

Construye tu primer Pipeline Declarativo de Jenkins para CI/CD

Tu primer Pipeline Declarativo de Jenkins debería responder una pregunta práctica: ¿puede Jenkins revisar tu código, compilarlo, probarlo y ejecutar pasos de despliegue solo cuando la rama correcta pasa? Un Jenkinsfile te da ese flujo de trabajo como código en el mismo repositorio que tu aplicación.

La sintaxis declarativa es un buen punto de partida porque te da una estructura predecible: pipeline, agent, stages, steps y post.

Entendiendo la Estructura del Pipeline Declarativo

El Pipeline Declarativo define todo el flujo de trabajo en un archivo llamado Jenkinsfile, que se almacena junto con el código de tu aplicación en tu repositorio SCM (por ejemplo, Git). Esta práctica se conoce como Pipeline como Código.

Elementos Clave de un Pipeline Declarativo

Un Pipeline Declarativo debe contener los siguientes bloques de nivel superior:

  1. pipeline: El bloque externo obligatorio que define el contenido del pipeline.
  2. agent: Especifica dónde se ejecutará el pipeline o una etapa específica (por ejemplo, any, none o etiquetas específicas).
  3. stages: Contiene uno o más bloques stage secuenciales.
  4. stage: Define un bloque conceptual de trabajo (por ejemplo, Compilar, Probar, Desplegar).
  5. steps: Contiene uno o más comandos o funciones ejecutados dentro de un stage.
pipeline {
    agent any 
    environment { // Opcional: Define variables de entorno
        APP_VERSION = '1.0.0'
    }
    stages {
        stage('Build') {
            steps {
                // Los comandos van aquí
            }
        }
    }
    post { // Opcional: Acciones que se ejecutan después de que el pipeline finaliza
        always { 
            echo 'Pipeline finalizado.' 
        }
    }
}

Paso 1: Configurando el Trabajo de Jenkins

Para ejecutar un Pipeline desde el código, necesitas configurar un trabajo de Jenkins para que lea el Jenkinsfile desde tu repositorio.

  1. Navega a tu panel de Jenkins y selecciona Nuevo elemento.
  2. Ingresa un nombre para tu pipeline (por ejemplo, mi-primer-pipeline-ci).
  3. Selecciona el tipo de elemento Pipeline y haz clic en Aceptar.
  4. En la página de configuración, desplázate hacia abajo hasta la sección Pipeline.
  5. Cambia la definición de Script de Pipeline a Script de Pipeline desde SCM.
  6. Selecciona tu SCM (por ejemplo, Git).
  7. Ingresa la URL del Repositorio y configura tus credenciales si es necesario.
  8. Asegúrate de que la Ruta del Script esté configurada en Jenkinsfile (el valor predeterminado).

Paso 2: Definiendo el Jenkinsfile para CI/CD

Crearemos un Jenkinsfile completo que simule un flujo de trabajo simple de CI/CD, integrando etapas estándar para un despliegue exitoso.

Supón que tienes una estructura de repositorio que contiene el código fuente de tu aplicación (por ejemplo, un proyecto simple de Python o Java) y el Jenkinsfile en la raíz.

Ejemplo Completo de Pipeline Declarativo

Este pipeline utiliza el agente node (si está configurado) y utiliza pasos básicos de shell (sh) para simular trabajo real. La etapa de despliegue es condicional, ejecutándose solo al completar exitosamente las etapas anteriores.

// Jenkinsfile
pipeline {
    // 1. Definición del Agente: Especifica dónde se ejecuta todo el pipeline
    agent { 
        label 'mi-agente-de-compilacion' // Usa una etiqueta específica si está disponible, o 'any'
    }
    
    // 2. Variables de Entorno: Define variables utilizables en todo el pipeline
    environment {
        REGISTRO_CONTENEDORES = 'registry.example.com'
        NOMBRE_IMAGEN = 'miapp'
    }
    
    stages {
        
        // Etapa 1: Checkout (Gestión de Código Fuente)
        stage('Checkout Fuente') {
            steps {
                // El paso 'checkout scm' revisa automáticamente el código 
                // según la configuración definida en la configuración del trabajo de Jenkins.
                checkout scm
                sh 'echo "Código fuente revisado exitosamente."'
            }
        }
        
        // Etapa 2: Compilar Artefactos
        stage('Compilar Artefacto') {
            steps {
                sh 'echo "Iniciando compilación para $NOMBRE_IMAGEN:$BUILD_ID"'
                // Simulación: Compilar una imagen Docker o un archivo jar/war
                sh "docker build --label build_id=${BUILD_ID} -t ${REGISTRO_CONTENEDORES}/${NOMBRE_IMAGEN}:${BUILD_ID} ."
            }
        }
        
        // Etapa 3: Pruebas y Compuertas de Calidad
        stage('Ejecutar Pruebas') {
            steps {
                sh './run_unit_tests.sh'
                sh 'echo "Ejecutando pruebas de integración..."'
                // Ejemplo de recolección de resultados de pruebas (requiere plugins apropiados)
                // junit '**/target/surefire-reports/*.xml'
            }
        }
        
        // Etapa 4: Despliegue (Condicional)
        stage('Desplegar en Staging') {
            // La directiva 'when' asegura que la etapa solo se ejecute bajo condiciones específicas
            when {
                branch 'main'
            }
            steps {
                sh "docker push ${REGISTRO_CONTENEDORES}/${NOMBRE_IMAGEN}:${BUILD_ID}"
                sh 'kubectl apply -f k8s/deployment-staging.yaml'
                script {
                    // Los bloques script permiten lógica Groovy tradicional dentro de pasos declarativos
                    echo "Despliegue exitoso en el entorno de Staging."
                }
            }
        }
    }
    
    // 3. Acciones Posteriores: Define acciones basadas en el estado final del pipeline
    post {
        success {
            echo 'Pipeline completado exitosamente. Notificando al equipo por Slack...'
            // slackSend channel: '#devops-alerts', message: '¡CI/CD Exitoso!'
        }
        failure {
            echo 'Pipeline fallido. Revisa los registros para errores.'
        }
        cleanup {
            sh 'docker image prune -f --filter "label=build_id=$BUILD_ID"'
        }
    }
}

Paso 3: Ejecutando y Monitoreando el Pipeline

Una vez que el Jenkinsfile se haya confirmado y enviado a la rama configurada en tu trabajo de Jenkins:

  1. En la página del trabajo de Jenkins, haz clic en Compilar ahora (o espera la encuesta SCM/disparador webhook).
  2. Monitorea la compilación en el panel Historial de Compilaciones.
  3. Haz clic en el número de compilación en ejecución y selecciona Salida de Consola para ver los detalles de ejecución paso a paso.
  4. También puedes usar la visualización de Vista de Etapas (si el plugin está instalado) para ver el progreso de las etapas Checkout, Compilar, Probar y Desplegar gráficamente.

Mejores Prácticas y Características Avanzadas

Utilizando Bibliotecas y Código Compartido

Para pasos complejos o altamente repetitivos, evita escribir Groovy verboso directamente en el Jenkinsfile. En su lugar, usa Bibliotecas Compartidas. Estas bibliotecas externas te permiten definir funciones comunes (como rutinas de despliegue estándar o funciones de notificación) que pueden ser llamadas desde múltiples pipelines, haciendo tu Jenkinsfile más limpio.

// Llamando a un paso de biblioteca compartida
stage('Configuración Personalizada') {
    steps {
        bibliotecaPersonalizada.inicializarEntorno(env: 'prod')
    }
}

Trabajando con Credenciales

Nunca codifiques información sensible (contraseñas, tokens, claves API) directamente en el Jenkinsfile. Usa el sistema integrado de Gestión de Credenciales de Jenkins.

El paso withCredentials te permite acceder de forma segura a secretos almacenados:

stage('Autenticar Registro') {
    steps {
        withCredentials([usernamePassword(credentialsId: 'docker-registry-creds', 
                                          passwordVariable: 'PASS', 
                                          usernameVariable: 'USER')]) {
            sh '''
                printf '%s' "$PASS" | docker login \
                  --username "$USER" \
                  --password-stdin "$REGISTRO_CONTENEDORES"
            '''
        }
    }
}

Selección de Agente

Consejo: Siempre define tu agent específicamente usando una label en lugar de agent any. Usar agent any significa que el pipeline podría ejecutarse en el nodo controlador de Jenkins, lo cual es un riesgo de seguridad y puede afectar el rendimiento del controlador. Asegúrate de tener agentes (nodos) de Jenkins correctamente configurados con las herramientas necesarias (Docker, Maven, Node.js) instaladas.

Conclusión

Mantén el primer pipeline aburrido y confiable: elige una etiqueta de agente real, revisa el código, compila, prueba, controla el despliegue por rama y mantén los secretos en las credenciales de Jenkins. Una vez que funcione, agrega publicación de artefactos, escaneo de seguridad y promoción de entornos paso a paso.