Bei Nuxeo wollen wir das Leben unserer Entwickler einfacher gestalten. Aus diesem Grund bieten wir unter anderem Nuxeo Studio an, eine Anwendung, mit deren Hilfe unsere Kunden (und deren Entwickler) Geschäftslogik durch die Festlegung neuer Dokumenttypen, Arbeitsabläufe und Regeln mit nur wenigen Klicks anpassen können. Wenn bestimmte Anwendungsfälle jedoch nach einer umfassenderen Anpassung verlangen, müssen Entwickler eigenen Code in Java verfassen und diesen über neue Bundles in der Nuxeo Platform bereitstellen. Aus diesem Grund bieten wir benutzerdefinierte Nuxeo-Pakete an, die die Bereitstellung des Marketplace deutlich vereinfachen.

Wenn Sie unserem Blog folgen, haben Sie möglicherweise schon bemerkt, dass wir großes Interesse an der OpenShift-Container-Plattform haben. Deshalb haben wir uns auch beim Thema Bereitstellung mit OpenShift beschäftigt. Wir möchten eine kontinuierliche Bereitstellungslösung mit OpenShift anbieten, bei der neuer Code in Ihrer Nuxeo-Entwicklerinstanz bereitgestellt wird, wenn Sie diesen und neue Tests schreiben und den Code an Github pushen. Sehen wir uns nun genauer an, wie das funktioniert.

OpenShift Source to Image

Eine der Bereitstellungsstrategien in OpenShift ist die sogenannte "sourceStrategy". Hierbei verweisen Sie einfach auf ein Github-Repository, in dem das Projekt erstellt werden soll.

Standardmäßig werden diese Projekte mit einer "Dockerfile" erstellt, Sie können jedoch auch ein Build-Image angeben, das weiß, wie das Projekt aufgebaut sein soll, dieses anschließend verpacken und dann ein Docker-Image erstellen, das das Projekt enthält. Dieses Verfahren bezeichnet man als Source To Image. Sie verfügen über Code (beispielswiese Java) als Eingabe und halten ein Docker-Image bereit, das als Ausgabe ausgeführt werden soll.

Im Docker-Meme Build, Ship, Run ist Source To Image für den Abschnitt Build verantwortlich. Nach der Erstellung wird das Bild dann als ImageStream an OpenShift gepusht, hierbei handelt es sich um den Abschnitt Ship. Abschließend können Sie den ImageStream in einer DeploymentConfig verwenden, dies entspricht dem Abschnitt Run.

Nuxeo-S2I-Image

Damit Sie diesen Bereitstellungszyklus vollständig durchführen können, haben wir ein Nuxeo-S2I- (Source to Image) Docker-Image erstellt, das weiß, wie ein Nuxeo-Projekt erstellt werden muss, und JDK-, Maven- und Knoten-Tools bereitstellt.

Erstellen wir doch nun einmal ein Nuxeo-Testprojekt unter Zuhilfenahme von Nuxeo CLI:

    # mkdir nuxeo-s2i-sample
    # cd nuxeo-s2i-sample
    # nuxeo bootstrap single-module

    ...
         info You'll be prompted for generation of:
         info   nuxeo-s2i-sample-core: single-module

       create Generate Module: nuxeo-s2i-sample-core

       create Generating Single module
         info   Parameters: Parent group, Parent artifact, Parent version, Nuxeo version, Project group, Project artifact, Project version, Project description
    ? Parent Group id (use white space to cancel default value.): org.nuxeo
    ? Parent Artifact id: nuxeo-addons-parent
    ? Parent Version: 9.2
    ? Project Group id: org.nuxeo.sample
    ? Project Artifact id: nuxeo-s2i-sample
    ? Project version: 1.0-SNAPSHOT
    ? Project description: Sample project to demonstrate S2I usage
       create pom.xml
       create src/main/resources/META-INF/MANIFEST.MF
       create src/main/java/org/nuxeo/sample/package-info.java
       create src/test/resources/jndi.properties
       create src/test/resources/log4j.xml
         info You can start editing code or you can continue with calling another generator (nuxeo bootstrap [<generator>..])

So entsteht ein leeres Nuxeo-Beispielprojekt, das Sie mit Maven bauen können. Stattdessen verwenden wir jedoch den "s2i"-Client dazu, ein Nuxeo-Docker-Image zu erstellen, das dieses Bundle enthält.

