Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Hallo zusammen in diesem Blog! Hier ist der dritte Beitrag aus der Reihe, in der wir zeigen, wie man moderne Webanwendungen auf Red Hat OpenShift bereitstellt.

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

In den beiden vorherigen Beiträgen haben wir beschrieben, wie man moderne Webanwendungen in nur wenigen Schritten bereitstellt und wie man das neue S2I-Image zusammen mit einem vorgefertigten HTTP-Server-Image, zum Beispiel NGINX, mithilfe von verbundenen Builds für die Organisation der Produktionsbereitstellung nutzt.

Heute zeigen wir, wie man auf der OpenShift-Plattform einen Entwicklungsserver für seine Anwendung startet und ihn mit dem lokalen Dateisystem synchronisiert. Außerdem werden wir darüber sprechen, was OpenShift Pipelines sind und wie sie als Alternative zu verbundenen Builds eingesetzt werden können.

OpenShift als Entwicklungsumgebung

Entwicklungsworkflow

Wie bereits im ersten Beitragerwähnt, ist der typische Entwicklungsprozess für moderne Webanwendungen im Wesentlichen ein "Entwicklungsserver", der Änderungen an lokalen Dateien überwacht. Wenn diese eintreten, wird eine Anwendungskompilation gestartet und die Anwendung wird im Browser aktualisiert.

In den meisten modernen Frameworks ist ein solcher "Entwicklungsserver" in die entsprechenden Befehlszeilenwerkzeuge integriert.

Lokales Beispiel

Schauen wir uns zunächst an, wie das bei der lokalen Ausführung von Anwendungen funktioniert. Als Beispiel nehmen wir die Anwendung React aus den vorherigen Artikeln, obwohl die gleichen Konzepte des Workflows auch in allen anderen modernen Frameworks Anwendung finden.
Um den "Entwicklungsserver" in unserem Beispiel mit React zu starten, geben wir den folgenden Befehl ein:

$ npm run start

Dann sehen wir im Terminalfenster ungefähr Folgendes:

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Und unsere Anwendung wird im Standardbrowser geöffnet:

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Jetzt, wenn wir Änderungen an der Datei vornehmen, sollte die Anwendung im Browser aktualisiert werden.

Okay, mit der Entwicklung im lokalen Modus ist alles klar, aber wie erreichen wir das Gleiche auf OpenShift?

Entwicklungsserver auf OpenShift

Wenn Sie sich erinnern, haben wir in im vorherigen Beitragden sogenannten Startphase (run phase) des S2I-Images behandelt und gesehen, dass standardmäßig das Modul serve für unsere Webanwendung zuständig ist.

Wenn wir jedoch genauer hinsehen, Ausführungsskript aus diesem Beispiel, finden wir die Umgebungsvariable $NPM_RUN, die es uns ermöglicht, auch unseren eigenen Befehl auszuführen.

Wir können zum Beispiel das Modul nodeshift verwenden, um unsere Anwendung bereitzustellen:

$ npx nodeshift --deploy.env NPM_RUN="yarn start" --dockerImage=nodeshift/ubi8-s2i-web-app

Hinweis: Das obige Beispiel wird aus Gründen der Kürze angeführt, um die allgemeine Idee zu veranschaulichen.

Hier haben wir in unser Deployment die Umgebungsvariable NPM_RUN hinzugefügt, die dem Ausführungsprozess mitteilt, dass er den Befehl yarn start ausführen soll, um den Entwicklungsserver von React innerhalb unseres OpenShift-Pods zu starten.

Wenn man das Protokoll des laufenden Pods betrachtet, sieht es ungefähr so aus:

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Natürlich ist das alles nichtssagend, solange wir unseren lokalen Code nicht mit dem Code synchronisieren können, der ebenfalls auf Änderungen überwacht wird, aber auf einem entfernten Server lebt.

Synchronisation von entferntem und lokalem Code

Glücklicherweise kann nodeshift leicht bei der Synchronisation helfen, und zur Überwachung von Änderungen kann der Befehl watch verwendet werden.

Nachdem wir also den Befehl zum Deployen des Entwicklungsservers für unsere Anwendung ausgeführt haben, können wir getrost folgenden Befehl verwenden:

$ npx nodeshift watch

Infolgedessen wird eine Verbindung zu dem zuvor erstellten laufenden Pod hergestellt, die Synchronisation unserer lokalen Dateien mit dem entfernten Cluster aktiviert, und die Dateien auf unserem lokalen System beginnen, auf Änderungen überwacht zu werden.

