Utiliser NSSM pour démarrer un agent Jenkins

Dans cet article, j’expliquerai comment utiliser NSSM pour démarrer un agent Jenkins sur Windows en tant que service. Jenkins est un outil d’intégration continue que j’utilise pour gérer mes projets sous git. L’application programmée en Java possède une interface web très intuitive. Un autre de ses avantages est que l’on peut distribuer la charge de la construction et du déploiement d’une application sur plusieurs agents.

Pour un agent Linux, j’utilise habituellement comme Launch method l’option Launch agents via SSH. Pour un agent Windows, c’est plutôt l’option Launch agent by connecting it to the master qui sera utilisée. Une fois l’agent configuré, nous serons confrontés à une page similaire à l’image suivante.

Jenkins Agent page
Jenkins Agent

La première option permet de télécharger une application JNLP (Java Network Launch Protocol) qui démarrera l’agent. Il est aussi possible de l’installer en tant que service. Par contre, mon anti-virus m’empêche de l’ouvrir et/ou de l’installer. C’est l’une des raisons qui m’a poussé à utiliser l’application NSSM. NSSM signifie Non-Sucking Service Manager et, comme son nom l’indique, est un gestionnaire de service « performant ». L’application possède une interface graphique pour installer, éditer ou supprimer un service créé à partir de NSSM. Par contre, dans cet article, c’est plutôt des lignes de commande que nous utiliserons.

Premièrement, pour me simplifier la tâche, j’ai installé nssm.exe dans le dossier C:\jenkins. C’est le Remote root directory dans lequel l’agent va opérer. Ensuite, on ouvre une fenêtre de terminal et on tape toutes ces commandes:

nssm install jenkinsagent "C:\jenkins\java\bin\java.exe"
nssm set jenkinsagent AppDirectory "C:\jenkins"
nssm set jenkinsagent AppParameters "-jar agent.jar -jnlpUrl http://server.com/ci/computer/Demo/jenkins-agent.jnlp -secret ba206ed36a928e773024ea46afdbfb8e33abd0de67f93c73213c4dcf229a1990 -workDir \"c:\jenkins\""
nssm set jenkinsagent DisplayName "Jenkins Agent Service"
nssm set jenkinsagent Description "A Jenkins agent."
nssm set jenkinsagent Start SERVICE_DELAYED_AUTO_START
nssm set jenkinsagent AppStdout "C:\jenkins\logs\nssm.log"
nssm set jenkinsagent AppStderr "C:\jenkins\logs\nssm.log"
nssm set jenkinsagent AppRotateFiles 1
nssm set jenkinsagent AppRotateBytes 1000000
nssm start jenkinsagent

L’agent nécessite d’être démarré par Java.exe, donc la ligne 1 doit être le chemin vers ce fichier. La ligne 3 est une copie de ce que vous allez trouver sur la page web de l’agent. La dernière ligne va démarrer le service. Après cette étape, l’agent devrait maintenant être disponible dans Jenkins.

Si vous désirez supprimer le service, c’est cette commande qu’il faut utiliser:

nssm remove jenkinsagent


Pour éditer un service déjà installé avec l’interface, on utilise cette commande:

nssm edit jenkinsagent

GitVersion dans Jenkins sous Linux

Dans un article précédent, j’avais expliqué comment utiliser GitVersion dans Jenkins sous Windows. Celui-ci traitera du même sujet, sauf que cette fois ci c’est sur Linux que l’application fonctionnera.

Je rappelle que GitVersion est une application qui sert à la génération de version automatique à partir d’un dépôt Git. Jenkins est un outil d’intégration continue programmé en Java. Ces deux projets à code source ouvert sont tous deux hébergés sur GitHub.

Pour se simplifier la vie, nous allons utiliser un conteneur Docker Linux pour démarrer l’application GitVersion. Toutes les propriétés de GitVersion serviront à générer des variables d’environnement. Ces variables pourront par la suite être utilisées à n’importe quel endroit dans le fichier Jenkinsfile:

stage('Version') {
	agent {
		docker {
			image 'gittools/gitversion:4.0.1-linux-debian-netcoreapp2.1'
			args '--entrypoint=\'\''
		}
	}
	steps {
		// Génération du fichier gitversion.properties
		sh 'dotnet /app/GitVersion.dll /output buildserver'
		// Enregistrement des variables d'environnement du fichier gitversion.properties
		script {
			readFile('gitversion.properties').split("\n").each { line ->
				el = line.split("=")
				env."${el[0]}" = (el.size() > 1) ? "${el[1]}" : ""
			}
		}
	}
}

