Schlagwort-Archive: Webserver

Zwei unabhängige Jenkins-Instanzen auf einem Webserver

Warum sollte man zwei unabhängige Jenkins-Instanzen auf einem Webserver haben wollen?
Die Antwort in meinem Fall lautet, weil ich mehr Durchsatz haben wollte. Wir haben an die 50 Jobs erstellt, die verschiedene Kunden- und Entwicklungsstände auf einer Instanz überwachen. Wenn es da viele, nahezu gleichzeitige Änderungen gibt, kann es keine schnelle Antwort des Continuous-Integration Server mehr geben.

Das kann man doch auch mit mehreren Prozessoren und einer Jenkins-Instanz erreichen?
Im Prinzip, ja. Durch unsere aktuelle Modulstruktur ist es leider nicht möglich, mehrere Module eines Entwicklungszweiges parallel von Jenkins bauen zu lassen. Das führt zu Überholvorgängen, die zu häufig zu falschen Fehlermeldungen führen. Das verunsichert die Entwickler unnötig und wollte ich vermeiden.

Ich könnte das Problem auch ohne eine zweite Jenkins-Instanz lösen, wenn ich bestimmte Jobs an einen einzigen Prozessor binden könnte. Ein entsprechendes Plugin konnte ich bisher nicht finden.

Bleibt also nur eine zweite Jenkins-Instanz aufzubauen. Einen zweiten Webserver wollte ich nicht installieren, da dieser zusätzliche Ressourcen benötigt. Der erste Ansatz bestand darin, das jenkins.war umzubenennen (z.B. in jenkins2.war) und auf dem Webserver zu deployen. Das funktioniert auch. Man hat dann einen Jenkins, der unter http://localhost:8080/jenkins läuft und einen der unter http://localhost:8080/jenkins2 läuft. Leider verwenden beide das gleiche Arbeitsverzeichnis und bearbeiten daher auch beide die gleichen Jobs parallel.

Es muss also eine Möglichkeit geben, JENKINS_HOME auf ein anderes Verzeichnis zeigen zu lassen. Eine Umgebungsvariable auf Rechnerebene scheidet aus, da dann alle Instanzen von dieser Variable betroffen wären. Die Lösung liegt in der web.xml. Zunächst muss die jenkins.war-Datei ausgepackt werden. Im Verzeichnis WEB-INF ist die web.xml dann zu finden. Hier gibt es den folgenden Eintrag:

<env-entry>
    <env-entry-name>HUDSON_HOME</env-entry-name>
   <env-entry-type>java.lang.String</env-entry-type>
   <env-entry-value></env-entry-value>
</env-entry>

Hier sind die Hudson-Wurzeln noch gut zu erkennen.JENKINS_HOME heißt in Wirklichkeit HUDSON_HOME. In das Tag <env-entry-value> wird nun einfach das neue Jenkins-Homeverzeichnis eingetragen und die geänderte Datei gespeichert.

Wenn nun wieder eine war-Datei erzeugt wird und man versucht die Datei auf dem Webserver zu deployen, dann bekommt man eine Fehlermeldung, die besagt, dass die SHA1-Signatur der web.xml-Datei nicht mit dem Inhalt übereinstimmt. Dieses Problem wird auf die radikale Art dadurch behoben, dass die JENKINS.SF- und JENKINS.DSA-Dateien im Verzeichnis META-INF gelöscht werden. Nun kann die neue jenkins.war-Datei deployed werden und die neue Instanz hat ein eigenes Arbeitsverzeichnis.

Da jede Woche eine neue Version von Jenkins herauskommt und ich diese Arbeit nicht jedes Mal von Hand ausführen will, habe ich ein kleines Ant-Skript erstellt, dass mir diese Arbeit automatisiert.

<?xml version=“1.0″ encoding=“UTF-8″?>
<project name=“Config Jenkins“ default=“packWar“ basedir=“.“>
    <property name=“war-content-dir“ value=“war-content“ />
    <property name=“webcontainer-home“ value=“/usr/share/tomcat6″ />

    <target name=“unpackWar“ description=“Unpacking Jenkins-WAR“>
        <delete dir=“${war-content-dir}“ failonerror=“false“
                    description=“Delete old dir if exist“ />
        <unwar src=“jenkins.war“ dest=“${war-content-dir}“ />
    </target>

    <target name=“deleteSignature“ description=“Delete signature files“
                depends=“unpackWar“>
        <delete file=“${war-content-dir}/META-INF/JENKINS.SF“ failonerror=“true“ />
        <delete file=“${war-content-dir}/META-INF/JENKINS.DSA“ failonerror=“true“ />
        <delete file=“${war-content-dir}/META-INF/JENKINS.RSA“ failonerror=“true“ />
    </target>

    <target name=“modifyWebXml“ depends=“unpackWar, deleteSignature“
                description=“Modify the web.xml to have a different JENKINS_HOME“>
        <replace file=’${war-content-dir}/WEB-INF/web.xml‘
            token=’&lt;env-entry-value&gt;&lt;/env-entry-value&gt;‘
            value=’&lt;env-entry-value&gt;${webcontainer-home}/.jenkins2&lt;/env-entry-value&gt;‘
            description=“Change HUDSON_HOME“ />
    </target>

    <target name=“packWar“ depends=“modifyWebXml“
            description=“Create a new war file“>
        <delete file=“jenkins2.war“ failonerror=“false“
            description=“Delete old jenkins2.war if existing“/>
        <war destfile=“jenkins2.war“ basedir=“${war-content-dir}“ filesonly=“true“
           manifest=“${war-content-dir}/META-INF/MANIFEST.MF“ />
    </target>
</project>

Den Skript kommt mit den Bordmitteln von Ant aus und selbsterklärend.

Durch die Verwendung von Properties für den Webserver kann mittels –Dwebcontainer-home=… ein beliebiges Homeverzeichnis mitgegeben werden. Auch das Deployment kann noch auf einfache Weise mit in das Skript integriert werden. Vielleicht werde ich dem nächst eine erweitere Version hier veröffentlichen.

Das Skript kann wahrscheinlich auch für Hudson verwendet werden. Ausprobiert habe ich es jedoch nicht.