Wenn jetzt die Datei src/App.js aktualisiert wird, reagiert das System auf diese Änderungen, kopiert sie zum entfernten Cluster und startet den Entwicklungsserver, der dann unsere Anwendung im Browser aktualisiert.

Um das Bild zu vervollständigen, zeigen wir, wie diese Befehle vollständig aussehen:

$ npx nodeshift --strictSSL=false --dockerImage=nodeshift/ubi8-s2i-web-app --build.env YARN_ENABLED=true --expose --deploy.env NPM_RUN="yarn start" --deploy.port 3000

$ npx nodeshift watch --strictSSL=false

Der watch-Befehl ist eine Abstraktion über dem oc rsync-Befehl, mehr darüber, wie es funktioniert, kann man hier erfahren. hier.

Das war ein Beispiel für React, aberelbe Methode kann auch mit anderen Frameworks verwendet werden, man muss lediglich die Umgebungsvariable NPM_RUN entsprechend festlegen.

OpenShift Pipelines

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Als Nächstes werden wir über ein Tool namens OpenShift Pipelines sprechen und wie es als Alternative zu verknüpften Builds (chained build) verwendet werden kann.

Was sind OpenShift Pipelines?

OpenShift Pipelines ist ein cloudorientiertes CI/CD-System für kontinuierliche Integration und Bereitstellung, das zur Organisation von Pipelines mit Tekton verwendet wird. Tekton ist ein flexibles, Kubernetes-natives CI/CD-Framework mit offenem Quellcode, das die Automatisierung der Bereitstellung auf verschiedenen Plattformen (Kubernetes, serverless, virtuelle Maschinen usw.) durch Abstraktion von der darunterliegenden Ebene ermöglicht.

Um diesen Artikel zu verstehen, sind bestimmte Kenntnisse über Pipelines erforderlich, daher empfehlen wir dringend, sich zunächst mit dem offiziellen Handbuch.

Einrichten der Arbeitsumgebung

Um mit den Beispielen aus diesem Artikel zu experimentieren, müssen Sie zunächst die Arbeitsumgebung vorbereiten:

  1. Installieren und Einrichten eines OpenShift 4 Clusters. In unseren Beispielen wird dafür CodeReady Containers (CRD) verwendet, die Installationsanleitung finden Sie hier.
  2. Sobald das Cluster bereit ist, muss der Pipeline-Operator installiert werden. Keine Sorge, das ist einfach, die Installationsanleitung finden Sie hier.
  3. Herunterladen Tekton CLI (tkn) hier.
  4. Starten Sie das Befehlszeilenwerkzeug create-react-app, um eine Anwendung zu erstellen, die anschließend bereitgestellt wird (dies ist eine einfache Anwendung React).
  5. (Optional) Klonen Sie das Repository, um das Anwendungsbeispiel lokal mit dem Befehl npm install auszuführen und dann npm start.

Im Anwendungsrepository gibt es auch einen Ordner k8s, in dem sich die YAML-Dateien von Kubernetes/OpenShift befinden, die zur Bereitstellung der Anwendung verwendet werden. Dort befinden sich Tasks, ClusterTasks, Ressourcen und Pipelines, die wir in diesem das Repository.

Wir beginnen

Zuerst müssen wir für unser Beispiel ein neues Projekt im OpenShift-Cluster erstellen. Nennen wir dieses Projekt webapp-pipeline und erstellen wir es mit dem folgenden Befehl:

$ oc new-project webapp-pipeline

Dieser Projektname wird dann im Code verwendet, also vergessen Sie nicht, den Code der Beispiele entsprechend zu ändern, falls Sie ihm einen anderen Namen geben. Ab diesem Punkt werden wir nicht von oben nach unten, sondern von unten nach oben vorgehen: das heißt, wir erstellen zuerst alle Bestandteile der Pipeline und erst danach die Pipeline selbst.

Also, als Erstes…

Aufgaben Tasks

Wir erstellen ein paar Aufgaben (tasks), die dann helfen werden, die Anwendung im Rahmen unserer Pipeline zu deployen. Die erste Aufgabe – apply_manifests_task – ist verantwortlich für die Anwendung der YAML-Dateien der Kubernetes-Ressourcen (Service, Deployment und Route), die sich im k8s-Ordner unserer Anwendung befinden. Die zweite Aufgabe – update_deployment_task – ist verantwortlich für das Aktualisieren des bereits bereitgestellten Images auf das, das von unserer Pipeline erstellt wird.

