View
266
Download
2
Category
Preview:
Citation preview
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
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
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’))
44
Pipeline
Seleccionamos el step que queremos
Especificamos los parámetros
Obtenemos el texto que hay que copiar
en el pipeline
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:"me@example.com", 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á)
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...
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
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
Recommended