Sie sind auf Seite 1von 63

Jenkins

Pipeline
De lo sencillo a lo más molón

Patxi Gortázar
francisco.gortazar@urjc.es
@fgortazar
Who?
ElasTest H2020 Project Coordinator
Devops @ Kurento
Teaching distributed systems @etsii_urjc
Haskeller aficionado
@fgortazar
https://es.linkedin.com/in/franciscogortazar
2
Jenkins

• Jenkins es el servidor de CI más popular


• Es utilizado para construir, para ejecutar tests y
para desplegar cualquier proyecto software

3
Jenkins
Encuesta sobre el uso de servidor CI 2016

https://zeroturnaround.com/rebellabs/java-tools-and-technologies-landscape-2016/
4
Jenkins

• Instalación rápida
– Necesitamos Java 8 o superior
– Vamos a https://jenkins.io/
– Seleccionamos download
– Descargamos la LTS Release (Generic Java
package)
5
Jenkins

• Instalación rápida
– Ejecutamos
$ java -jar jenkins.war --httpPort=8081
– La password de admin aparece en el log o en el fichero
~/.jenkins/secrets/initialAdminPassword
– Nota: Borrar la carpeta ~/.jenkins si ya teníamos
instalado Jenkins de antes y queremos empezar de cero
6
Jenkins

• Instalación rápida
– Accedemos a http://localhost:8081/

7
Jenkins

8
Jenkins

9
Jenkins

Configuramos la
cuenta de
administrador

10
Jenkins

11
Jenkins

Configuramos
la Jenkins

12
Jenkins

13
Jenkins

Especificamos
la ruta al JDK
que tengamos
instalado

14
Jenkins

Añadimos
Maven para
que se pueda
usar en las
tareas (jobs)

15
Jenkins

Ponemos
como nombre
“M3”

16
Jenkins

Creación de tareas (jobs)
– El objetivo de jenkins es ejecutar tareas
– Una tarea es la ejecución de un comando
– Esos comandos pueden terminar correctamente o con error
– La salida del comando se puede consultar mientras se
ejecuta y se guarda para una consulta posterior
– Los comandos pueden generar ficheros que también se
guardan
17
Jenkins

Creación de tareas (jobs)
– Las tareas se pueden ejecutar:

Iniciadas por el desarrollador (manualmente)

Cada cierto tiempo (periódicamente)

Motivadas por un evento externo (nuevo
commit en un repositorio)

18
Jenkins

Creación de tareas (jobs)
– Una tarea típica en Jenkins consiste en:

1) Descargar un proyecto software de un repositorio
git

2) Compilar el proyecto

3) Ejecutar los tests sobre el proyecto

4) Opcionalmente generar un binario/paquete y
publicarlo en algún repositorio de binarios
19
Jenkins

Creamos una nueva


tarea para descargar
el proyecto y ejecutar
los tests

20
Jenkins

21
Jenkins

Seleccionamos
Github+Maven como
pantilla para el script de
pipeline

22
Jenkins

Ejecutamos
la nueva
tarea

23
Jenkins

La tarea
Tarea finalizada ejecuta
correctamente (los varias etapas
tests han pasado)

24
Jenkins

Podemos ver los logs


de cada etapa

25
Jenkins

26
Jenkins

Pinchamos en el
número de ejecución
para ver más detalles

27
Jenkins

El jar se ha
guardado

Podemos ver los


resultados de los
tests

28
Jenkins

Podemos ver toda


la salida por
consola

29
Jenkins
Las instrucciones
de pipeline salen
en gris claro

Las salidas de los


comandos en
negro

30
Pipeline
● Jenkins soporta dos sintaxis de pipelines
– Sintaxis declarativa
● DSL para definir pipelines
● Sencillo de utilizar
● Útil si tu pipeline es sencillo
● Se puede incluir código groovy para cosas más complejas en seccion
– Script (Groovy)
● Se puede utilizar directamente el lenguaje groovy
● Se dispone de librerías específicas para poder utilizar una notación similar a pipelines
declarativos
● Más flexible y potente

