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

Im vorherigen Beitrag haben wir kurz die Möglichkeiten des neuen S2I (Source-to-Image) Builder-Images erörtert, das zur Erstellung und Bereitstellung moderner Webanwendungen auf der OpenShift-Plattform dient. Dabei haben wir uns mit dem Thema der schnellen Bereitstellung von Anwendungen beschäftigt, und heute schauen wir uns an, wie man das S2I-Image als 'reines' Builder-Image verwenden und mit verknüpften Builds in OpenShift kombinieren kann.
Reines Builder-Image
Wie bereits im ersten Teil erwähnt, verfügen die meisten modernen Webanwendungen über einen sogenannten Build-Schritt, in dem normalerweise Operationen wie Code-Transpilation, das Zusammenführen mehrerer Dateien und Minifizierung stattfinden. Die aus diesen Vorgängen resultierenden Dateien – also statisches HTML, JavaScript und CSS – werden im Output-Ordner abgelegt. Der Ort dieses Ordners hängt normalerweise davon ab, welche Build-Tools verwendet werden, und für React ist dies der Ordner ./build (wir werden auf dieses Thema weiter unten detaillierter eingehen).
Source-to-Image (S2I)
In diesem Beitrag beschäftigen wir uns nicht mit dem Thema „Was ist S2I und wie verwendet man es?“ (darüber können Sie mehr lesen ), jedoch ist es wichtig, die beiden Phasen dieses Prozesses klar zu verstehen, um zu begreifen, was das Web App Builder-Image macht.
Phase der Assemblierung
Die Assemblierungsphase ähnelt im Wesentlichen dem, was passiert, wenn Sie `docker build` ausführen und schließlich ein neues Docker-Image erhalten. Diese Phase tritt entsprechend auf, wenn der Build auf der OpenShift-Plattform gestartet wird.
Im Fall des Web App Builder-Images ist das für die Installation der Abhängigkeiten Ihrer Anwendung und den Start des Builds verantwortlich. Standardmäßig verwendet das Builder-Image den Befehl `npm run build`, dieser kann jedoch über die Umgebungsvariable NPM_BUILD überschrieben werden.
Wie bereits erwähnt, hängt der Standort der bereitgestellten Anwendung von den verwendeten Werkzeugen ab. Bei React zum Beispiel befindet sich dieser im Ordner /build, während es bei Angular-Anwendungen der Ordner project_name/dist ist. Und wie bereits im letzten Beitrag gezeigt, kann der Speicherort des Ausgabeverzeichnisses, das standardmäßig auf build gesetzt ist, über die Umgebungsvariable OUTPUT_DIR überschrieben werden. Da der Speicherort des Ausgabeverzeichnisses je nach Framework unterschiedlich ist, kopieren Sie einfach die generierte Ausgabe in das Standardverzeichnis im Image, nämlich nach /opt/apt-root/output. Dies ist wichtig für das Verständnis des weiteren Teils dieses Artikels. Lassen Sie uns nun schnell zum nächsten Schritt übergehen – der Phase des Ausführens (run phase).
Phase des Ausführens (run phase)
Diese Phase tritt ein, wenn für das neue Image, das in der Assemblierungsphase erstellt wurde, der Befehl docker run aufgerufen wird. Dies geschieht auch bei der Bereitstellung auf der OpenShift-Plattform. Standardmäßig nutzt zum Bereitstellen von statischem Inhalt, der im oben angegebenen Standard-Ausgabeverzeichnis liegt.
Diese Methode eignet sich gut für die schnelle Bereitstellung von Anwendungen, allerdings sollte statischer Inhalt nicht auf diese Weise bereitgestellt werden. Da wir tatsächlich nur statischen Inhalt bereitstellen, ist die in unserem Node.js-Image enthaltene Installation nicht erforderlich – ein Webserver reicht aus.
Anders gesagt, benötigen wir bei der Erstellung das eine, beim Ausführen das andere. In solchen Situationen sind verkettete Builds (chained builds) nützlich.
Verkettete Builds (chained builds)
Das steht in der :
„Zwei Builds können miteinander verknüpft werden, wobei einer ein kompiliertes Artefakt erzeugt und der andere dieses Artefakt in einem separaten Image speichert, das verwendet wird, um dieses Artefakt auszuführen.“
Anders gesagt, wir können das Image Web App Builder verwenden, um unseren Build auszuführen, und dann das Image des Webservers, also NGINX, verwenden, um unseren Inhalt bereitzustellen.
So können wir das Image Web App Builder als „reinen“ Builder verwenden und gleichzeitig ein kleines Runtime-Image haben.
Schauen wir uns das nun an einem konkreten Beispiel an.
Für die Übung verwenden wir , erstellt mit dem Befehlszeilenwerkzeug create-react-app.
Um alles zusammenzuführen, benötigen wir .
Wir werden diese Datei im Detail durchgehen und beginnen mit dem Abschnitt für Parameter.
parameters:
- name: SOURCE_REPOSITORY_URL
description: Die Quell-URL für die Anwendung
displayName: Quell-URL
required: true
- name: SOURCE_REPOSITORY_REF
description: Der Branch-Name für die Anwendung
displayName: Quell-Branch
value: master
required: true
- name: SOURCE_REPOSITORY_DIR
description: Der Speicherort innerhalb des Quell-Repositorys der Anwendung
displayName: Quellverzeichnis
value: .
required: true
- name: OUTPUT_DIR
description: Der Speicherort der kompilierten statischen Dateien von Ihrem Web-App-Builder
displayName: Ausgabeverzeichnis
value: build
required: false
Das ist alles recht klar, aber man sollte auf den Parameter OUTPUT_DIR achten. Für die React-Anwendung aus unserem Beispiel besteht kein Grund zur Sorge, da React den Standardwert für das Ausgabeverzeichnis verwendet. Bei Angular oder etwas anderem muss dieser Parameter entsprechend angepasst werden.
Nun schauen wir uns den Abschnitt der ImageStreams an.
- apiVersion: v1
kind: ImageStream
metadata:
name: react-web-app-builder // 1
spec: {}
- apiVersion: v1
kind: ImageStream
metadata:
name: react-web-app-runtime // 2
spec: {}
- apiVersion: v1
kind: ImageStream
metadata:
name: web-app-builder-runtime // 3
spec:
tags:
- name: latest
from:
kind: DockerImage
name: nodeshift/ubi8-s2i-web-app:10.x
- apiVersion: v1
kind: ImageStream
metadata:
name: nginx-image-runtime // 4
spec:
tags:
- name: latest
from:
kind: DockerImage
name: 'centos/nginx-112-centos7:latest'
Betrachten Sie die dritte und vierte Abbildung. Beide sind als Docker-Images definiert, und es ist deutlich zu sehen, woher sie stammen.
Das dritte Image ist der web-app-builder und stammt von nodeshift/ubi8-s2i-web-app mit dem Tag 10.x auf .
Das vierte ist das NGINX-Image (Version 1.12) mit dem Tag latest auf .
Jetzt schauen wir uns die ersten beiden Images an. Beide sind zu Beginn leer und werden nur während des Build-Prozesses erstellt. Das erste Image – react-web-app-builder – wird das Ergebnis der Assembly-Phase sein, in der das Image web-app-builder-runtime und unser Quellcode kombiniert werden. Deshalb haben wir in den Namen dieses Images „-builder“ aufgenommen.
Das zweite Image – react-web-app-runtime – entsteht durch die Kombination von nginx-image-runtime und einigen Dateien aus dem Image react-web-app-builder. Dieses Image wird ebenfalls beim Deployment verwendet und enthält ausschließlich den Webserver sowie das statische HTML, JavaScript und CSS unserer Anwendung.
Klingt kompliziert? Lassen Sie uns die Build-Konfigurationen ansehen, dann wird es etwas klarer.
In unserer Vorlage gibt es zwei Build-Konfigurationen. Hier ist die erste, die ziemlich standardmäßig ist:
apiVersion: v1
kind: BuildConfig
metadata:
name: react-web-app-builder
spec:
output:
to:
kind: ImageStreamTag
name: react-web-app-builder:latest
source:
git:
uri: ${SOURCE_REPOSITORY_URL}
ref: ${SOURCE_REPOSITORY_REF}
contextDir: ${SOURCE_REPOSITORY_DIR}
type: Git
strategy:
sourceStrategy:
env:
- name: OUTPUT_DIR
value: ${OUTPUT_DIR}
from:
kind: ImageStreamTag
name: web-app-builder-runtime:latest
incremental: true
type: Source
triggers:
- github:
secret: ${GITHUB_WEBHOOK_SECRET}
type: GitHub
- type: ConfigChange
- imageChange: {}
type: ImageChange
Wie wir sehen können, gibt die Zeile mit dem Label 1 an, dass das Ergebnis dieses Builds in das Image react-web-app-builder eingefügt wird, das wir zuvor im Abschnitt über ImageStreams gesehen haben.
Die Zeile mit dem Label 2 gibt an, wo der Code herkommt. In unserem Fall handelt es sich um ein Git-Repository, und die Position, der Ref und der Kontext-Ordner sind durch Parameter definiert, die wir bereits zuvor gesehen haben.
Die Zeile mit dem Label 3 haben wir bereits im Abschnitt Parameter gesehen. Sie fügt die Umgebungsvariable OUTPUT_DIR hinzu, die in unserem Beispiel den Wert build hat.
Die Zeile mit dem Label 4 weist darauf hin, dass wir das Image web-app-builder-runtime verwenden möchten, das wir bereits im Abschnitt ImageStream gesehen haben.
Die Zeile mit dem Label 5 besagt, dass wir einen inkrementellen Build verwenden möchten, sofern das S2I-Image dies unterstützt, und das Image Web App Builder unterstützt dies. Beim ersten Start wird nach Abschluss der Assemblierungsphase der Ordner node_modules in einer Archivdatei gespeichert. Bei späteren Starts wird das Image einfach diesen Ordner entpacken, um die Build-Dauer zu verkürzen.
Und schließlich enthält die Zeile mit dem Label 6 nur einige Trigger, damit der Build automatisch ausgeführt wird, ohne manuelles Eingreifen, wenn sich etwas ändert.
Insgesamt handelt es sich um eine recht standardisierte Build-Konfiguration.
Schauen wir uns nun die zweite Build-Konfiguration an. Sie ähnelt der ersten sehr, weist jedoch eine wichtige Abweichung auf.
apiVersion: v1
kind: BuildConfig
metadata:
name: react-web-app-runtime
spec:
output:
to:
kind: ImageStreamTag
name: react-web-app-runtime:latest // 1
source: // 2
type: Image
images:
- from:
kind: ImageStreamTag
name: react-web-app-builder:latest // 3
paths:
- sourcePath: /opt/app-root/output/. // 4
destinationDir: . // 5
strategy: // 6
sourceStrategy:
from:
kind: ImageStreamTag
name: nginx-image-runtime:latest
incremental: true
type: Source
triggers:
- github:
secret: ${GITHUB_WEBHOOK_SECRET}
type: GitHub
- type: ConfigChange
- type: ImageChange
imageChange: {}
- type: ImageChange
imageChange:
from:
kind: ImageStreamTag
name: react-web-app-builder:latest // 7
Die zweite Build-Konfiguration – react-web-app-runtime – beginnt ganz Standardmäßig.
In der Zeile mit dem Label 1 gibt es nichts Neues – sie sagt einfach, dass das Ergebnis der Build in das Bild react-web-app-runtime gelegt wird.
Die Zeile mit dem Label 2 gibt an, woher der Quellcode stammt, ähnlich wie in der vorherigen Konfiguration. Dabei beachten Sie bitte, dass er aus dem Image stammt. Und zwar aus dem Image, das wir gerade erstellt haben – aus react-web-app-builder (wie in der Zeile mit dem Label 3 angegeben). Die Dateien, die wir verwenden möchten, befinden sich innerhalb des Images, und ihr Speicherort wird in der Zeile mit dem Label 4 festgelegt, in unserem Fall ist das /opt/app-root/output/. Wenn Sie sich erinnern, werden genau dort die Dateien abgelegt, die aus dem Build-Ergebnis unserer Anwendung generiert wurden.
Der Zielordner, der in der Zeile mit dem Label 5 angegeben ist, ist einfach das aktuelle Verzeichnis (alles läuft, erinnern Sie sich, innerhalb einer magischen Sache namens OpenShift und nicht auf Ihrem lokalen Computer).
Der Abschnitt strategy – die Zeile mit dem Label 6 – ähnelt ebenfalls der ersten Build-Konfiguration. Dieses Mal werden wir jedoch das nginx-image-runtime verwenden, das wir im Abschnitt ImageStream bereits gesehen haben.
Schließlich ist die Zeile mit dem Label 7 der Abschnitt der Trigger, der diesen Build jedes Mal aktiviert, wenn sich das Image react-web-app-builder ändert.
Ansonsten enthält diese Vorlage eine ganz standardisierte Bereitstellungskonfiguration sowie Elemente, die mit Diensten und Routen zu tun haben. Wir werden jedoch nicht näher darauf eingehen. Bitte beachten Sie, dass das Bild, das bereitgestellt wird, das Bild react-web-app-runtime ist.
Anwendungsbereitstellung
Nachdem wir nun einen Blick auf die Vorlage geworfen haben, sehen wir uns an, wie wir sie für die Bereitstellung einer Anwendung nutzen können.
Wir können das OpenShift-Client-Tool namens oc verwenden, um unsere Vorlage bereitzustellen:
$ find . | grep openshiftio | grep application | xargs -n 1 oc apply -f
$ oc new-app --template react-web-app -p SOURCE_REPOSITORY_URL=https://github.com/lholmquist/react-web-app
Der erste Befehl im obigen Screenshot ist absichtlich technisch, um die Vorlage /openshiftio/application.yaml zu finden.
Der zweite Befehl erstellt einfach eine neue Anwendung basierend auf dieser Vorlage.
Nachdem diese Befehle ausgeführt wurden, sehen wir, dass wir zwei Builds erhalten haben:

Und wenn wir zum Bildschirm Übersicht zurückkehren, sehen wir das gestartete Pod:

Ein Klick auf den Link und wir gelangen zu unserer Anwendung, die die Standardseite der React-App darstellt:

Ergänzung 1
Für Angular-Begeisterte haben wir ebenfalls .
Die Vorlage hier ist identisch, abgesehen von der Variable OUTPUT_DIR.
Ergänzung 2
In diesem Artikel haben wir NGINX als Webserver verwendet, es ist jedoch ziemlich einfach, ihn durch Apache zu ersetzen, indem Sie einfach die Vorlagendatei ändern. findet man .
Fazit
Im ersten Teil dieser Reihe haben wir gezeigt, wie man moderne Web-Anwendungen schnell auf der OpenShift-Plattform bereitstellt. Heute haben wir uns angesehen, was ein Web-App-Image ausmacht und wie es mit einem reinen Webserver wie NGINX mithilfe von verknüpften Builds (chained builds) zu einer für Produktionsumgebungen geeigneten App-Bereitstellung kombiniert werden kann. Im nächsten und letzten Artikel dieser Reihe zeigen wir, wie Sie auf OpenShift einen Entwicklungsserver für Ihre Anwendung starten und die Synchronisierung von lokalen und entfernten Dateien gewährleisten können.
Inhalt dieser Artikelreihe
- Teil 1: ;
- Teil 2: wie man ein neues S2I-Image zusammen mit einem bereits vorhandenen HTTP-Server-Image, wie z.B. NGINX, unter Verwendung von verknüpften OpenShift-Bauten für eine Produktionsbereitstellung einsetzt;
- Teil 3: So starten Sie auf der OpenShift-Plattform einen Entwicklungsserver für Ihre Anwendung und synchronisieren ihn mit dem lokalen Dateisystem.
Zusätzliche Ressourcen
- Kostenloses E-Book .
- Informationen über .
Quelle: habr.com
