Blog

Ephemeral Jenkins Slaves to the Rescue!

Jeder, der in einem größeren Software-Projekt mit Jenkins gearbeitet hat, kennt das Problem: Die Kapazitäten im Jenkins sind knapp, einige Jobs dürfen nur auf bestimmten Knoten („Slaves“) ausgeführt werden, andere Jobs müssen vielleicht zwingend exklusiv auf einem Knoten laufen, da es sonst zu Port-Kollisionen kommt.

Man könnte jetzt mehr Slaves bei der IT des Kunden beantragen oder gleich Slaves in VMs anlegen. Beides nicht unbedingt schlanke Lösungen, zumal man alle Tools wieder installieren und in Jenkins konfigurieren muss. Warum also nicht Docker-basierte Slaves nutzen? Da könnte man lokal die Images mit allen Tools und Einstellungen vorbereiten und dann nutzen.

Genau das und mehr ist mit dem Docker Plugin in Jenkins möglich:

Es können dynamisch flüchtige (ephemeral) Slaves bei Bedarf aus Images erzeugt werden. Das Ganze passiert vollautomatisch und erlaubt, einfach eine skalierbare und wartbare Umgebung für den Build zu schaffen. Nach der Installation des Plugins in Jenkins werden Images als Vorlagen hinterlegt:

Man kann z.B. für ein weiteres JDK ein Image hinterlegen:

So kann man etwa für einen Android-Build ein Docker-Image für ein Label „android“ vorbereiten und für Android-Apps nutzen.

Ein Beispiel-Setup ist auf GitHub zu finden. Einfach das Repository klonen und „./docker-setup.sh“ setzt lokal eine Umgebung mit Jenkins, 2 Jenkins-Slaves und einem vorkonfiguriertem Gitlab auf. Wenn man jetzt einen Pipeline-Job mit bestimmen JDK erstellt, dann werden dynamisch Slaves erstellt:

jenkins_server | Jan 26, 2018 3:36:01 PM com.nirima.jenkins.plugins.docker.DockerCloud addProvisionedSlave
jenkins_server | INFO: Provisioning 'openjdk:9' number '0' on 'docker'; Total containers: '8'
jenkins_server | Jan 26, 2018 3:36:01 PM hudson.slaves.NodeProvisioner$StandardStrategyImpl apply
jenkins_server | INFO: Started provisioning Image of openjdk:9 from docker with 1 executors. Remaining excess workload: 0
jenkins_server | Jan 26, 2018 3:36:01 PM com.nirima.jenkins.plugins.docker.DockerTemplate pullImage
jenkins_server | INFO: Pulling image 'openjdk:9'. This may take awhile..

Adressiert werden können die Slaves wie sonst auch in Jenkins ganz transparent per Label:

node {
    
      stage('Build') {
        sh 'java -version'
      }

      stage('test') {
		parallel(
			'JDK 8': {
				node('JDK8') {
          			sh 'java -version'
				}
			},
			'JDK 9': {
				node('JDK9') {
          			sh 'java -version'
				}
			},
			failFast: false
		)    
	  }
}

Zunächst werden die regulären Executors angesprochen, da am Anfang keine „Node-Anforderungen“ im Jenkinsfile hinterlegt sind:

Sobald das Node Label „JDK8“ oder „JDK9“ erreicht, wird automatisch ein neuer Slave anhand des Docker Images angelegt:

jenkins_server    | INFO: Will provision 'openjdk:9', for label: 'JDK9', in cloud: 'docker'
jenkins_server    | Jan 26, 2018 3:48:50 PM com.nirima.jenkins.plugins.docker.DockerCloud addProvisionedSlave
jenkins_server    | INFO: Provisioning 'openjdk:9' number '0' on 'docker'; Total containers: '7

Und auch direkt eingebunden:

Mit dieser Methode kann man auch sehr gut Probleme mit Portkonflikten isolieren und die Umgebung vorkonfigurieren. Und anschließend werden die Container rückstandslos verworfen. Docker sei Dank…

Über den Autor

Martin Reinhardt arbeitet als Architekt bei der Management- und IT-Unternehmensberatung Holisticon AG. Er beschäftigt sich dort mit der Architektur von komplexen verteilten Systemen, modernden Webarchitekturen und Build Management. Martin engagiert sich in der Software-Craftsmanship-Bewegung. Er ist seit mehreren Jahren im Bereich der Java- und Webentwicklung tätig. Außerdem setzt er sich neben der Architektur vor allem für die Testautomatisierung in verschiedenen Technologien ein und ist auch in verschieden OpenSource-Projekten zu dem Thema wie z.B. dem Galen Framework tätig.

Antwort hinterlassen