31
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { sh "'${mvnHome}/bin/mvn' ..."
sh "mvn -Dmaven.test.failure.ignore ..." } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} }
} }
post { stage('Results') {
always { junit '**/target/surefire-reports/...'
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} }
success { }
archive "target/*.jar"
}
} 32
}
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { Indicamos dónde se sh "'${mvnHome}/bin/mvn' ..."
debe..."
sh "mvn -Dmaven.test.failure.ignore ejecutar. } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} Si no indicamos }
} nada (o any en }
post {
always { declarativa) se stage('Results') {
junit '**/target/surefire-reports/...'
escogerá uno
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} cualquiera } }
success {
archive "target/*.jar"
}
} 33
}
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { En los scripts puedo sh "'${mvnHome}/bin/mvn' ..."
sh "mvn -Dmaven.test.failure.ignore ..."variables
declarar } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} globales que podré }
} usar en las }
post {
diferentes etapas stage('Results') {
always { junit '**/target/surefire-reports/...'
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} }
success { }
archive "target/*.jar"
}
} 34
}
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { sh "'${mvnHome}/bin/mvn' ..."
sh "mvn -Dmaven.test.failure.ignore ..." } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} Un pipeline está }
} }
post { compuesto de una ostage('Results') {
always { más etapas junit '**/target/surefire-reports/...'
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} (stages) }
success { }
archive "target/*.jar"
}
} 35
}
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { sh "'${mvnHome}/bin/mvn' ..."
sh "mvn -Dmaven.test.failure.ignore ..." } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} Dentro de cada }
} }
post { etapa puede haberstage('Results') {
always { uno o más pasos junit '**/target/surefire-reports/...'
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} (steps) }
success { }
archive "target/*.jar"
}
} 36
}
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { sh "'${mvnHome}/bin/mvn' ..."
sh "mvn -Dmaven.test.failure.ignore ..." } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} }
} }
post { Existen diferentes stage('Results') {
always { tipos de steps junit '**/target/surefire-reports/...'
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} }
success { }
archive "target/*.jar"
}
} 37
}
Pipeline
pipeline {
tools {
}
maven "M3"
Declarativa
Declarativa Script
Script
agent any node {
stages { def mvnHome
stage("Preparation") { stage('Preparation') {
steps { git 'https://github.com/jglick/...'
git 'https://github.com/jglick/...' mvnHome = tool 'M3'
} }
} stage('Build') {
stage("Build") { if (isUnix()) {
steps { sh "'${mvnHome}/bin/mvn' ..."
sh "mvn -Dmaven.test.failure.ignore ..." } else {
} bat(/"${mvnHome}\bin\mvn" ...)
} La forma de utilizar }
} }
post { las herramientas stage('Results') {
always { configuradas es junit '**/target/surefire-reports/...'
junit "**/target/surefire-reports/..." archive 'target/*.jar'
} diferente }
success { }
archive "target/*.jar"
}
} 38
}
Pipeline
● Build steps...
– Son funciones disponibles dentro del pipeline
– Los plugins pueden contribuir nuevos steps
– Se pueden utilizar en ambos tipos de sintaxis
– En la mayoría de los casos requieren parámetros
● Los parámetros son pares clave-valor (parámetros nombrados)
● Si sólo hay uno, se puede obviar el nombre
readFile ‘build.properties’
● O no:
readFile file: ‘build.properties’
● Pero si hay varios hay que ponerlos (nótese la coma):
readFile file: ‘build.properties’, encoding: ‘UTF-8’

39
Pipeline
● Build steps...
– Hay tres sintaxis diferentes para invocar steps
● Cuando no hay colisión de nombres, y existe un alias para el step:
archiveArtifacts ‘**.jar’
● Cuando hay colisión de nombres o no hay alias para el step:
step([$class: ‘ArtifactsArchiver’, artifacts: ‘**.jar’])
● Siempre podemos utilizar Groovy plano:
step(new ArtifactArchiver(‘**.jar’))

40
Pipeline

Hay que desmarcar


el sanbox
(no se permite
código)

41
Pipeline

Los tres ficheros se


archivan

42
Pipeline

Tenemos a nuestra
disposición un
generador de
steps

43
Pipeline
Seleccionamos el
step que queremos

Especificamos los
parámetros

Obtenemos el texto
que hay que copiar
en el pipeline
44
Tenemos también
disponibles
variables globales

45
Notificaciones
● Podemos añadir acciones al final del job
– Se ejecutarán al finalizar dependiendo del estado
– Interesante para mandar correos o archivar artefactos
– Podemos ejecutar unas acciones u otras en función del estado del job:
● Always: acciones que se ejecutarán siempre
● Success: acciones para ser ejecutadas si el job tiene éxito
● Failure: acciones para ser ejecutadas si el job falla
● Unstable: acciones que se ejecutarán si el job tiene test fallidos
● Changed: acciones que se ejecutarán sólo si el estado de la ejecución actual difiere
del estado de la ejecución anterior
● Aborted: acciones que se ejecutarán si el job se para manualmente

