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

In den beiden vorherigen Beiträgen haben wir erklärt, wie man moderne Webanwendungen in nur wenigen Schritten bereitstellt und wie man das neue S2I-Image zusammen mit einem fertigen HTTP-Server-Image, wie NGINX, mit Hilfe von verknüpften Builds für die Produktion verwendet.
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 besprechen, was OpenShift Pipelines sind und wie sie als Alternative zu verbundenen Builds eingesetzt werden können.
OpenShift als Entwicklungsumgebung
Entwicklungsworkflow
Wie bereits im erwähnt, besteht der typische Entwicklungsprozess für moderne Webanwendungen einfach aus einem „Entwicklungsserver“, der Änderungen an lokalen Dateien überwacht. Wenn Änderungen vorgenommen werden, wird das Anwendungs-Build gestartet, und anschließend wird es im Browser aktualisiert.
In den meisten modernen Frameworks ist ein solcher „Entwicklungsserver“ in die entsprechenden Befehlszeilentools integriert.
Lokales Beispiel
Zunächst schauen wir uns an, wie das bei der lokalen Ausführung von Anwendungen funktioniert. Als Beispiel nehmen wir die Anwendung aus früheren Artikeln, wobei praktisch die gleichen Konzepte des Workflows auch auf alle anderen modernen Frameworks angewendet werden.
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:

Und unsere Anwendung öffnet sich im Standardbrowser:

Jetzt, wenn wir Änderungen an der Datei vornehmen, sollte sich die Anwendung im Browser aktualisieren.
Okay, die Entwicklung im lokalen Modus ist klar, aber wie erreichen wir das Gleiche auf OpenShift?
Entwicklungsserver auf OpenShift
Wenn ihr euch erinnert, haben wir im , die sogenannte Ausführungsphase des S2I-Images besprochen und gesehen, dass standardmäßig das Modul serve für die Bereitstellung unserer Webanwendung zuständig ist.
Wenn wir jedoch genauer hinsehen aus diesem Beispiel, gibt es eine Umgebungsvariable $NPM_RUN, die es ermöglicht, auch einen eigenen Befehl auszuführen.
Zum Beispiel kann das Modul nodeshift verwendet werden, um unsere Anwendung bereitzustellen:
$ npx nodeshift --deploy.env NPM_RUN="yarn start" --dockerImage=nodeshift/ubi8-s2i-web-app
Hinweis: Das obige Beispiel wird verkürzt dargestellt, um die allgemeine Idee zu veranschaulichen.
Hier haben wir in unsere Bereitstellung die Umgebungsvariable NPM_RUN hinzugefügt, die dem Ausführungsprozess mitteilt, dass er den Befehl yarn start ausführen soll, der den Entwicklungsserver von React innerhalb unseres OpenShift-Pods startet.
Wenn wir die Logs des laufenden Pods ansehen, wird Folgendes angezeigt:

Natürlich ist das alles wenig hilfreich, bis wir den lokalen Code mit dem Remote-Code synchronisieren können, der ebenfalls auf Änderungen überwacht wird.
Synchronisierung von Remote- und lokalem Code
Glücklicherweise hilft nodeshift bei der Synchronisierung, und zur Überwachung von Änderungen kann der Befehl watch verwendet werden.
Nachdem wir den Befehl zur Bereitstellung des Entwicklungsservers für unsere Anwendung ausgeführt haben, können wir diesen Befehl sicher verwenden:
$ npx nodeshift watch
In der Folge wird eine Verbindung zu dem gestarteten Pod hergestellt, den wir zuvor erstellt haben. Die Synchronisierung unserer lokalen Dateien mit dem entfernten Cluster wird aktiviert, und die Dateien auf unserem lokalen System beginnen, auf Änderungen überwacht zu werden.
Wenn wir nun die Datei src/App.js aktualisieren, reagiert das System auf diese Änderungen, kopiert sie in den entfernten Cluster und startet den Entwicklungsserver, der dann unsere Anwendung im Browser aktualisiert.
Zur Vollständigkeit 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 Befehl 'watch' ist eine Abstraktion über dem Befehl 'oc rsync'. Detailliertere Informationen darüber, wie das funktioniert, finden Sie hier. .
Das war ein Beispiel für React, aber eine ähnliche Methode kann auch mit anderen Frameworks verwendet werden; passen Sie einfach die Umgebungsvariable NPM_RUN entsprechend an.
OpenShift Pipelines

