Introducción a Jenkins para principiantes - CI/CD

En esta guía para principiantes, conoceremos Jenkins, el servidor de automatización de CI/CD, y ejecutaremos y automatizaremos el proceso de compilación de un proyecto simple.

Introducción

El advenimiento del desarrollo acelerado con muchas metodologías como Scrum, Agile y Kanban trajo consigo algunos problemas clave: los desarrolladores que trabajaban en pequeños incrementos pasaron mucho tiempo esperando que se compilara la nueva versión, llegara a los probadores y finalmente se despliega. El proceso de desarrollo sería mucho más rápido si este ciclo eliminara la intervención humana siempre que fuera posible.

Surgió la idea de servidores de automatización. A lo largo de los años, muchas soluciones aparecieron y desaparecieron, pero Jenkins logró llegar a la cima y convertirse en el estándar en lo que respecta a la automatización. Si bien es perfecto para programar y ejecutar secuencias de comandos de shell o por lotes de forma sencilla, al ser de código abierto y contar con un gran apoyo de la comunidad, Jenkins proporciona una fácil integración con muchas herramientas, plataformas y marcos con más de 1500 complementos que hacen que todo el proceso sea sencillo.

Conceptos clave de Jenkins

Para comprender por qué alguien debería usar Jenkins, debemos comprender cuáles son los problemas que Jenkins pretende resolver.

La canalización de CI/CD

De principio a fin, hay varias etapas en el ciclo de vida del software. La automatización nos ayuda a cerrar las brechas entre ellos, haciendo que todo el proceso sea perfecto. Tomando como ejemplo un flujo de trabajo común y corriente: un servidor de automatización escuchará las nuevas versiones de desarrollo, las buscará y ejecutará los comandos apropiados para construir y probar la nueva versión, y finalmente pondrá la nueva versión en producción si todo fue exitoso.

Todas estas etapas, que están formadas por pasos más pequeños, deben definirse en tiempo y orden como una sola canalización.

La arquitectura del controlador-agente

Para repartir la carga de compilaciones y tareas simultáneas, Jenkins presenta la arquitectura Controller-Agent. El "Controlador" - el servidor Jenkins es responsable de administrar proyectos, configuraciones, usuarios y datos. "Agentes" pueden ser llamados para ejecutar ciertas etapas de una canalización en particular. Esto brinda muchos beneficios, como escalabilidad fácil, hardware óptimo (procesos matemáticos a gran escala o con gran cantidad de datos), servidores de prueba y compilaciones específicas de la plataforma.

Complementos

Los complementos son el núcleo del éxito de Jenkins. Cualquier desarrollador de Java puede escribir su propio complemento y compartirlo con la comunidad. Jenkins enfatiza mucho esto y ha escrito algunas guías muy detalladas sobre el tema. Independientemente de la herramienta que desee utilizar en la tubería, Jenkins probablemente lo tenga cubierto con un complemento que hace que todo el proceso de configuración e integración con esa herramienta sea muy sencillo.

Además del aspecto del flujo de trabajo, hay muchos complementos escritos directamente para administrar el propio Jenkins, desde una interfaz de usuario más bonita hasta una administración más sencilla de múltiples usuarios y sus privilegios de acceso.