Keine Sorge, wenn es bisher noch nicht ganz klar ist. Tatsächlich sind diese Aufgaben eine Art von Dienstprogrammen, und wir werden sie später genauer erläutern. Lassen Sie uns vorerst einfach die beiden erstellen:

$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/update_deployment_task.yaml
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/tasks/apply_manifests_task.yaml

Dann überprüfen wir mit dem tkn CLI-Befehl, ob die Aufgaben erstellt wurden:

$ tkn task ls

NAME                AGE
apply-manifests     vor 1 Minute
update-deployment   vor 1 Minute

Hinweis: Dies sind lokale Aufgaben Ihres aktuellen Projekts.

Klastenaufgaben Cluster tasks

Klastenaufgaben sind im Grunde dasselbe wie einfache Aufgaben. Das heißt, es handelt sich um eine wiederverwendbare Sammlung von Schritten, die auf verschiedene Weise kombiniert werden, wenn eine bestimmte Aufgabe ausgeführt wird. Der Unterschied besteht darin, dass eine Klastenaufgabe im gesamten Cluster verfügbar ist. Um die Liste der Klastenaufgaben zu sehen, die automatisch erstellt werden, wenn der Pipeline Operator hinzugefügt wird, verwenden wir erneut den tkn CLI-Befehl:

$ tkn clustertask ls

NAME                       AGE
buildah                    vor 1 Tag
buildah-v0-10-0            vor 1 Tag
jib-maven                  vor 1 Tag
kn                         vor 1 Tag
maven                      vor 1 Tag
openshift-client           vor 1 Tag
openshift-client-v0-10-0   vor 1 Tag
s2i                        vor 1 Tag
s2i-go                     vor 1 Tag
s2i-go-v0-10-0             vor 1 Tag
s2i-java-11                vor 1 Tag
s2i-java-11-v0-10-0        vor 1 Tag
s2i-java-8                 vor 1 Tag
s2i-java-8-v0-10-0         vor 1 Tag
s2i-nodejs                 vor 1 Tag
s2i-nodejs-v0-10-0         vor 1 Tag
s2i-perl                   vor 1 Tag
s2i-perl-v0-10-0           vor 1 Tag
s2i-php                    vor 1 Tag
s2i-php-v0-10-0            vor 1 Tag
s2i-python-3               vor 1 Tag
s2i-python-3-v0-10-0       vor 1 Tag
s2i-ruby                   vor 1 Tag
s2i-ruby-v0-10-0           vor 1 Tag
s2i-v0-10-0                vor 1 Tag

Jetzt erstellen wir zwei Klastenaufgaben. Die erste wird ein S2I-Image generieren und es in das interne OpenShift-Registry hochladen; die zweite wird unser Image auf Basis von NGINX erstellen und die bereits entwickelte Anwendung als Inhalt verwenden.

Wir erstellen und laden das Image hoch

Bei der Erstellung der ersten Aufgabe wiederholen wir das, was wir bereits im vorherigen Artikel über verknüpfte Builds behandelt haben. Wir erinnern daran, dass wir das S2I-Image (ubi8-s2i-web-app) verwendet haben, um unsere Anwendung zu „bauen“, und letztlich ein Image erhalten haben, das im internen OpenShift-Registry gespeichert ist. Jetzt werden wir dieses S2I-Image der Webanwendung verwenden, um ein DockerFile für unsere Anwendung zu erstellen, und dann Buildah einsetzen, um den tatsächlichen Build durchzuführen und das erhaltene Image in die interne OpenShift-Registry zu senden, denn genau das macht OpenShift, wenn Sie Ihre Anwendungen mit NodeShift bereitstellen.

Fragen Sie sich, woher wir das alles wissen? Aus официальной версии official Node.js, haben wir es einfach kopiert und an unsere Bedürfnisse angepasst.

So, jetzt erstellen wir die Cluster-Aufgabe s2i-web-app:

$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/s2i-web-app-task.yaml

Wir werden das nicht im Detail durchgehen, sondern nur auf den Parameter OUTPUT_DIR eingehen:

params:
      - name: OUTPUT_DIR
        description: Der Speicherort des Build-Ausgabeverzeichnisses
        default: build

Standardmäßig ist dieser Parameter auf build gesetzt, dorthin legt React den gebauten Inhalt ab. In anderen Frameworks werden andere Pfade verwendet, zum Beispiel in Ember ist es dist. Die Ausgabe unserer ersten Cluster-Aufgabe wird ein Image sein, das die von uns gebauten HTML-, JavaScript- und CSS-Dateien enthält.

Wir erstellen ein Image auf der Basis von NGINX