Als Nächstes sprechen wir über ein Werkzeug namens OpenShift Pipelines und wie es als Alternative zu verknüpften Builds (chained build) verwendet werden kann.
Was sind OpenShift Pipelines?
OpenShift Pipelines – ist ein cloud-orientiertes CI/CD-System für kontinuierliche Integration und Lieferung, das zur Organisation von Pipelines unter Verwendung von Tekton entwickelt wurde. Tekton ist ein flexibles, Kubernetes-natives CI/CD-Framework mit Open-Source-Code, das die Bereitstellung auf verschiedenen Plattformen (Kubernetes, serverless, virtuelle Maschinen usw.) durch Abstraktion von der darunter liegenden Ebene automatisiert.
Um diesen Artikel zu verstehen, sind bestimmte Kenntnisse über Pipelines erforderlich. Daher empfehlen wir dringend, sich zunächst mit dem .
Einrichten der Arbeitsumgebung
Um mit den Beispielen aus diesem Artikel zu experimentieren, müssen Sie zunächst die Arbeitsumgebung vorbereiten:
- Installieren und Konfigurieren eines OpenShift 4-Clusters. In unseren Beispielen verwenden wir dafür CodeReady Containers (CRD), deren Installationsanleitungen Sie finden können .
- Nachdem der Cluster bereit ist, muss der Pipeline Operator darauf installiert werden. Keine Angst, es ist einfach; die Installationsanleitung finden Sie .
- Hochladen (tkn) .
- Führen Sie das Kommandozeilenwerkzeug create-react-app aus, um eine Anwendung zu erstellen, die später bereitgestellt wird (es handelt sich um eine einfache Anwendung ).
- (Optional) Klonen Sie das Repository, um das Beispielprojekt lokal mit dem Befehl npm install und anschließend npm start auszuführen.
Im Anwendungsrepository wird es auch einen Ordner k8s geben, in dem die YAML-Dateien für Kubernetes/OpenShift gespeichert sind, die zum Bereitstellen der Anwendung verwendet werden. Dort befinden sich Tasks, ClusterTasks, Ressourcen und Pipelines, die wir in diesem erstellen werden. .
Legen wir los
Zunächst müssen wir ein neues Projekt im OpenShift-Cluster erstellen. Wir nennen dieses Projekt webapp-pipeline und erstellen es mit dem folgenden Befehl:
$ oc new-project webapp-pipeline
Der Projektname wird später im Code verwendet, also denken Sie daran, den Code in den Beispielen entsprechend zu ändern, falls Sie ihn anders benennen möchten. Ab diesem Punkt werden wir nicht von oben nach unten, sondern von unten nach oben arbeiten: Zuerst erstellen wir alle Komponenten der Pipeline und dann die Pipeline selbst.
Also, zunächst…
Aufgaben Tasks
Wir erstellen eine Reihe von Aufgaben (tasks), die helfen werden, die Anwendung in unserem Pipeline-Prozess bereitzustellen. Die erste Aufgabe – apply_manifests_task – ist dafür verantwortlich, die YAML-Dateien der Kubernetes-Ressourcen (Service, Deployment und Route), die sich im k8s-Ordner unserer Anwendung befinden, anzuwenden. Die zweite Aufgabe – update_deployment_task – hat die Aufgabe, das bereits bereitgestellte Image auf das zu aktualisieren, das unser Pipeline-Prozess erstellt.
Keine Sorge, wenn es im Moment noch nicht ganz klar ist. Tatsächlich sind diese Aufgaben eine Art Dienstprogramm, und wir werden sie später ausführlicher besprechen. Aber zunächst erstellen wir sie einfach:
$ 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
Danach überprüfen wir mit dem tkn CLI-Befehl, ob die Aufgaben erstellt wurden:
$ tkn task ls
NAME ALTER
apply-manifests vor 1 Minute
update-deployment vor 1 Minute
Hinweis: Dies sind lokale Aufgaben Ihres aktuellen Projekts.
Cluster-Aufgaben
Clusteraufgaben sind grundsätzlich 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 gestartet wird. Der Unterschied besteht darin, dass die Clusteraufgabe im gesamten Cluster verfügbar ist. Um eine Liste der Clusteraufgaben zu sehen, die automatisch erstellt werden, wenn Sie einen Pipeline-Operator hinzufügen, verwenden wir erneut den Befehl tkn CLI:
$ tkn clustertask ls
NAME ALTER
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 Clusteraufgaben. Die erste wird ein S2I-Image generieren und es an das interne OpenShift-Register senden; die zweite wird unser Image auf Basis von NGINX erstellen, wobei wir bereits unsere gebaute Anwendung als Inhalt verwenden.
Image erstellen und senden
Bei der Erstellung der ersten Aufgabe wiederholen wir das, was wir im vorherigen Artikel über verknüpfte Builds bereits gemacht haben. Erinnern wir uns, dass wir das S2I-Image (ubi8-s2i-web-app) verwendet haben, um unsere Anwendung zu „bauen“, und am Ende erhielten wir ein Image, das im internen OpenShift-Register gespeichert wurde. Jetzt werden wir dieses S2I-Image der Webanwendung verwenden, um ein DockerFile für unsere Anwendung zu erstellen, und dann Buildah einsetzen, um den eigentlichen Build durchzuführen und das resultierende Image in das interne OpenShift-Register zu senden, da dies genau das ist, was OpenShift tut, wenn Sie Ihre Anwendungen mit NodeShift bereitstellen.
Sie fragen sich, woher wir das alles wissen? Aus , wir haben es einfach kopiert und angepasst.
Jetzt erstellen wir die Clusteraufgabe s2i-web-app:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/s2i-web-app-task.yaml
Wir werden dies nicht im Detail durchgehen, sondern uns lediglich auf den Parameter OUTPUT_DIR konzentrieren:
params:
- name: OUTPUT_DIR
description: Der Speicherort des Build-Ausgabeverzeichnisses
default: build
Standardmäßig ist dieser Parameter auf build gesetzt, wohin React den erstellten Inhalt ablegt. In anderen Frameworks werden andere Pfade verwendet, zum Beispiel dist in Ember. Das Ergebnis unserer ersten Clusteraufgabe wird ein Image sein, das unser erstelltes HTML, JavaScript und CSS enthält.
Wir erstellen ein Image auf Basis von NGINX
Was unsere zweite Clusteraufgabe betrifft, so soll sie ein Image auf Basis von NGINX erstellen, wobei der Inhalt unserer bereits zusammengestellten Anwendung verwendet wird. Im Grunde genommen handelt es sich hierbei um den Teil des vorherigen Abschnitts, in dem wir die verknüpften Builds (chained builds) behandelt haben.
Dazu werden wir, genau wie oben, eine Clusteraufgabe webapp-build-runtime erstellen:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/clustertasks/webapp-build-runtime-task.yaml
Wenn wir den Code dieser Clusteraufgaben betrachten, fällt auf, dass das verwendete Git-Repository oder die Namen der zu erstellenden Images nicht konkretisiert sind. Wir geben lediglich an, was wir in Git übergeben oder in ein bestimmtes Image schreiben müssen. Genau deshalb können diese Clusteraufgaben wiederverwendet werden, auch bei der Arbeit mit anderen Anwendungen.
Und hier gelangen wir elegant zum nächsten Punkt…
Ressourcen
Da die Clusteraufgaben, wie wir gerade erwähnt haben, so allgemein wie möglich gehalten werden müssen, müssen wir Ressourcen erstellen, die als Eingabe (Git-Repository) und Ausgabe (Endbilder) verwendet werden. Die erste benötigte Ressource ist Git, wo unsere Anwendung gespeichert ist, etwas in der Art von:
# 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 der PipelineResource-Typ den Wert git. Der Schlüssel url im Abschnitt params verweist auf das spezifische Repository und gibt den master-Branch an (dies ist optional, wir fügen es jedoch zur Vollständigkeit hinzu).
Jetzt müssen wir eine Ressource für das Image erstellen, in dem die Ergebnisse der Ausführung der s2i-web-app-Aufgabe gespeichert werden, das wird so gemacht:
# 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, insbesondere auf das im Namespace webapp-pipeline. Vergessen Sie nicht, diesen Parameter zu ändern, wenn Sie einen anderen Namespace verwenden.
Und schließlich wird die letzte benötigte Ressource ebenfalls den Typ image haben und es wird das endgültige NGINX-Image sein, das dann bei der Bereitstellung 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
Beachten Sie erneut, dass diese Ressource das Image im internen OpenShift-Registry im Namespace webapp-pipeline speichert.
Um all diese Ressourcen auf einmal zu erstellen, verwenden wir den Befehl create:
$ oc create -f https://raw.githubusercontent.com/nodeshift/webapp-pipeline-tutorial/master/resources/resource.yaml
Um sicherzustellen, dass die Ressourcen erstellt wurden, können Sie folgendes tun:
$ tkn resource ls
Pipeline
Jetzt, da wir alle erforderlichen Komponenten haben, erstellen wir die Pipeline mit dem folgenden Befehl:
$ 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 durchgehen. Die erste ist der Name:
apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: build-and-deploy-react
Dann sehen wir im Abschnitt 'spec' die Ressourcenangaben, 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
Nun erstellen wir die Aufgaben, die unser Pipeline ausführen muss. Zuerst wird die bereits erstellte Aufgabe s2i-web-app ausgeführt:
tasks:
- name: build-web-application
taskRef:
name: s2i-web-app
kind: ClusterTask
Diese Aufgabe nimmt die Eingangs- (gir-Ressource) und Ausgangsparameter (Ressource built-web-application-image). Außerdem übergeben wir ihr einen speziellen Parameter, damit sie TLS nicht validiert, da wir selbstsignierte Zertifikate verwenden:
resources:
inputs:
- name: source
resource: web-application-repo
outputs:
- name: image
resource: built-web-application-image
params:
- name: TLSVERIFY
value: "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
kind: ClusterTask
Wie bei der vorherigen Aufgabe übergeben wir eine Ressource, aber diesmal ist es das built-web-application-image (das Ergebnis unserer vorherigen Aufgabe). Als Ausgabe legen wir erneut ein Bild fest. Da diese Aufgabe nach der vorherigen ausgeführt werden soll, fügen wir das Feld runAfter hinzu:
resources:
inputs:
- name: image
resource: built-web-application-image
outputs:
- name: image
resource: runtime-web-application-image
params:
- name: TLSVERIFY
value: "false"
runAfter:
- build-web-application
Die nächsten beiden Aufgaben sind für die Anwendung der YAML-Dateien des Dienstes, der Route und des Deployments verantwortlich, die sich im k8s-Verzeichnis unserer Webanwendung befinden, sowie dafür, dieses Deployment bei der Erstellung neuer Images zu aktualisieren. Diese beiden Clusteraufgaben haben wir bereits am Anfang des Artikels definiert.
Start der Pipeline
Nun sind alle Teile unserer Pipeline erstellt, und wir werden sie mit dem folgenden Befehl starten:
$ tkn pipeline start build-and-deploy-react
An dieser Stelle wird die Befehlszeile im interaktiven Modus verwendet, und es müssen die entsprechenden Ressourcen als Antwort auf jede ihrer Anfragen ausgewählt werden: Für die Ressource git wählen wir web-application-repo, dann für die Ressource des ersten Images – built-web-application-image, und schließlich für die Ressource des zweiten Images – 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 folgendem Befehl:
$ tkn pipeline logs -f
Sobald die Pipeline gestartet ist und die Anwendung bereitgestellt wurde, fordern wir den veröffentlichten Route mit folgendem Befehl an:
$ oc get route react-pipeline-example --template='http://{{.spec.host}}'
Für eine bessere Übersicht können wir unsere Pipeline im Developer-Modus der Web-Konsole im Abschnitt Pipelines, wie in Abb. 1 gezeigt, betrachten.

Abb. 1. Übersicht der gestarteten Pipelines.
Ein Klick auf die gestartete Pipeline zeigt zusätzliche Informationen an, wie in Abb. 2 dargestellt.

Abb. 2. Zusätzliche Informationen zur Pipeline.
Nach den zusätzlichen Informationen können die gestarteten Anwendungen im Blick Topology, wie in Abb. 3 gezeigt, betrachtet werden.

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

Abb. 4. Gestartete React-Anwendung.
Fazit
Wir haben gezeigt, wie man einen Entwicklungsserver für seine Anwendung auf OpenShift startet und ihn mit dem lokalen Dateisystem synchronisiert. Außerdem haben wir betrachtet, wie man eine chained-build Template mit OpenShift Pipelines simuliert. Alle Beispielcodes aus diesem Artikel sind verfügbar unter .
Weitere Ressourcen (EN)
- Kostenloses E-Book
- Weitere Artikel über auf der Red Hat-Website
Ankündigungen bevorstehender Webinare
Wir starten eine Reihe von Freitagswebinaren zum nativen Erlebnis mit der Red Hat OpenShift Container Platform und Kubernetes:
Quelle: habr.com