Maintenant que vous avez ces informations de version, vous pouvez les utiliser pour générer la version de votre logiciel automatiquement.

Reverse proxy et Jenkins

Jenkins est un outil d’intégration continue que j’utilise sur un serveur Windows pour gérer mes projets sous git. L’application programmée en Java possède une interface web très intuitive. Pour l’utiliser à partir d’un site web commercial (.com) j’ai dû configurer IIS avec un reverse proxy. Jenkins est accessible par TLS grâce à Let’s Encrypt. Cette configuration semble parfaite, sauf que j’ai un petit problème. Lorsque j’accède à la section Manage Jenkins, un message d’erreur est affiché.

It appears that your reverse proxy set up is broken.
Avertissement à propos du reverse proxy dans Jenkins

Plusieurs guides existent en ligne pour corriger ce problème, mais aucun n’a fonctionné complètement avec mon environnement. Après avoir regardé des instructions pour Apache et Nginx j’ai compris qu’il fallait modifier les en-tête HTTP suivantes: X-Forwarded-Proto, X-Forwarded-Port et X-Forwarded-Host.

J’ai essayer de les ajouter comme Server Variables dans les règles de mon site web sur IIS, mais cela n’a pas fonctionné. En lisant la documentation de Microsoft j’ai réalisé que les variables devaient être en majuscule, que les tirets devaient être remplacés par des traits de soulignement et que le préfixe « HTTP_ » était nécessaire. Donc, voici ce que j’ai ajouté comme valeurs de remplacement:

  • HTTP_X_FORWARDED_PROTO = https
  • HTTP_X_FORWARDED_PORT = 443
  • HTTP_X_FORWARDED_HOST = {HTTP_HOST}

Résultat dans IIS:

IIS Inbound Rule for Jenkins
Capture d’écran des règles pour Jenkins dans IIS

Après avoir enregistré les changements, j’ai actualisé la page de gestion sur Jenkins et l’erreur est disparue.

Utiliser GitVersion dans Jenkins

GitVersion est une application pour Windows codée en C# qui sert à la génération de version automatique à partir d’un dépôt Git. Jenkins est un outil d’intégration continue programmé en Java. Ces deux projets à code source ouvert sont tous deux hébergés sur GitHub. Cet article expliquera comment utiliser GitVersion dans Jenkins et ça, sans l’utilisation de plugin supplémentaires.

L’utilisation de GitVersion sera faite à l’intérieur d’un fichier Jenkinsfile qui est utilisé par des projets de type Pipeline. Dans mon premier exemple, le paramètre showvariable sera donné à GitVersion pour aller chercher une variable spécifique. Ce n’est pas très efficace si l’on a besoin d’aller chercher plusieurs variables. Par contre, c’est assez simple. Voici un bout code qui sert à changer la description du build:

steps {
    script {
        def FullSemver = bat returnStdout: true, script: '@"GitVersion.exe" /showvariable FullSemver'
        currentBuild.description = "v${FullSemver}"
    }
}

Comme mentionné plus tôt, cette technique manque de flexibilité. Dans le prochain exemple, toutes les propriétés de GitVersion serviront à générer des variables d’environnement. Ces variables pourront par la suite être utilisées à n’importe quel endroit dans le fichier. L’inconvénient est que c’est un peu plus long:

steps {
    // Génération du fichier gitversion.properties
    bat '@"GitVersion.exe" /output buildserver'
    // Enregistrement des variables d'environnement du fichier gitversion.properties
    script {
        readFile('gitversion.properties').split("\r\n").each { line ->
            el = line.split("=")
            env."${el[0]}" = (el.size() > 1) ? "${el[1]}" : ""
        }
    }
    bat '''
        @echo Quelques variables d’environnement:
        @echo %GitVersion_SemVer%
        @echo %GitVersion_BranchName%
        @echo %GitVersion_AssemblySemVer%
        @echo %GitVersion_MajorMinorPatch%
        @echo %GitVersion_Sha%
    '''
}

Voici un exemple de fichier gitversion.properties généré avec la version 4.0.0-beta.14 de GitVersion:

GitVersion_Major=1
GitVersion_Minor=0
GitVersion_Patch=1
GitVersion_PreReleaseTag=
GitVersion_PreReleaseTagWithDash=
GitVersion_PreReleaseLabel=
GitVersion_PreReleaseNumber=
GitVersion_BuildMetaData=1
GitVersion_BuildMetaDataPadded=0001
GitVersion_FullBuildMetaData=1.Branch.master.Sha.3af072d1cd7e121e9723381a95bce0bf3809663b
GitVersion_MajorMinorPatch=1.0.1
GitVersion_SemVer=1.0.1
GitVersion_LegacySemVer=1.0.1
GitVersion_LegacySemVerPadded=1.0.1
GitVersion_AssemblySemVer=1.0.1.0
GitVersion_AssemblySemFileVer=1.0.1.0
GitVersion_FullSemVer=1.0.1+1
GitVersion_InformationalVersion=1.0.1+1.Branch.master.Sha.3af072d1cd7e121e9723381a95bce0bf3809663b
GitVersion_BranchName=master
GitVersion_Sha=3af072d1cd7e121e9723381a95bce0bf3809663b
GitVersion_NuGetVersionV2=1.0.1
GitVersion_NuGetVersion=1.0.1
GitVersion_NuGetPreReleaseTagV2=
GitVersion_NuGetPreReleaseTag=
GitVersion_CommitsSinceVersionSource=1
GitVersion_CommitsSinceVersionSourcePadded=0001
GitVersion_CommitDate=2018-08-29

Avec certain type de projet Jenkins, j’ai dû ajouter un comportement supplémentaire lors de l’opération clone. La version demeurait toujours à 0.1.0 et cela même si des tags existaient. Dans les configurations du projet, dans la section Behaviors il faut ajouter la propriété Advanced clone behaviours. Ensuite, on s’assure que Fetch tags est sélectionné.

Advanced clone behaviours

Cela va faire en sorte que le paramètre --tags sera utilisé lors du fetch.

Maintenant que vous avez ces informations de version, vous pouvez les utiliser pour générer la version de votre logiciel automatiquement. Je me sers de l’application envsubst pour faire des substitutions dans un fichier.

Intégrer Gogs à Jenkins

Gogs (Go Git Service) est une solution Git auto-hébergée codée en Go. Jenkins est un outil d’intégration continue programmé en Java. Ces deux projets à code source ouvert sont tous deux hébergés sur GitHub. Lorsque que combiné ensemble, ils permettent presque un cycle de développement logiciel complet.

Le type de projet à utiliser dans Jenkins est le Multibranch Pipeline car il est le mieux adapté à Git. C’est pourquoi que dans la section Branch Sources lorsque l’on clique sur Add source on doit choisir Git. Vous devez entrer le Project Repository, pour vous simplifier la tâche vous pouvez utiliser le bouton Copy de Gogs. Dans la section Behaviors, appuyez sur le bouton Add et choisissez l’option Configure Repository Browser. Dans la liste de Repository browser, il faut choisir gogs et entrer le URL de la page du projet. Cela fera en sorte qu’à plusieurs places dans Jenkins des liens vers Gogs seront ajoutés.

Liens vers Gogs
Le SHA1 sera un lien vers la soumission dans Gogs

Ceci conclut la première étape. La seconde consiste à pouvoir démarrer des tâches sur Jenkins suite à une soumission. Avant de quitter la page de configuration du projet, dans la section Scan Multibranch Pipeline Triggers on peut cocher l’option Periodically if not otherwise run. Cela va permettre une vérification du dépôt à tous les jours. C’est une protection au cas où Jenkins ou Gogs serait incapable d’effectuer la prochaine étape.

Dans Gogs il faut maintenant choisir votre dépôt et aller dans les Settings. Par la suite, on va dans la section Webhooks, on clique sur Add Webhook et on choisit Gogs.
Entrez ces paramètres:

  • Payload URL: http://jenkinsserver.com/git/notifyCommit?url=http://gogsserver.com/Org/Project.git
    • Org/Project.git = nom du dépôt utilisé dans Jenkins (sensible à la case)
  • Content Type: application/x-www-form-urlencoded
  • When should this webhook be triggered: Let me choose what I need.
  • Cocher les options suivantes:
    • Create
    • Delete
    • Push
  • Active doit être cocher

Pour terminer, appuyer sur le bouton Add Webhook.

Avec cette configuration les branches pourront être ajoutées et supprimées automatiquement dans Jenkins. Si vous avez un fichier Jenkinsfile inclus dans votre projet, les tâches ajoutées à celui-ci pourront être effectuées à chaque soumission. Malheureusement les requêtes de tirage (pull requests) ne fonctionnent pas.

Si vous avez besoin d’aide sur le plugin Git de Jenkins vous pouvez consulter cette page web.