46
Notificaciones
● Por ejemplo:
– Enviar un correo cuando el job cambie de estado
– Archivar artefactos cuando el job tenga éxito
– Archivar logs cuando el job sea inestable

47
Notificaciones
pipeline {
agent any
stages {
stage('Prepara') {
steps {
writeFile encoding: 'utf-8', file: 'artifact.txt', text: 'Hello, world!'
writeFile encoding: 'utf-8', file: 'logs.txt', text: 'Core dumped!'
}
}
}
post {
changed {
mail to:"me@example.com", subject:"OK: ${currentBuild.fullDisplayName}",body: "Success"
}
unstable {
archiveArtifacts 'logs.txt'
}
success {
archiveArtifacts 'artifact.txt'
}
}
} 48
Builds
● Podemos lanzar otros jobs directamente desde el pipeline
● Nos permite definir flujos complejos
● Con Scripted pipeline tenemos control total sobre el flujo

49
Builds

node {
stage('First sample') {
Build job: 'StepSyntaxArchiveArtifacts',
propagate: false
}

stage('Second sample') {
build 'DeclarativePipeline'
} Evita propagar el
} error si el job fallara
(el segundo stage
siempre se
ejecutará)

50
Builds

51
Builds

stage('Update ci environments') {
steps {
build job: 'Development/run_ansible',
propagate: false

build job: 'Development/kurento_ci_build',


propagate: false,
parameters: [string(name: 'GERRIT_REFSPEC', value: 'master')]
}
}
Podemos pasar
parámetros al job

52
stage('Testing new environment') { Ojo, que son
Builds
steps {
parallel (
"kurento_api_audit" : {
paréntesis...

build job: 'Development/kurento_api_audit', propagate: false,


parameters: [string(name: 'GERRIT_REFSPEC', value: 'master')]
},
"kurento_app_audit" : {
build job: 'Development/kurento_app_audit', propagate: false,
parameters: [string(name: 'GERRIT_REFSPEC', value: 'master')]
},
"capability_functional_audit" : {
build job: 'Development/capability_functional_audit', propagate: false,
parameters: [string(name: 'GERRIT_REFSPEC', value: 'master')]
},
"capability_stability_audit" : {
build job: 'Development/capability_stability_audit', propagate: false,
parameters: [string(name: 'GERRIT_REFSPEC', value: 'master')]
},
"webrtc_audit" : {
build job: 'Development/webrtc_audit', propagate: false,
parameters: [string(name: 'GERRIT_REFSPEC', value: 'master')]
}
)
}
} 53
Builds

54
Reutilización
● Supongamos que tenemos varios jobs muy similares entre sí
– Comparten stages
– Comparten configuraciones específicas
● Supongamos que tenemos que cambiar algo de esa parte común
– Refactorizar un stage compartido entre varios jobs
– Cambiar algún parámetro
– …
● Preferiría no tener que cambiar los jobs uno a uno
– Incluso usando Jenkinsfile dentro de proyectos esto es un engorro cuando varios proyectos
comparten una misma estructura de Jenkinsfile
● ¿Qué puedo hacer? ¿Estoy vendido? ¿Y si son 50 jobs (de verdad NO OS HA
PASADO)?
55
Reutilización
● La solución se llama Shared Libraries
– Librerías Groovy que puedo utilizar en los pipelines
– Tienen que estar disponibles en un repositorio de código
– Se dan de alta en la configuración global de Jenkins
– Se importan en el pipeline y se utilizan

56
Reutilización
● Shared Libraries: estructura del proyecto

(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
| +- foo.txt # help for 'foo' variable
+- resources # resource files (external libraries
only)
| +- org
| +- foo
| +- bar.json # static helper data for org.foo.Bar

57
Definimos nuestra
clase con nuestros
métodos

58
Reutilización
● Shared Libraries: estructura del proyecto

59
Reutilización
Nos desplazamos a
la sección Global
Pipeline Libraries

Indicamos el
nombre y la versión
a utilizar

Indicamos cómo
obtener la librería

60
Reutilización (scripted pipeline)

Cargamos la librería
e importamos el
paquete

Usamos la librería
de forma normal

61
Reutilización (declarative pipeline)

Cargamos la librería
e importamos el
paquete

Usamos la librería
dentro de un bloque
script

62
Jenkins
Pipeline
De lo sencillo a lo más molón

Patxi Gortázar
francisco.gortazar@urjc.es
@fgortazar

Das könnte Ihnen auch gefallen