Was unsere zweite Cluster-Aufgabe betrifft, so soll sie ein Image auf Basis von NGINX erstellen, das den Inhalt unserer bereits gebauten Anwendung verwendet. Im Grunde ist dies der Teil des vorherigen Abschnitts, in dem wir die verknüpften Builds behandelt haben.

Dazu – ganz wie oben – erstellen wir die Cluster-Aufgabe webapp-build-runtime:

$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/webapp-build-runtime-task.yaml

Wenn man den Code dieser Cluster-Aufgaben betrachtet, sieht man, dass dort nicht das Git-Repository spezifiziert wird, mit dem wir arbeiten, oder die Namen der Images, die wir erstellen. Wir geben nur an, was wir an Git übergeben oder ein Image, in das das finale Image ausgegeben werden soll. Deshalb können diese Cluster-Aufgaben wiederverwendet werden, auch wenn wir mit anderen Anwendungen arbeiten.

Und hier kommen wir elegant zum nächsten Punkt…

Ressourcen

Also, da die Cluster-Aufgaben, wie wir gerade gesagt haben, so allgemein wie möglich sein müssen, müssen wir Ressourcen erstellen, die als Eingabe (Git-Repository) und Ausgabe (Endbilder) verwendet werden. Die erste Ressource, die wir benötigen, ist Git, wo sich unsere Anwendung befindet, etwas wie das:

# This resource is the location of the git repo with the web application source
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: web-application-repo
spec:
  type: git
  params:
    - name: url
      value: https://github.com/nodeshift-starters/react-pipeline-example
    - name: revision
      value: master

Hier hat PipelineResource den Typ git. Der Schlüssel url im Abschnitt params verweist auf das spezifische Repository und legt den Branch master fest (das ist optional, aber wir geben ihn der Vollständigkeit halber an).

Jetzt müssen wir eine Ressource für das Bild erstellen, in dem die Ergebnisse der Ausführung der Aufgabe s2i-web-app gespeichert werden. Das geschieht so:

# This resource is the result of running "npm run build",  the resulting built files will be located in /opt/app-root/output
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: built-web-application-image
spec:
  type: image
  params:
    - name: url
      value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-application:latest

Hier hat PipelineResource den Typ image, und der Wert des Parameters url verweist auf das interne OpenShift Image Registry, konkret auf das, das sich im Namespace webapp-pipeline befindet. Vergessen Sie nicht, diesen Parameter zu ändern, wenn Sie einen anderen Namespace verwenden.

Und schließlich wird die letzte Ressource, die wir benötigen, ebenfalls vom Typ image sein und es wird das endgültige NGINX-Bild sein, das dann beim Deployment verwendet wird:

# This resource is the image that will be just the static html, css, js files being run with nginx
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: runtime-web-application-image
spec:
  type: image
  params:
    - name: url
      value: image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtime-web-application:latest

Und wieder sei darauf hingewiesen, dass diese Ressource das Bild im internen OpenShift-Register im Namespace webapp-pipeline speichert.

Um all diese Ressourcen gleichzeitig zu erstellen, verwenden wir den Befehl create:

$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/resources/resource.yaml

Sie können überprüfen, ob die Ressourcen erstellt wurden, indem Sie Folgendes eingeben:

$ tkn resource ls

Pipeline

Jetzt, wo wir alle notwendigen Komponenten haben, erstellen wir die Pipeline, indem wir den folgenden Befehl ausführen:

$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/pipelines/build-and-deploy-react.yaml

Aber bevor wir diesen Befehl ausführen, lassen Sie uns diese Komponenten analysieren. Die erste ist der Name:

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: build-and-deploy-react

Dann sehen wir im Abschnitt spec die Angabe der Ressourcen, die wir zuvor erstellt haben:

spec:
  resources:
    - name: web-application-repo
      type: git
    - name: built-web-application-image
      type: image
    - name: runtime-web-application-image
      type: image

Dann erstellen wir die Aufgaben, die unser Pipeline ausführen soll. Zuerst muss sie die bereits von uns erstellte Aufgabe s2i-web-app ausführen:

tasks:
    - name: build-web-application
      taskRef:
        name: s2i-web-app
        kind: ClusterTask

Diese Aufgabe nimmt die Eingangsparameter (git-Ressource) und die Ausgangsparameter (Ressource built-web-application-image). Wir übergeben ihr auch einen speziellen Parameter, damit sie TLS nicht überprüft, da wir selbstsignierte Zertifikate verwenden:

Ressourcen:
        Eingaben:
          - Name: Quelle
            Ressource: web-application-repo
        Ausgaben:
          - Name: Bild
            Ressource: built-web-application-image
      Parameter:
        - Name: TLSVERIFY
          Wert: "false"

Die nächste Aufgabe ist fast identisch, nur dass hier die bereits erstellte Clusteraufgabe webapp-build-runtime aufgerufen wird:

Name: build-runtime-image
    TaskRef:
      Name: webapp-build-runtime
      Art: ClusterTask

Wie bei der vorherigen Aufgabe übergeben wir eine Ressource, aber jetzt ist es das built-web-application-image (Ausgabe unserer vorherigen Aufgabe). Und erneut definieren wir als Ausgabe ein Bild. Da diese Aufgabe nach der vorherigen ausgeführt werden muss, fügen wir das Feld runAfter hinzu:

Ressourcen:
        Eingaben:
          - Name: Bild
            Ressource: built-web-application-image
        Ausgaben:
          - Name: Bild
            Ressource: runtime-web-application-image
        Parameter:
        - Name: TLSVERIFY
          Wert: "false"
      runAfter:
        - build-web-application

Die nächsten beiden Aufgaben sind für die Anwendung der YAML-Dateien für den Dienst, die Route und das Deployment verantwortlich, die im k8s-Verzeichnis unserer Webanwendung leben, sowie für die Aktualisierung dieses Deployments bei der Erstellung neuer Bilder. Diese beiden Clusteraufgaben haben wir bereits zu Beginn des Artikels definiert.

Pipeline starten

Also, alle Teile unseres Pipelines sind erstellt, und wir werden sie mit dem folgenden Befehl starten:

$ tkn pipeline start build-and-deploy-react

In diesem Schritt wird die Befehlszeile im interaktiven Modus verwendet und man muss die entsprechenden Ressourcen als Antwort auf jede ihrer Anfragen auswählen: Für die Ressource git wählen wir web-application-repo, dann für die Ressource des ersten Bildes – built-web-application-image, und schließlich für die Ressource des zweiten Bildes – runtime-web-application-image:

? Choose the git resource to use for web-application-repo: web-application-repo (https://github.com/nodeshift-starters/react-pipeline-example)
? Choose the image resource to use for built-web-application-image: built-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/built-web-
application:latest)
? Choose the image resource to use for runtime-web-application-image: runtime-web-application-image (image-registry.openshift-image-registry.svc:5000/webapp-pipeline/runtim
e-web-application:latest)
Pipelinerun started: build-and-deploy-react-run-4xwsr

Jetzt überprüfen wir den Status der Pipeline mit dem folgenden Befehl:

$ tkn pipeline logs -f

Nachdem die Pipeline gestartet wurde und die Anwendung bereitgestellt ist, fordern wir die veröffentlichte Route mit dem folgenden Befehl an:

$ oc get route react-pipeline-example --template='http://{{.spec.host}}'

Für mehr Anschaulichkeit können wir unsere Pipeline im Entwickler-Modus der Web-Konsole im Abschnitt Pipelines, wie in Abb. 1 gezeigt.

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Abb. 1. Übersicht über die gestarteten Pipelines.

Ein Klick auf die gestartete Pipeline zeigt zusätzliche Informationen an, wie in Abb. 2 gezeigt.

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Abb. 2. Zusätzliche Informationen zur Pipeline.

Nach den zusätzlichen Informationen können die gestarteten Anwendungen im Sichtfeld Topologie, wie in Abb. 3 gezeigt.

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Abb. 3. gestarteter Pod.

Ein Klick auf den Kreis in der oberen rechten Ecke des Symbols öffnet unsere Anwendung, wie in Abb. 4 gezeigt.

Moderne Anwendungen auf OpenShift, Teil 3: OpenShift als Entwicklungsumgebung und OpenShift Pipelines

Abb. 4. gestartete React-Anwendung.

Fazit

Wir haben gezeigt, wie man auf OpenShift einen Entwicklungsserver für seine Anwendung starten und ihn mit dem lokalen Dateisystem synchronisieren kann. Außerdem haben wir betrachtet, wie man eine chained-build-Vorlage mit OpenShift Pipelines simuliert. Alle Beispielcodes aus diesem Artikel sind zu finden hier.

Zusätzliche Ressourcen (EN)

Ankündigungen bevorstehender Webinare

Wir starten eine Reihe von Freitags-Webinaren über die native Nutzung von Red Hat OpenShift Container Platform und Kubernetes:

Quelle: habr.com

60GB SSD 8Gb DDR4