s2i build . nuxeo/s2i:9.2 nuxeo-s2i-sample

Nach einer Weile entsteht ein "nuxeo-s2i-sample"-Docker-Image, das Sie wie folgt wie ein Nuxeo-Image ausführen können:

docker run --rm -ti -p 8080:8080 nuxeo-s2i-sample

Über das Admin Center in den Verteilungsinformationen können wir prüfen, ob unser Paket bereitgestellt wurde.

Verwendung von Source to Image in OpenShift

OpenShift kann "s2i" verwenden. Wir benötigen nun also nur noch eine Ressource, die auf unser Nuxeo-S2I-Image verweist. Hierzu kommt ImageStream zum Einsatz:

    apiVersion: v1
    kind: ImageStream
    metadata:
      name: nuxeo-s2i
      annotations:
        openshift.io/display-name: Nuxeo Source to image
    spec:
      tags:
        - name: "latest"
          annotations:
            openshift.io/display-name: Nuxeo (latest)
            description: |
              Build and run a Nuxeo application. For more information about using this builder image, see https://github.com/nuxeo-sandbox/nuxeo-s2i

              WARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.
            iconClass: icon-java
            tags: builder, java, nuxeo
            supports: nuxeo
            sampleRepo: https://github.com/nuxeo/nuxeo-sample-project
          from:
            kind: ImageStreamTag
            name: "9.3-SNAPSHOT"            
        - name: "9.3-SNAPSHOT"
          annotations:
            openshift.io/display-name: Nuxeo 9.3-SNAPSHOT
            description: |
              Build and run a Nuxeo application. For more information about using this builder image, see https://github.com/nuxeo-sandbox/nuxeo-s2i
            iconClass: icon-java
            tags: builder, java, nuxeo
            supports: nuxeo
            sampleRepo: https://github.com/nuxeo/nuxeo-sample-project
          from:
            kind: DockerImage
            name: nuxeo/s2i:master

Anschließend können wir über die Schaltfläche Projekt hinzufügen ein neues Nuxeo-Projekt erstellen, indem wir den eben erstellten ImageStream auswählen.

Nun geben wir die Github-Repository-Adresse unseres Nuxeo-Projekts an:

Das war's schon! OpenShift ruft das S2I-Image auf, erstellt Ihr Maven-Projekt, sucht das Artefakt im Zielverzeichnis, fügt es dem Verzeichnis "bundles" unseres Nuxeo-Docker-Image hinzu, pusht das Image und stellt es in einer DeploymentConfig bereit.

Nach dem Start der Nuxeo Platform können wir prüfen, ob das Paket installiert wurde, indem wir "rsh" im Container ausführen und die im Verzeichnis "bundles" installierten Pakete anzeigen lassen.

# oc get po
NAME                  READY     STATUS      RESTARTS   AGE
nuxeosample-1-7z7s2   1/1       Running     0          5m
# oc rsh nuxeosample-1-7z7s2
nux...z7s2:/opt/nuxeo/server$ ls /opt/nuxeo/server/nxserver/bundles | grep sample
nuxeo-s2i-sample-1.0-SNAPSHOT.jar

Kontinuierliche Bereitstellung

Unser Nuxeo-Projekt ist leer, wir möchten ihm nun also bestimmte Verhaltensweisen hinzufügen und den aktuellen Pod durch das Projekt ersetzen. Hierzu könnten wir unsere Änderungen an Github pushen und ein neues Build ausführen, das eine neue Bereitstellung verursacht. Diesen manuellen Schritt können wir jedoch durch Verwendung eines WebHooks ganz einfach umgehen.

Wir bearbeiten zunächst in OpenShift das Nuxeo-Build und öffnen das Fenster für die erweiterten Einstellungen. Hier suchen wir nach einem "Trigger" und kopieren den Github-WebHook-Endpunkt.

In Github erstellen wir sodann einen WebHook, der bei jedem Commit aufgerufen wird.

Anschließend erstellen wir einen Empfänger (Listener), der die Beschreibung jedes neu erstellten Knotens aktualisiert. Im nächsten Schritt erstellen wir in Nuxeo ein Dokument mit dem Namen "Note" und aktualisieren dessen Beschreibung auf "Happily deployed thru s2i".

