jenkins pipeline

63
De lo sencillo a lo más molón Jenkins Pipeline Patxi Gortázar [email protected] @fgortazar

Upload: patxi-gortazar

Post on 28-Jan-2018

259 views

Category:

Software


2 download

TRANSCRIPT

De lo sencillo a lo más molón

Jenkins Pipeline

Patxi Gortá[email protected]

@fgortazar

2

Who?

ElasTest H2020 Project Coordinator

Devops @ Kurento

Teaching distributed systems @etsii_urjc

Haskeller aficionado

@fgortazar

https://es.linkedin.com/in/franciscogortazar

3

Jenkins

•Jenkins es el servidor de CI más popular

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

4

Jenkins

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

Encuesta sobre el uso de servidor CI 2016

5

Jenkins

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

package)

6

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

7

Jenkins

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

8

Jenkins

9

Jenkins

10

Jenkins

Configuramos la cuenta de

administrador

11

Jenkins

12

Jenkins

Configuramos la Jenkins

13

Jenkins

14

Jenkins

Especificamos la ruta al JDK que tengamos

instalado

15

Jenkins

Añadimos Maven para

que se pueda usar en las

tareas (jobs)

16

Jenkins

Ponemos como nombre

“M3”

17

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

18

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)

19

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

20

Jenkins

Creamos una nueva tarea para descargar el proyecto y ejecutar

los tests

21

Jenkins

22

Jenkins

Seleccionamos Github+Maven como

pantilla para el script de pipeline

23

Jenkins

Ejecutamos la nueva

tarea

24

Jenkins

Tarea finalizada correctamente (los tests han pasado)

La tarea ejecuta

varias etapas

25

Jenkins

Podemos ver los logs de cada etapa

26

Jenkins

27

Jenkins

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

28

Jenkins

El jar se ha guardado

Podemos ver los resultados de los

tests

29

Jenkins

Podemos ver toda la salida por

consola

30

JenkinsLas instrucciones de pipeline salen

en gris claro

Las salidas de los comandos en

negro

31

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

32

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

33

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

Indicamos dónde se debe ejecutar. Si no indicamos nada (o any en declarativa) se escogerá uno

cualquiera

34

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

En los scripts puedo declarar variables

globales que podré usar en las

diferentes etapas

35

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

Un pipeline está compuesto de una o

más etapas (stages)

36

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

Dentro de cada etapa puede haber uno o más pasos

(steps)

37

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

Existen diferentes tipos de steps

38

Pipeline

node { def mvnHome stage('Preparation') { git 'https://github.com/jglick/...' mvnHome = tool 'M3' } stage('Build') { if (isUnix()) { sh "'${mvnHome}/bin/mvn' ..." } else { bat(/"${mvnHome}\bin\mvn" ...) } } stage('Results') { junit '**/target/surefire-reports/...' archive 'target/*.jar' }}

pipeline { tools { maven "M3" } agent any stages { stage("Preparation") { steps { git 'https://github.com/jglick/...' } } stage("Build") { steps { sh "mvn -Dmaven.test.failure.ignore ..." } } } post { always {

junit "**/target/surefire-reports/..." } success { archive "target/*.jar" } }}

Declarativa ScriptDeclarativa Script

La forma de utilizar las herramientas configuradas es

diferente

39

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’

40

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’))

41

Pipeline

Hay que desmarcar el sanbox

(no se permite código)

42

Pipeline

Los tres ficheros se archivan

43

Pipeline

Tenemos a nuestra disposición un generador de

steps

44

Pipeline

Seleccionamos el step que queremos

Especificamos los parámetros

Obtenemos el texto que hay que copiar

en el pipeline

45

Tenemos también disponibles

variables globales

46

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

47

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

48

Notificacionespipeline { 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:"[email protected]", subject:"OK: ${currentBuild.fullDisplayName}",body: "Success" } unstable { archiveArtifacts 'logs.txt' } success { archiveArtifacts 'artifact.txt' } }}

49

Builds

● Podemos lanzar otros jobs directamente desde el pipeline● Nos permite definir flujos complejos● Con Scripted pipeline tenemos control total sobre el flujo

50

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á)

51

Builds

52

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

53

Buildsstage('Testing new environment') { steps { parallel ( "kurento_api_audit" : { 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')] } ) }}

Ojo, que son paréntesis...

54

Builds

55

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)?

56

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

57

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

58

Definimos nuestra clase con nuestros

métodos

59

Reutilización

● Shared Libraries: estructura del proyecto

60

ReutilizaciónNos desplazamos a la sección Global Pipeline Libraries

Indicamos el nombre y la versión

a utilizar

Indicamos cómo obtener la librería

61

Reutilización (scripted pipeline)

Cargamos la librería e importamos el

paquete

Usamos la librería de forma normal

62

Reutilización (declarative pipeline)

Cargamos la librería e importamos el

paquete

Usamos la librería dentro de un bloque

script

De lo sencillo a lo más molón

Jenkins Pipeline

Patxi Gortá[email protected]

@fgortazar