Convenciones de nomenclatura {#convenciones de nomenclatura}

A lo largo del ciclo de vida de Jenkins, la nomenclatura cambió un poco, entre otras cosas debido al hecho de que cierta terminología puede verse como ofensiva.

Aunque hace años se introdujeron ciertas convenciones de nomenclatura, la comunidad todavía las usa indistintamente. Para evitar confusiones, aquí hay algunos términos sinónimos:

  • Maestro == Controlador
  • Esclavo == Agente
  • Trabajo == Proyecto
  • Flujo de trabajo == Canalización

La antigua arquitectura Maestro/Esclavo pasó a llamarse arquitectura Controlador/Agente, debido a las connotaciones negativas de la terminología.

Instalación

Hay muchas formas de instalar Jenkins. Junto con las instalaciones específicas de la plataforma, muchas plataformas de alojamiento en la nube ofrecen paquetes de Jenkins preconfigurados. También existe una imagen oficial de Docker, así como un archivo war genérico de Java.

Esta guía cubrirá el proceso de instalación en Ubuntu 20.04, aunque el proceso no difiere mucho para Windows, Mac u otras distribuciones. Consulte la página de descarga de Jenkins para su máquina específica (o servicio en la nube).

Instalación de un JDK/JRE

Al estar escrito en Java, Jenkins requiere un Java Runtime Environment para ejecutarse. Tenga en cuenta que para OpenJDK, solo se admiten las versiones 8 y 11. Si desea crear aplicaciones Java con Jenkins, deberá instalar un JDK en lugar de solo el JRE.

Avancemos e instalemos openjdk-11-jdk:

1
$ sudo apt install openjdk-11-jdk

Actualización de la lista de fuentes e instalación con apt

Jenkins no está disponible en el repositorio oficial de Linux, por lo que tendremos que agregar su propio repositorio. Vamos a instalar la versión LTS (Long-Term Support) que se actualiza cada 12 semanas, según el sitio web de Jenkins.

Para la vanguardia, si, por ejemplo, desea desarrollar complementos, elimine la parte -estable de la primera y segunda líneas a continuación:

1
2
3
4
5
$ wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
$ sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > \
        /etc/apt/sources.list.d/jenkins.list'
$ sudo apt update
$ sudo apt install jenkins

Finalmente, podemos continuar y registrar Jenkins como un servicio y ejecutarlo a través de la terminal:

1
2
$ sudo systemctl daemon-reload
$ sudo systemctl start jenkins

Acceder a Jenkins desde el navegador {#acceder a Jenkins desde el navegador}

De forma predeterminada, Jenkins está alojado en el puerto 8080.

Si ha instalado Jenkins en su máquina local, se puede acceder desde el navegador navegando a localhost: 8080. Si lo instaló en una máquina virtual, ejecutar el comando ifconfig (parte de net-tools) revelará la dirección IP de la máquina virtual en su red local.

Al iniciar Jenkins por primera vez, se requiere una contraseña oculta. Se puede encontrar en /var/lib/jenkins/secrets/initialAdminPassword, escrito en el servidor. Recupérala e ingrésala para continuar:

Contraseña secreta de Jenkins

En la segunda página, elija la opción Instalar complementos sugeridos. La instalación del complemento se trata más adelante en esta guía. Espere a que se instalen los complementos, configure una cuenta de administrador, configure la URL de Jenkins (en nuestro caso, la dejaremos en localhost:8080) para que otros accedan, y se le presentará el Panel de control :

Panel de Jenkins

Usando Jenkins

Jenkins es un proyecto grande y complejo, y cubriremos la mayoría de las funciones más importantes.

Para hacerlo, cubriremos tres ejemplos de flujo de trabajo:

  • Usar el navegador para construir un proyecto Maven con notificaciones por correo electrónico.
  • Conectarse a un repositorio de GitHub y compilar nuestra aplicación Maven con el Jenkinsfile del repositorio.
  • Usar jenkins-cli.jar para realizar tareas cotidianas, como manipular trabajos, iniciar compilaciones, verificar registros, etc. desde la línea de comandos.

Usaremos un proyecto ficticio de Maven, hecho para esta guía.

Compilación local simple

Para configurar fácilmente Maven, instalaremos un complemento de Maven para Jenkins.

Instalación de complementos {#instalación de complementos}

Vaya a la opción Administrar complementos dentro de la sección Administrar Jenkins:

Elemento del menú Administrar complementos

Con la pestaña Disponible seleccionada, busque "Maven" y marque la casilla adyacente. Seleccione Instalar sin reiniciar:

Complemento de integración de Maven

Espere a que se instale el complemento antes de continuar.

Configuración de Maven {#configuración de Maven}

Desde la sección Administrar Jenkins, vaya a Configuración global de herramientas. Desplácese hasta la parte inferior y agregue una instalación de Maven. Guarde los nuevos cambios.

Agregar una instalación de Maven

Configuración del correo electrónico

Vaya a Configurar sistema dentro de Administrar Jenkins. Navegue hacia abajo hasta Notificación de correo electrónico y configure una dirección de correo electrónico que usará Jenkins. Tenga en cuenta que Google y muchos otros servicios requieren la configuración de contraseñas específicas de la aplicación, por motivos de seguridad.

Creación de un proyecto

Selecciona Nuevo elemento en la barra lateral, dale un nombre a tu proyecto y márcalo como Proyecto Maven antes de presionar Aceptar:

Creando un proyecto Maven

En la parte inferior, configure la ubicación del archivo POM y configure el paso adicional de publicación para enviar notificaciones por correo electrónico. Tenga en cuenta que, en sistemas similares a Unix, Jenkins crea un usuario jenkins separado, por lo que es posible que se requieran privilegios de acceso.

El "Disparador" predeterminado para enviar correos electrónicos es una compilación fallida, pero eso se puede cambiar en la Configuración avanzada.

Ejecutar la compilación {#ejecutar la compilación}

Con los pasos configurados, podemos iniciar la compilación. La barra lateral nos informará del progreso, así como también nos mostrará el historial de compilación. Las compilaciones fallidas (#1) mostrarán un color diferente.

Navegue a la opción Salida de consola para obtener más detalles:

Barra lateral del proyecto

Seguimiento de un GitHub Repo y lectura de su archivo Jenkins

Tuvimos que repasar el ejemplo más simple anterior para tener una idea de cómo funciona Jenkins. El siguiente ejemplo es, con mucho, la forma más frecuente en que se configurará cualquier canalización. Tener la configuración de la canalización ubicada dentro de un archivo de texto y dentro de un CVS permite una mayor portabilidad y capacidad de ajuste.

Para impulsar nuestros cambios en sentido ascendente, o si se trabaja en un repositorio privado, tendremos que autenticar a Jenkins en GitHub. También apuntaremos a Jenkins en la dirección del Jenkinsfile, que generalmente se encuentra dentro de la raíz del repositorio.

El Jenkinsfile es solo un archivo que contiene la definición de una canalización. Se supone que debe verificarse en el control de fuente. Usando Jenkinsfile, Jenkins puede ejecutar canalizaciones.

Credenciales de GitHub

Para acceder de forma segura a GitHub, generaremos un par de claves, registraremos la clave privada en Jenkins y escribiremos la clave pública en la lista de implementación del repositorio de GitHub. De esa manera, podemos tener código público de código abierto (o simplemente código compartido entre colegas) mientras mantenemos la seguridad.

Para generar el par de claves, usaremos el comando ssh-keygen:

1
$ ssh-keygen -t rsa -b 4096

Elija dónde almacenar las claves y establezca una contraseña si lo desea.

A continuación, copie la clave privada y vaya al panel de Jenkins. Desde allí, en Administrar Jenkins, vaya a Administrar credenciales -> Jenkins -> Credenciales globales -> Agregar credenciales.

Seleccione Nombre de usuario SSH con clave privada, pegue la clave junto con su frase de contraseña y presione Aceptar.

Añadiendo Credenciales SSH a Jenkins

Copie la clave pública y péguela en la lista de claves de implementación de su repositorio, ubicada en https://github.com/user/repo/setting/keys/new. Asígnele un nombre, marque la casilla para permitir el acceso de escritura si desea que los cambios formen parte de su canalización y presione Agregar tecla.

Lista de implementación de un repositorio de GitHub

Ahora es el momento de crear el proyecto y configurarlo.

Creando el Proyecto

Desde el tablero, vaya a Nuevo elemento -> Canalización multisucursal. Dale un nombre y continúa. En Fuentes de rama, seleccione git, asigne un nombre a la fuente, escriba la dirección del repositorio y seleccione las credenciales adecuadas que acabamos de agregar. Guarde los cambios y continúe.

Haremos que nuestro proyecto escuche los cambios en el repositorio desplazándonos hacia abajo hasta Escanear disparadores de canalización de múltiples ramas y marcando la casilla pequeña, seleccionando 1 minuto como nuestro intervalo deseado. Presiona guardar.

Nota: Si al lado de Git, ves GitHub como una opción, eso significa que tienes instalado el complemento de GitHub. El uso de GitHub como la fuente de la sucursal requiere que use una combinación de nombre de usuario/contraseña o nombre de usuario/credenciales de token, que permite el acceso a todos los repositorios para los que la cuenta está autorizada.

La ruta Git también es la más genérica, ya que el procedimiento es el mismo para cualquier repositorio Git remoto: no tiene que estar alojado en GitHub, pero tal vez en el servidor de una empresa o en un servidor diferente. servicio de alojamiento como BitBucket y GitLab.

Hasta ahora, nuestro proyecto solo buscará cambios en nuestro repositorio de Git. Vamos a escribir el archivo Jenkins para que Jenkins sepa lo que se supone que debe hacer.

Escribir un Jenkinsfile

Para definir un conjunto de procedimientos para ejecutar, una tubería, usamos Jenkinsfiles. Al igual que Docker se basa en Dockerfiles como una lista de comandos para ejecutar, también lo hace Jenkins. Jenkinsfiles usa una sintaxis similar a Groovy.

Avancemos y escribamos un script similar a Groovy, llamado "Jenkinsfile" (sin extensión) y confirmémoslo/empújelo a la raíz de nuestro repositorio:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
pipeline {
    agent any
    stages{
        stage('build'){
            steps {
                sh 'mvn clean install'
            }
        }
    }
    post {
        always {
            mail to :"[correo electrónico protegido]",
                subject: "Build Finished: ${currentBuild.fullDisplayName}",
                body:"Check out status at ${env.BUILD_URL}"
        }
    }
}

Esta sintaxis simple es muy legible y bastante autoexplicativa. Hemos definido una canalización, que puede ser ejecutada por cualquier agente disponible. Solo hay una etapa (‘construir’`), que ejecutará un comando de shell para construir nuestro código.

Después de que finalice la etapa, se enviará un correo electrónico para notificar que la canalización finalizó, proporcionando información y un enlace a la URL de la compilación para obtener más información.

Este proceso, o cualquier otro si tuviéramos que hacer cambios en el archivo Jenkins, se ejecutará cada vez que se envíe una nueva confirmación al repositorio.

Tareas menores en la línea de comandos

Para evitar usar la ruta del navegador para las tareas cotidianas, como iniciar/detener trabajos, verificar la salida de la consola de una compilación o importar/exportar, necesitaremos descargar jenkins-cli.jar.

Se incluye con cada instalación de Jenkins:

1
$ wget localhost:8080/jnlpJars/jenkins-cli.jar

Para ver si podemos conectarnos a Jenkins, escribamos el siguiente comando:

1
2
3
4
$ java -jar jenkins-cli.jar http://localhost:8080 who-am-i
Authenticated as: anonymous
Authorities:
  anonymous

La conexión fue exitosa. Conectémonos con un usuario con mayores permisos para poder administrar proyectos, complementos, compilaciones, etc. Para evitar escribir nuestra contraseña en la consola, se puede configurar un token de API.

Generación de un token de API

Vamos a crear un token para nuestro usuario administrador, siga los pasos de la imagen y copie el texto que recibimos:

Obtener un token de API

Para especificar un usuario, usaremos la opción -auth que recibe el [USER:SECRET | @FILE] parámetros. Pongamos nuestro nombre de usuario:token en un archivo llamado credenciales al que haremos referencia cuando nos conectemos.

1
2
3
4
$ java -jar jenkins-cli.jar -s http://localhost:8080 -auth @credentials who-am-i
Authenticated as: admin
Authorities:
    authenticated
Listado de trabajos y compilaciones en ejecución

Para enumerar y ejecutar nuestros trabajos, usaremos los comandos list-jobs y build, y usaremos el comando console para obtener el resultado. Tenga en cuenta que GitHub Maven App, al ser un proyecto de varias ramas, requiere especificar la rama con la sintaxis project/branch, en nuestro caso `GitHub Maven/Maven':

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ java -jar jenkins-cli.jar -s http://localhost:8080 -auth @credentials list-jobs
GitHub Maven App
Maven App
$ java -jar jenkins-cli.jar -s http://localhost:8080 -auth @credentials build 'GitHub Maven App/Maven'
$ $ java -jar jenkins-cli.jar -s http://localhost:8080 -auth @credentials console 'GitHub Maven App/Maven'
Started from command line by
                            admin
Running as SYSTEM
Building in workspace /var/lib/jenkins/workspace/Maven App
Parsing POMs
.
.
.
Importación/exportación de trabajos existentes

Todas las configuraciones en Jenkins se definen con XML. Esto facilita la reutilización de configuraciones existentes o la importación de nuevas. Además de las definiciones de proyectos, las configuraciones globales como complementos y credenciales están escritas en XML.

jenkins-cli brinda soporte para importar y exportar con los comandos get-job y create-job que toman XML como su parámetro. El siguiente código duplica nuestro proyecto Maven en uno nuevo:

1
2
$ java -jar jenkins-cli.jar -s http://localhost:8080 -auth @credentials get-job 'Maven App' > myMavenProject.xml
$ java -jar jenkins-cli.jar -s http://localhost:8080 -auth @credentials create-job 'new Maven App' < myMavenProject.xml

Conclusión

El punto clave aquí es el poder de la automatización. Vale la pena invertir algo de tiempo y esfuerzo en una poderosa herramienta, configurar todo con cuidado y nunca más perder el tiempo haciendo trabajo manual. El retorno de la inversión es invaluable.

Esta guía pretende ser una introducción al poder y la extensibilidad de Jenkins. Con los principios básicos bien entendidos, su conocimiento de Jenkins se disparará una vez que comience a experimentar con diferentes proyectos, mezclando y combinando diferentes herramientas de construcción, lenguajes y entornos de construcción.

If you're eager to continue your Jenkins journey - you can check our guide on Programación de trabajos en Jenkins or Configuración de comprobaciones cerradas para proyectos Spring Boot en GitHub. ).