# nuxeo bootstrap listener
...
create Generating Listener
    info Parameters: Listener package, Listener class name, Trigger on event, Custom events, Is it an asynchronous listener, Is it a post commit listener
? Listener package: org.nuxeo.sample
? Listener class name: NoteCreationListener
? Trigger on events: aboutToCreate
? Is it an asynchronous Listener? No
? Is it a post-commit Listener? No
    info Maven dependency: org.nuxeo.runtime:nuxeo-runtime-test:::test
        info Maven dependency: org.nuxeo.ecm.platform:nuxeo-platform-test:::test
        info Maven dependency: org.nuxeo.ecm.core:nuxeo-core-event
        force pom.xml
        force src/main/resources/META-INF/MANIFEST.MF
create src/main/java/org/nuxeo/sample/NoteCreationListener.java
create src/test/java/org/nuxeo/sample/TestNoteCreationListener.java
create src/main/resources/OSGI-INF/notecreationlistener-listener-contrib.xml
info You can start editing code or you can continue with calling another generator (nuxeo bootstrap [<generator>..])

Sie können dann den Java-Code von "src/main/java/org/nuxeo/sample/NoteCreationListener.java" so bearbeiten, dass der Empfänger das Dokument aktualisiert.

public class NoteCreationListener implements EventListener {

    @Override
    public void handleEvent(Event event) {
        EventContext ctx = event.getContext();
        if (!(ctx instanceof DocumentEventContext)) {
            return;
        }

        DocumentEventContext docCtx = (DocumentEventContext) ctx;
        DocumentModel doc = docCtx.getSourceDocument();

        // Add some logic starting from here.
        doc.setPropertyValue("dc:description","Happily deployed thru s2i");
    }
}

Nach der Festlegung und dem Push an Github wird das OpenShift-Build gestartet und die Bereitstellung durchgeführt. Nun möchten wir natürlich prüfen, ob die Bereitstellung auch funktioniert: Hierzu erstellen wir ein "Note"-Dokument und siehe da - unsere Beschreibung wurde aktualisiert!

Weitere Optionen für das S2I-Image

In seiner Grundform sucht das S2I-Image lediglich nach beliebigen JARs im Verzeichnis "target" und kopiert diese in den Ordner "$NUXEO_HOME/nxserver/bundles". Sollten Sie über ein Maven-Projekt mit mehreren Modulen verfügen, ist dies möglicherweise ungünstig. Für eine einfachere Konfiguration können Sie dem Stammverzeichnis des Projekts eine ".nuxeo-s2i"-Manifestdatei hinzufügen, in der festgelegt ist, welche Elemente bereitgestellt werden sollen. Sie können selbstverständlich auch ein Nuxeo-Paket angeben. Beispieldateien sehen möglicherweise wie folgt aus:

# Directory where to find JAR artifacts to deploy
#ARTIFACT_DIR=target

# Nuxeo package to deploy
#NUXEO_PACKAGE=sample-package/target/sample-package-*.zip

# Whether to start Nuxeo in a test phase and do some smoke tests
#NUXEO_SMOKE_TEST=false

Das ist jedoch nur der Anfang - wir werden künftig sicherlich weitere Optionen hinzufügen, beispielsweise die Ausführung von Maven-Integrationstests auf der bereitgestellten Nuxeo-Instanz. Wir freuen uns jederzeit über Ihr Feedback!

Sollte zu guter Letzt das "assemble"-Skript Ihren Ansprüchen nicht genügen, können Sie jederzeit ein eigenes angeben, indem Sie den Source-to-Image-Anweisungen folgen.

Kontinuierlicher Entwicklungsfluss

S2I ist ein sehr einfaches Tool, mit dessen Hilfe Code in ein ausführbares Docker-Image verwandelt wird. Mit OpenShift jedoch lässt es uns Entwicklung und Bereitstellung vollständig automatisieren.

Das Nuxeo-S2I-image befindet sich derzeit noch in der Entwicklung. Wenn Sie es gemeinsam mit Nuxeo Studio einsetzen, verfügen Sie über eine vollständige Kette mit schnellen Optionen für die Anwendungsentwicklung. Vergessen Sie nicht, uns Ihr Feedback zukommen zu lassen und uns von Ihren Experimenten mit den hier beschriebenen Optionen zu berichten.