vagrant box add jenkins-lab-demo http://bit.ly/2Bl1hfI
ENSG - Décembre 2017
Présentation disponible à l’URL https://dduportal.github.io/ensg-ci-cd/cicd-ensg-2017-dec
This work is licensed under a Creative Commons Attribution 4.0 International License
Pour naviguer, utilisez les flèches en bas à droite (ou celles de votre clavier)
Gauche/Droite: changer de chapitre
Haut/Bas: naviguer dans un chapitre
Pour avoir une vue globale : utiliser la touche "o" (pour "Overview")
Pour voir les notes de l’auteur : utilisez la touche "s" (pour "Speaker notes")
Training Engineer @ CloudBees
Docker & Apple fanboy.
Human stack focused
Rock climber
Contact:
Twitter: @DamienDuportal
Github: dduportal
eMail: damien.duportal@gmail.com
Découvrir (ou redécouvrir) les bases des éléments de la "chaîne de production logicielle"
SCM, Tests, Sécurité, etc.
Découvrir les concepts de l’Intégration Continue et du Déploiement Continu
Découvrir Jenkins
Mettre en oeuvre Jenkins en tant que dévelopeur
2 jours ensemble
Matin:
09:00 → 10:30
11:00 → 12:30
Après-Midi:
13:30 → 15:00
15:30 → 17:00
QCM: 25 % de la note
Rendu de TP: 75 % de la note
But : évaluer l’acquisition des concepts théoriques autour du CI/CD
Format :
10 questions à choix multiples portant sur les 2 jours
Pas de points négatifs
Temps limité: 15 minutes
But : évaluer l’acquisition de compétences de mise en oeuvre basiques autour du CI/CD
Format:
Rendu public dans GitHub : valorisable sur vos CVs
Réutilisation d’un de vos projets
Temps:
Estimation du travail personnel: 4h +- 1h
Dates de remise des consignes et rendus à définir ensemble
3 semaines entre les deux
"Gestion de Code Source"
Les Gestionnaires de Code Source, également connus comme "Version Control Systems" (VCS):
Sont des systèmes logiciels
Conservent toutes les modifications apportées à une collection de fichiers, dans le temps
Permettent de partager ces changements
Fournissent des fonctionnalités de merge et de suivi des modifications
Pour collaborer efficacement sur un même référentiel de code source
Aide à la résolution de conflits
Partage de contenu facile
Pour conserver une trace de tous les changements : On parle de source unique de vérité (Single Source of Truth)
Historique complet des modifications
Possibilité de retour arrière à tout moment
Locaux
Centralisés
Distribués
Plus vieux type, ancêtre de tous les autres
Uniquement historique de modification
Utilise une "base de donnée de versions" des fichiers
Stockage uniquement des différences ("diff")
Pas de partage
Exemple: rcs (toujours dans Apple XCode Tools)
Couvre historique ET partage
La "base de données de versions" est stockée sur un serveur central
Chaque client ne possède qu'une seule version du code
Apprentissage très facile, limité sur la résolution de conflits
Exemples: CVS, SVN, Perforce, TFS
La "base de données de versions" est distribuée par duplication sur chaque noeud
Exemples: Git, Mercurial, Bazaar, Monotone
Hébergés dans le Cloud
Hébergé "à la maison"
SCM as a Service
Le serveur centralisé est un service hébergé par un fournisseur
Avantages:
Pas de temps/énergie passés sur la gestion
Associent au SCM d’autre services : gestionnaire de tickets, wiki, éditeur de texte online, etc.
Risque: Votre code est hébergé par un tiers
Exemples: GitHub, Bitbucket by Atlassian, Amazon CodeCommit, Visual Studio Online by Microsoft, SourceForge, GitLab.com, etc.
Pour pallier au risque précédent, on trouve des versions "On-Premide" (généralement payantes)
Le monde de l’Open Source fourni également des solutions à héberger soit-même
Très souvent gratuit et on peut le corriger
Temps et énergie à consacrer
Exemples: Gitlab, Gitea, Gogs, Bazaar server, VisualSVN Server, etc.
diff: un ensemble de lignes "changées" sur un fichier donné
changeset: un ensemble de "diff" (donc peut couvrir plusieurs fichiers)
commit: Action de sauvegarder un changeset dans la base de données des versions.
Le dernier commit dans l’historique est aliasé comme "HEAD"
Abstraction d’une version "isolée" du code
Concrètement, une branche est un alias pointant vers un "commit"
On intègre une branche dans une autre en effectuant un merge
Un nouveau commit est créé, fruit de la combinaison de 2 autres commits
Une Pull Request (ou "Merge Request") est une procédure de revue de code avant intégration
Voici quelques motifs d’utilisation des SCMs :
"Centralized" Flow
"Feature Branch" Flow
"Git" Flow
"GitHub" Flow
Une seule branche par fonctionnalité
"Infrastructure as Code" :
Besoins de traçabilité, de définition explicite et de gestion de conflits
Collaboration requise pour chaque changement (revue, responsabilités)
Code Civil:
Un peu de lecture :
Le code est donc sujet à erreurs: Conséquences?
Les tests identifient ces erreurs, dans un but de correction
Le test logiciel est une pratique suivant 2 piliers :
Valider que le logiciel remplisse les rôles qui lui sont confiés
Rechercher les fautes pour les corriger, améliorant la qualité du système
Automatiser : répétition et reproductibilité
Test Manuel à considérer dans peu de cas, quand :
Coût de l’automatisation dépasse sa valeur
Automatisation impossible
SUT: "System Under Testing". Défini les frontières du système.
Test Double: Terme générique désignant un sous-ensemble simplifié du "S.U.T.". Exemples: Mock, Stub, Spy, etc.
Boîte Blanche: Tester avec une vue interne du SUT
Boîte Noire: Tester le SUT sans connaissance préalable de ses mécanismes interne
La question primordiale est: "Que voulez-vous tester ?"
En fonction de la réponse, différent types de tests peuvent être utilisé (liste NON exhaustive) :
Unit testing
Integration testing
Smoke testing
Functional Testing
Non-Regression testing
Acceptance testing
Focalisé sur le plus petit sous sytème possible du SUT, en "boîte blanche"
Tests indépendants les uns des autres
Ordre d’exécution non important
Utilisation de Test Doubles pour simuler le "reste" en bon fonctionnement
Vérifier l’intégration entre différents sous-systèmes
Le SUT est en "boîte blanche"
But : Fail Fast en "boîte blanche"
Valide les fonctions "de base" du système
On parle parfois de "Sanity Checking"
If it smokes, it’s bad
Vérifie que le logiciel se comporte comme prévue par les personnes en charge de la fabrication
Pas de biais d’inteprétation
Le SUT est en "boîte noire"
Vérifie que le SUT a un comportement stable dans le temps
Focalisation sur bug qui ne doit pas revenir
Le SUT est en "boîte noire"
Correcting a single bug may introduce several more.
Également connu sous l’acronyme "UAT" User Acceptance Testing
Vérifie que le logiciel se comporte comme attendu par l’utilisateur
Biais de communication inclus
Le SUT est en "boîte noire"
Fonction des temps d’exécutions, des coûts de corrections, et des valeurs ajoutées. Contextuel.
TDD: Écrire les tests unitaires avant le code
BDD: Privilégier language naturel et interactions
"Given, When, Then"
Moins de technique. Valeur ajoutée pour l’utilisateur.
Continuous Integration is a software development practice where members of a team integrate their work frequently. Usually each person integrates at least daily - leading to multiple integrations per day.
Construire et intégrer le code en continu
Le code est intégré souvent, au moins quotidiennement pour que l’intégration soit un non-évenement
Chaque intégration est validée par une construction automatisée avec tests
But : Détecter les fautes au plus tôt
Continuous Integration doesn’t get rid of bugs, but it does make them dramatically easier to find and remove.
Continous Delivery (CD)
Diminuer les risque liés au déploiement
Permettre de récolter des retours utilisateurs plus souvent
Rendre l’avancement visible par tous
How long would it take to your organization to deploy a change that involves just one single line of code?
Suite logique de l’intégration continue:
Chaque changement est potentiellement déployable en production
Le déploiement peut donc être effectué à tout moment
Your team prioritizes keeping the software deployable over working on new features
Continuous Deployment
Version "avancée" de la livraison continue:
Chaque changement est déployé en production, de manière automatique
Question importante: En avez-vous besoin ?
Avez-vous les mêmes besoin que Amazon Google ou Netflix ?
"Software Supply Chain"
"Feedback loop" / "Boucle de feedback"
Problèmatique : réagir rapidement pour corriger une faute
"Au plus tôt, au moins cher"
Problème #1: Avoir un retour
Problème #2: Réagir systématiquement sur un retour
Problème #3: Avoir confiance
Quels acteurs du système ?
Quel médium de communication ?
Quel déclencheurs et quelles limites ?
Culture à construire, les outils suivent facilement
Industrialisation du logiciel
Modélisation de la chaîne de valeur ("Value Stream Mapping")
"Fast is cheap": Piloté par le concept de la défaillance rapide ("fail fast")
Stage ("étape"): Élément de base
Abstraction atomiques d’un ensemble d’actions
Exemple: "Build", "Run Unit Tests"
Possibilité de parallèlisation
Gate ("Porte"): Transition entre 2 étapes
Manuel ou automatique
Peuvent être conditionnelles
Déclenchement initial : un changement dans la base de code
Chaque étape peut produire des livrables: on parlera d'Artefacts dans ce cours
Le déploiement est ce qui permet de rendre le logiciel prêt à l’usage
Un "déploiement" est exécuté vers un environnement
Production
Préproduction ("staging") / recette ("qualification")
Tests
"Disaster Recovery Environment"
Commencer par un "Produit Minimum Viable" (MVP) puis itérer
S’efforcer d’appliquer les bonne pratiques
Optimiser le Pipeline (lors des itérations)
Réutilisation des artefacts: "Only Build Your Binaries Once"
Arrêt du Pipeline dès qu’une faute est identifiée: "Fail Fast"
Identifier si un artefacts n’est pas déployable (tests…)
S’assurer qu’une même version de la base de code est utilisée à tout moment pour un Pipeline donnée
Paralléliser les étapes
Arrêt du Pipeline si une "branche" est en erreur
Sinon: étape inutile à supprimer
Les "gates" manuelles peuvent également être paralleliser
relation "1-N": N "gates" manuelles déclencheront N étapes parallèles
Un peu de lecture :
Votre organisation utilise l'information pour créer de la valeur
L’information doit donc être:
Confidentielle
Intègre
Disponible
C’est l’ensemble des pratiques et des outils permettant de prévenir et combattre les menaces sur l’organisation
4 piliers:
Connaissance du sytème
Least Privilege
Défense en profondeur
Mieux vaut prévenir que guérir
AAA signifie :
Authentification
Authorisation
Accounting (comptabilisation)
C’est l’ensemble des procédures et outils pour identifier un acteur avec une confiance suffisante
Une fois l’acteur identifié avec confiance, il faut contrôler ses droit en terme de manipulations
Nomenclature :
Ressources: Tâches ou objets manipulables et accessibles
Rôles: Ensemble de droits regroupés par commodité
Requêteurs: Acteur souhaitant manipuler des ressources
Etre autorisé à manipuler des ressources ne garantie pas l’effection à 100%
Limites du système (mémoire, disque, consommation, temps, etc.)
Erreurs, pannes et fautes
L'"accounting" permet de mesurer et contrôler les manipulations
Respect des limites
Reprises sur erreur
Capacity planning
Un peu de lecture :
VirtualBox (5.1.30+)
Check: VboxManage -v
Vagrant (2.0.1+)
Check: vagrant -v
Pour le proxy HTTP:
https://github.com/tmatilai/vagrant-proxyconf
export VAGRANT_HTTP_PROXY=… && vagrant …
et/ou https://github.com/AlbanMontaigu/docker-transparent-proxy
vagrant box add jenkins-lab-demo http://bit.ly/2Bl1hfI
Créer un dossier de travail nommé jenkins-lab-demo
dans votre HOME utilisateur
Se positionner dans ce dossier
Exécuter vagrant init
mkdir ~/jenkins-lab-demo
cd ~/jenkins-lab-demo
vagrant init -m -f jenkins-lab-demo
vagrant up # Démarrer la VM
vagrant suspend # Suspendre la VM
vagrant resume # Relancer la VM
vagrant halt # Arrêter "proprement la VM"
vagrant destroy # Détruire la VM (BRUTAL)
Dans votre navigateur, ouvrir http://localhost:10000
Bienvenue sur la page d’accueil du Lab:
Le lien Workshop Slides vous permettra d’accéder au slides
Cliquer sur le lien Git Server sur la page d’accueil du Lab
S’authentifier en tant que butler
(mot de passe butler
)
Cliquer sur Explore (en haut)
Cliquer sur butler/demoapp
But : Illustrer un exemple de "Software Supply Chain"
Problématique : Quel language/framewor/outil choisir ?
Solution:
"Opinionated" demo application
Tout le monde sur le même pied
Application Web
Page d’accueil affichant "Greetings from Spring Boot!"
C’est un des exemples de Spring Boot Starter
Langage: Java (OpenJDK 8)
Toolchain: Maven (Maven >= 3.3)
Code source stocké dans un dépôt Git
Configuration Maven: pom.xml
Code source de l’application: src/main/java/
Code source des tests: src/test
Script utilitaires: scripts
Ouvrir la console DevBox
WebSockets doit être autorisé
Clean the window: clear
Show command history: history
CTRL + R
: search the command history interactively
CTRL + C
: cancel current command and clean line buffer
CTRL + A
: jump to beginning of line
CTRL + E
: jump to end of line
cat
(concatenate)
ls
(list)
cd
(change directory)
pwd
(print working directory)
man
(manual)
rm
(remove)
mkdir
(make directory)
touch
(create an empty file)
Obtenir l’adresse HTTP du dépôt depuis le GitServer
# Get the git repository
git clone http://localhost:10000/gitserver/butler/demoapp
# Browse to the local repository
cd ./demoapp
# Check source code
ls -l
Maven TL;DR:
Workflow standardisé
pom.xml
décrit l’application (Project Object Model)
Maven Command line : mvn
, attends des goals en argument
mvn dependency:list
Accepte des flags
mvn dependency:list -fn
Goal compile
Résolution des dépendances
Pré-traitement du code source
Compilation des classes
Résultats dans le dossier ./target
:
mvn compile
ls -l ./target
Goal test
Exécute le goal compile
Compilation des tests unitaires
Exécution des tests unitaires
Rapports de tests dans ./target/surefire-reports
:
mvn test
ls -l ./target/surefire-reports
goal package
Exécute les goals compile
et test
Paquetage de l’application
Résultat dans ./target
mvn package
ls -lrh ./target/
Spring Boot demo exécutée comme un "Über-Jar"
Exécution avec la commande java:
java -jar ./target/demoapp-1.0.0.jar
Ouvrir une autre instance de DevBox et vérifier
http//localhost:8080 avec curl
Goal verify
Exécute compile
, test
et package
Compile et exécute les tests d’intégration sur l’application empaquetée
Rapport de tests dans ./target/failsafe-reports
:
mvn verify # 1 test failure expected
ls -l ./target/failsafe-reports
Définissons ensemble un pipeline
Etudier le contenu du dossier scripts
Jenkins is an open source automation server which enables developers around the world to reliably build, test, and deploy their software.
Orchestrateur de tâches Open Source
#1 Serveur Intégration Continue Integration
Un des tout premiers moteur d’intégration continue
Créé par Kohsuke Kawaguchi en 2006
Architecture orientée plugins
Une communauté indépendant et active (jenkins.io)
Projet original: "Hudson", renommé "Jenkins" en 2011
500+ releases
150,000+ installations actives
1,200+ plugins
But : CI → CD
Pas de "cassure" depuis Jenkins 1
Expérience "premièr démarrage" améliorée
Pipeline-as-Code:
Syntaxe "scriptée" : "Code your Pipeline"
Pierre angulaire de l’évolution de Jenkins
Visualisation et manipulation de "Pipelines"
GUI moderne, se concentrant sur les actions principales
Un outil pour définir votre "Pipeline" dans Jenkins
Le Pipeline est décrit dans un fichier texte: le JenkinsFile
DSL spécifique
Stocké dans un SCM
"Pipeline-as-code" : Nous avons besoin d’un Jenkinsfile
Par où commencer ?
Declarative
Syntaxe par défaut
S’utilise avec Blue Ocean
Scripted
Syntaxe originale (~3 ans)
"Great Power == Great Responsibility"
À utiliser lorsque le Déclaratif commence à être bizarre
Fourni le cycle ("round trip") complet avec le SCM
Pas de Pipeline ? "Suivez le guide".
Le Pipeline existe déjà ? Edit, commit, et exécutez le
Cliquez sur le lien "Jenkins" sur la page d’accueil du lab
Authentifiez vous en tant que butler
(le mot de passe est butler
)
Passez à l’interface Blue Ocean:
Ou cliquez sur le lien "Open Blue Ocean" à gauche
Créer un nouveau Pipeline, avec les réglages suivants :
Stocké dans Git
Utilisez l’URL en SSH
Configurez Gitea pour que Jenkins puisse accéder au code :
Dans Gitea, cliquez en haut à droite sur le drop-down
Allez dans "Settings" → "SSH/GPG Keys"
Ajoutez la clef SSH publique générée par Jenkins
Cliquez sur le bouton Create a Pipeline
Utilisez Blue Ocean Pipeline Editor et le serveur Gitea
Créez un pipeline avec 3 "stages" : Build, Test et Deploy
Chaque "stage" doit avoir 1 "step" qui affiche un message
"Building…" pour Build, "Testing…" pour Test …
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Build'
}
}
stage('Test') {
steps {
echo 'Test'
}
}
stage('Deploy') {
steps {
echo 'Deploy'
}
}
}
}
En utilisant Blue Ocean Pipeline Editor:
Modifiez les 3 stages du pipeline actuel
Les scripts sont stockés dans le dossier ./scripts
Utilisez la "step" Shell Script (mot clef sh
)
Supprimez les steps echo
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
}
}
stage('Test') {
steps {
sh './scripts/test.sh'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
En utilisant le Blue Ocean Pipeline Editor:
Modifiez le pipeline actuel
La "stage" Build doit archiver tous les fichier ".jar" générés
Indices : Dans le dossier target
, motif *.jar
La "stage" Test doit publier les rapports de test junit
Indices : Dans le dossier target
, motif **/*.xml
Le Pipeline doit être UNSTABLE
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
archiveArtifacts 'target/*.jar'
}
}
stage('Test') {
steps {
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
Le build est en état UNSTABLE
(jaune)
Priorité: réparer le build
Utiliser Gitea git server
Les tests d’intégration sont dans src/test/java/hello
Indices:
Integration Tests: == IT
Depuis src/test/java/hello/HelloControllerIT.java
Cliquer sur "Edit"
Commenter la ligne 39
Dé-commenter la ligne 40
Commit avec un message (push automatique)
Lancer le build manuellement dans Blue Ocean
Le build doit être vert (Stable)
Nous avons dû lancer le build manuellement
IC: Retours rapides !
Lancer le build dès que le code est poussé
Configurons un "Webhook" :
Depuis Gitea git server → Settings → Webhooks
Ajouter un nouveau webhook:
Type: Gitea
When should this webhook be triggered?: I need everything
Payload URL: http://localhost:10000/jenkins/job/demoapp/build?delay=0
Ajoutez un commentaire dans le Jenkinsfile depuis Gitea git server
Un build va démarrer
Validez dans l’onglet "Changes"
Dans l’éditeur Blue Ocean, voir la version textuelle:
Combinaison CTRL + S
(On Mac: CMD +S
)
Bi-directionnel: essayez de charger une solution de pipeline
Le Pipeline Syntax Snippet Generator comme acolyte:
Génération dynamique en fonction de vos plugins
Depuis l’interface "ancienne" de Jenkins
Menu de gauche de votre job "Pipeline" (ou MultiBranch)
But: réutiliser les binaires générés dans Build
Action: "mise sur étagère": Stash / Unstash
Modifier le Pipeline pour :
"Stasher" le dossier target
, à la fin de la phase Build
"Unstasher" au début de la phase Test
Attention, une limite de l’éditeur Blue Ocean va être atteinte
L’éditeur Blue Ocean ne supporte pas encore le ré-ordonnancement de "stages"
Mode textuel et/ou Snippet Generator à utiliser
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
stage('Test') {
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
Section post
:
Contient des "steps" à exécuter à la fin du Pipeline ou après une "stage"
Divisé en "condition d’états":
always
, success
, failure
, changed
Chaque condition contient ses propres "steps"
Pas encore intégré dans l’éditeur Blue Ocean
Si le "stage" Build échoue, alors la tâche "archiveArtifacts" ne devrait pas être exécutée
Même chose pour stash
Les rapports de tests unitaires doivent être publiés dans tous les cas après la phase Build
Format Junit
Stockés dans target/**/*.xml
Utiliser la documentation:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
}
post {
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
always {
junit 'target/**/*.xml'
}
}
}
stage('Test') {
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
Un noeud (ou node) est une machine prête à recevoir des builds
Step agent
spécifie sur quel "noeud" exécuter des "stages".
Une section agent
globale doit être définie
(au niveau du block pipeline
)
On peut aussi définire des sections agent
par "stage"
Exécuter l’étape Build sur un agent
configuré avec le label maven-jdk8
Exécuter l’étape Test sur un agent
configuré avec le label java8
L’éditeur Blue Ocean est utilisable
pipeline {
agent any
stages {
stage('Build') {
agent {
node {
label 'maven-java8'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
agent {
node {
label 'java8'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
But: Tester en parallèle l’application sur java 7 et 8
Mot clef parallel
définissant un block contenant
des "stages"
Agent java7
pour le Test Java 7
L’éditeur Blue Ocean est utilisable (et recommandé)
pipeline {
agent any
stages {
stage('Build') {
agent {
node {
label 'maven-java8'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
node {
label 'java8'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
But: Usage de Docker pour faciliter la définition des environements de build
Le mot clef agent
permet d’exécuter les "stages" dans
un container Docker, depuis une "image Docker",
ou depuis un Dockerfile
(recette maison d’image Docker)
Exécuter le Build dans un containeur
basé sur le fichier Dockerfile.build
Exécuter le Test Java 8 dans un containeur
basé sur les images maven:3-jdk-8-alpine
Trick: documentation manquante sur filename
,
dans un block dockerfile
pipeline {
agent any
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
Jenkins permet de "mettre en pause" l’exécution d’un pipeline, en attendant une validation humaine
Continuous Delivery / Deployment
Mot-clef input
, c’est une "step" Pipeline
Hautement configurable: Documentation Step Input
Généralement utilisé dans un "stage" dédié.
Obligatoirement avec agent none
(pas d’exécuteur, pas de workspace)
Ajouter une stage "approval" avant le déploiement
pipeline {
agent any
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
input(message: 'Deploy Application?', ok: 'Yes Deploy!')
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}
Définir l’exécution conditionnelle d’une "stage"
Mot clef when
Doit contenir au moins une condition parmi:
branch
environment
expression
Logique "built-in": allOf
, anyOf
, etc.
Définir des collections de clé-valeurs, en tant que variables d’environement:
Définition globale ou par "stage"
Ou en utilisant withEnv
dans un block steps
pour une instruction spécifique
N’éxecuter les "stages" Approval et Deploy que:
Si on se trouve sur la branche master
Ou si la variable FORCE_DEPLOY
est à true
pipeline {
agent any
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
input(message: 'Deploy Application?', ok: 'Yes Deploy!')
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}
Directive parameters
: l’utilisateur fournit des argument
au pipeline
Disponible en tant que variables accessibles dans l’objet params
Oeuf & Poule : Jenkins ne peut accéder au paramètre lors dur 1er build
Ajouter un paramètre DEPLOY_MESSAGE
dont la valeur par défaut est Deploy ?
Ce paramètre est utilisé dans le input
pipeline {
agent any
parameters {
string(name: 'DEPLOY_MESSAGE', defaultValue: 'Deploy ?', description: 'Message de déploiement')
}
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
input(message: params.DEPLOY_MESSAGE, ok: 'Yes Deploy!')
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}
Options: Configurer un "job" depuis le Pipeline
Configuration: Même chose dans la GUI "Legacy"
Mot clef options
Documentation des options: https://jenkins.io/doc/book/pipeline/syntax/#options
Certaines options comme timeout
peuvent être appliquée
dans un bloc step
On souhaite que la "stage" Approval attende 3 minute avant d’arrêter le pipeline
On ne veut conserver que les 5 derniers builds d’un pipeline: limiter l’usage disque
pipeline {
agent any
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
}
parameters {
string(name: 'DEPLOY_MESSAGE', defaultValue: 'Deploy ?', description: 'Message de déploiement')
}
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
timeout(time: 3, unit: 'MINUTES') {
input(message: params.DEPLOY_MESSAGE, ok: 'Yes Deploy!')
}
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}
Create a repository jenkins-libs
Init with a file vars/runPipeline.groovy
:
def call(String MESSAGE) {
echo "Lib: ${MESSAGE}"
}
Switch to legacy UI, configure the Multibranch job
Add the shared library
Adapt the pipeline to run the function in Build stage
pipeline {
agent any
libraries {
lib('jenkins-libs@master')
}
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
}
parameters {
string(name: 'DEPLOY_MESSAGE', defaultValue: 'Deploy ?', description: 'Message de déploiement')
}
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
runPipeline('Salut')
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
timeout(time: 3, unit: 'MINUTES') {
input(message: params.DEPLOY_MESSAGE, ok: 'Yes Deploy!')
}
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}
Industrialisation du logiciel : secteur balbutiant et très dynamique
Beaucoup de solutions !
Hébergement du Service ?
Existant ?
Profil des utilisateurs ?
Criticité ?
CI seul ou "plus large" ?
Topologie de facturation ?
SaaS (modèles gratuits et/ou Enterprise) :
TravisCI
CircleCI
CodeShip
GitLab.com
Microsoft VSTS
Amazon Pipeline
BitBucket Pipeline
A héberger soit-même :
Jenkins
CloudBees Jenkins Enteprise
GitLab
Microsoft VSTS
Atlassian Bamboo (BitBucket Pipeline)
"Serverless": https://github.com/lambci
Glisser vers la production (OpenShift Pipelines)