Moderne Anwendungen auf OpenShift, Teil 2: Verkettete Builds

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

Moderne Anwendungen auf OpenShift, Teil 2: Verkettete Builds

Im vorherigen Beitrag haben wir die Funktionen des neuen S2I-Builder-Images (Source-to-Image) kurz angesprochen, das für die Erstellung und Bereitstellung moderner Webanwendungen auf der OpenShift-Plattform konzipiert ist. Damals interessierte uns das Thema der schnellen Bereitstellung einer Anwendung, und heute schauen wir uns an, wie man ein S2I-Image als „reines“ Builder-Image verwendet und es mit zugehörigen OpenShift-Assemblys kombiniert.

Sauberes Builder-Image

Wie wir in Teil XNUMX erwähnt haben, verfügen die meisten modernen Webanwendungen über eine sogenannte Build-Phase, in der typischerweise Vorgänge wie Code-Transpilierung, Verkettung mehrerer Dateien und Minimierung ausgeführt werden. Die als Ergebnis dieser Vorgänge erhaltenen Dateien – und dabei handelt es sich um statisches HTML, JavaScript und CSS – werden im Ausgabeordner gespeichert. Der Speicherort dieses Ordners hängt normalerweise davon ab, welche Build-Tools verwendet werden. Für React ist dies der Ordner ./build (wir werden weiter unten ausführlicher darauf zurückkommen).

Quelle-zu-Bild (S2I)

In diesem Beitrag gehen wir nicht auf das Thema „Was ist S2I und wie man es verwendet“ ein (Sie können mehr darüber lesen). hier), aber es ist wichtig, sich über die beiden Schritte in diesem Prozess im Klaren zu sein, um zu verstehen, was ein Web App Builder-Image bewirkt.

Montagephase

Die Montagephase ist von Natur aus sehr ähnlich zu dem, was passiert, wenn Sie Docker Build ausführen und am Ende ein neues Docker-Image erhalten. Dementsprechend findet diese Phase statt, wenn ein Build auf der OpenShift-Plattform gestartet wird.

Im Fall eines Web App Builder-Images ist es für die Installation der Abhängigkeiten Ihrer Anwendung und die Ausführung des Builds verantwortlich. Assemble-Skript. Standardmäßig verwendet das Builder-Image das npm run build-Konstrukt, dies kann jedoch über die Umgebungsvariable NPM_BUILD überschrieben werden.

Wie bereits erwähnt, hängt der Speicherort der fertigen, bereits erstellten Anwendung davon ab, welche Tools Sie verwenden. Im Fall von React ist dies beispielsweise der Ordner ./build und bei Angular-Anwendungen der Ordner project_name/dist. Und wie bereits im vorherigen Beitrag gezeigt, kann der Speicherort des Ausgabeverzeichnisses, das standardmäßig auf „Build“ eingestellt ist, über die Umgebungsvariable OUTPUT_DIR überschrieben werden. Da der Speicherort des Ausgabeordners von Framework zu Framework unterschiedlich ist, kopieren Sie die generierte Ausgabe einfach in den Standardordner im Image, nämlich /opt/apt-root/output. Dies ist wichtig, um den Rest dieses Artikels zu verstehen, aber werfen wir zunächst einen kurzen Blick auf die nächste Phase – die Ausführungsphase.

Laufphase

Diese Phase tritt auf, wenn ein Aufruf von Docker Run für das neue Image erfolgt, das während der Assembly-Phase erstellt wurde. Das Gleiche passiert bei der Bereitstellung auf der OpenShift-Plattform. Default Skript ausführen verwendet Serve-Modul um statischen Inhalt bereitzustellen, der sich im oben genannten Standardausgabeverzeichnis befindet.

Diese Methode eignet sich für die schnelle Bereitstellung von Anwendungen, es wird jedoch im Allgemeinen nicht empfohlen, statische Inhalte auf diese Weise bereitzustellen. Da wir in Wirklichkeit nur statische Inhalte bereitstellen, muss Node.js nicht in unserem Image installiert sein – ein Webserver reicht aus.

Mit anderen Worten: Beim Zusammenbau brauchen wir eine Sache, bei der Ausführung brauchen wir eine andere. In dieser Situation sind verkettete Builds praktisch.

Verkettete Builds

Darüber schreiben sie verkettete Builds in der OpenShift-Dokumentation:

„Zwei Assemblys können miteinander verknüpft werden, wobei eine eine kompilierte Entität generiert und die andere diese Entität in einem separaten Image hostet, das zum Ausführen dieser Entität verwendet wird.“

Mit anderen Worten: Wir können das Web App Builder-Image verwenden, um unseren Build auszuführen, und dann das Webserver-Image, dasselbe NGINX, verwenden, um unsere Inhalte bereitzustellen.

Somit können wir das Web App Builder-Image als „reinen“ Builder verwenden und haben gleichzeitig ein kleines Laufzeit-Image.

Schauen wir uns das nun anhand eines konkreten Beispiels an.

Für das Training werden wir verwenden einfache React-Anwendung, erstellt mit dem Befehlszeilentool „create-react-app“.

Es wird uns helfen, alles zusammenzustellen OpenShift-Vorlagendatei.

Schauen wir uns diese Datei genauer an und beginnen mit dem Parameterabschnitt.

parameters:
  - name: SOURCE_REPOSITORY_URL
    description: The source URL for the application
    displayName: Source URL
    required: true
  - name: SOURCE_REPOSITORY_REF
    description: The branch name for the application
    displayName: Source Branch
    value: master
    required: true
  - name: SOURCE_REPOSITORY_DIR
    description: The location within the source repo of the application
    displayName: Source Directory
    value: .
    required: true
  - name: OUTPUT_DIR
    description: The location of the compiled static files from your web apps builder
    displayName: Output Directory
    value: build
    required: false

Hier ist alles ziemlich klar, aber es lohnt sich, auf den Parameter OUTPUT_DIR zu achten. Für die React-Anwendung in unserem Beispiel besteht kein Grund zur Sorge, da React den Standardwert als Ausgabeordner verwendet. Im Fall von Angular oder etwas anderem muss dieser Parameter jedoch nach Bedarf geändert werden.

Werfen wir nun einen Blick auf den Abschnitt „ImageStreams“.

- 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'

Schauen Sie sich das dritte und vierte Bild an. Sie sind beide als Docker-Images definiert und Sie können deutlich erkennen, woher sie stammen.

Das dritte Bild ist Web-App-Builder und stammt von nodeshift/ubi8-s2i-web-app mit dem Tag 10.x Docker-Hub.

Das vierte ist ein NGINX-Image (Version 1.12) mit dem neuesten Tag Docker-Hub.

Schauen wir uns nun die ersten beiden Bilder an. Sie sind beide beim Start leer und werden erst während der Build-Phase erstellt. Das erste Image, „React-Web-App-Builder“, wird das Ergebnis eines Assemblierungsschritts sein, der das Web-App-Builder-Runtime-Image und unseren Quellcode kombiniert. Aus diesem Grund haben wir dem Namen dieses Bildes „-builder“ hinzugefügt.

Das zweite Image – React-Web-App-Runtime – ist das Ergebnis der Kombination von Nginx-Image-Runtime und einigen Dateien aus dem React-Web-App-Builder-Image. Dieses Bild wird auch während der Bereitstellung verwendet und enthält nur den Webserver und statisches HTML, JavaScript und CSS unserer Anwendung.

Verwirrt? Werfen wir nun einen Blick auf die Build-Konfigurationen und es wird etwas klarer.

Unsere Vorlage verfügt über zwei Build-Konfigurationen. Hier ist das erste, und es ist ziemlich Standard:

  apiVersion: v1
  kind: BuildConfig
  metadata:
    name: react-web-app-builder
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: react-web-app-builder:latest // 1
    source:   // 2 
      git:
        uri: ${SOURCE_REPOSITORY_URL}
        ref: ${SOURCE_REPOSITORY_REF}
      contextDir: ${SOURCE_REPOSITORY_DIR}
      type: Git
    strategy:
      sourceStrategy:
        env:
          - name: OUTPUT_DIR // 3 
            value: ${OUTPUT_DIR}
        from:
          kind: ImageStreamTag
          name: web-app-builder-runtime:latest // 4
        incremental: true // 5
      type: Source
    triggers: // 6
    - github:
        secret: ${GITHUB_WEBHOOK_SECRET}
      type: GitHub
    - type: ConfigChange
    - imageChange: {}
      type: ImageChange

Wie Sie sehen können, besagt die Zeile mit der Bezeichnung 1, dass das Ergebnis dieses Builds in demselben React-Web-App-Builder-Image platziert wird, das wir etwas früher im Abschnitt „ImageStreams“ gesehen haben.

Die Zeile mit der Bezeichnung 2 verrät Ihnen, woher Sie den Code erhalten. In unserem Fall handelt es sich um ein Git-Repository, und der Speicherort, die Referenz und der Kontextordner werden durch die Parameter bestimmt, die wir oben bereits gesehen haben.

Die Zeile mit der Bezeichnung 3 ist das, was wir bereits im Parameterabschnitt gesehen haben. Es fügt die Umgebungsvariable OUTPUT_DIR hinzu, die in unserem Beispiel build ist.
Die Zeile mit der Bezeichnung 4 besagt, dass das Web-App-Builder-Runtime-Image verwendet werden soll, das wir bereits im Abschnitt „ImageStream“ gesehen haben.

Zeile mit der Bezeichnung 5 besagt, dass wir einen inkrementellen Build verwenden möchten, wenn das S2I-Image dies unterstützt und das Web App Builder-Image dies unterstützt. Beim ersten Start, nach Abschluss der Montagephase, speichert das Image den Ordner „node_modules“ in einer Archivdatei. Bei nachfolgenden Ausführungen wird das Image dann einfach diesen Ordner entpacken, um die Erstellungszeit zu verkürzen.

Und schließlich ist die Zeile mit der Bezeichnung 6 nur ein paar Auslöser, damit der Build automatisch und ohne manuelles Eingreifen ausgeführt wird, wenn sich etwas ändert.

Insgesamt handelt es sich hierbei um eine ziemlich standardmäßige Build-Konfiguration.

Schauen wir uns nun die zweite Build-Konfiguration an. Es ist dem ersten sehr ähnlich, es gibt jedoch einen wichtigen Unterschied.

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 ist also „react-web-app-runtime“ und beginnt recht standardmäßig.

Die Zeile mit der Bezeichnung 1 ist nichts Neues – sie besagt lediglich, dass das Build-Ergebnis in das React-Web-App-Runtime-Image eingefügt wird.

Die Zeile mit der Bezeichnung 2 gibt wie in der vorherigen Konfiguration an, woher der Quellcode stammt. Beachten Sie jedoch, dass wir hier sagen, dass es sich um ein Bild handelt. Darüber hinaus aus dem Bild, das wir gerade erstellt haben – vom React-Web-App-Builder (angezeigt in Zeile mit der Bezeichnung 3). Die Dateien, die wir verwenden möchten, befinden sich im Bild und ihr Speicherort wird in der Zeile mit der Bezeichnung 4 festgelegt, in unserem Fall ist es /opt/app-root/output/. Wie Sie sich erinnern, werden hier die Dateien gespeichert, die auf der Grundlage der Ergebnisse der Erstellung unserer Anwendung generiert wurden.

Der im Begriff mit der Bezeichnung 5 angegebene Zielordner ist einfach das aktuelle Verzeichnis (das ist alles, denken Sie daran, es läuft in einem magischen Ding namens OpenShift und nicht auf Ihrem lokalen Computer).

Der Strategieabschnitt – Zeile mit der Bezeichnung 6 – ähnelt ebenfalls der ersten Build-Konfiguration. Nur dieses Mal werden wir nginx-image-runtime verwenden, was wir bereits im Abschnitt ImageStream gesehen haben.

Schließlich ist die Zeile mit der Bezeichnung 7 ein Abschnitt mit Triggern, die diesen Build jedes Mal aktivieren, wenn sich das React-Web-App-Builder-Image ändert.

Ansonsten enthält diese Vorlage eine ziemlich standardmäßige Bereitstellungskonfiguration sowie Dinge, die sich auf Dienste und Routen beziehen, aber wir werden nicht zu sehr ins Detail gehen. Bitte beachten Sie, dass es sich bei dem bereitgestellten Image um das React-Web-App-Runtime-Image handelt.

Anwendungsbereitstellung

Nachdem wir uns nun die Vorlage angesehen haben, wollen wir nun sehen, wie man sie zum Bereitstellen einer Anwendung verwendet.

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 Screenshot oben ist eine bewusst technische Möglichkeit, eine Vorlage zu finden./openshiftio/application.yaml.

Der zweite Befehl erstellt einfach eine neue Anwendung basierend auf dieser Vorlage.

Nachdem diese Befehle ausgeführt wurden, werden wir sehen, dass wir zwei Assemblys haben:

Moderne Anwendungen auf OpenShift, Teil 2: Verkettete Builds

Und wenn wir zum Übersichtsbildschirm zurückkehren, sehen wir den gestarteten Pod:

Moderne Anwendungen auf OpenShift, Teil 2: Verkettete Builds

Klicken Sie auf den Link und wir werden zu unserer App weitergeleitet, der Standard-React-App-Seite:

Moderne Anwendungen auf OpenShift, Teil 2: Verkettete Builds

1-Nachtrag

Für Angular-Liebhaber haben wir auch Beispielanwendung.

Das Muster ist hier dasselbe, mit Ausnahme der Variablen OUTPUT_DIR.

2-Nachtrag

In diesem Artikel haben wir NGINX als Webserver verwendet, es ist jedoch recht einfach, ihn durch Apache zu ersetzen, indem Sie einfach die Vorlage in der Datei ändern NGINX-Bild auf Apache-Bild.

Abschluss

Im ersten Teil dieser Serie haben wir gezeigt, wie man moderne Webanwendungen schnell auf der OpenShift-Plattform bereitstellen kann. Heute haben wir uns angeschaut, was ein Web-App-Image macht und wie es mithilfe verketteter Builds mit einem reinen Webserver wie NGINX kombiniert werden kann, um einen produktionsbereiteren Anwendungs-Build zu erstellen. Im nächsten und letzten Artikel dieser Reihe zeigen wir, wie Sie einen Entwicklungsserver für Ihre Anwendung unter OpenShift ausführen und die Synchronisierung lokaler und Remote-Dateien sicherstellen.

Inhalt dieser Artikelserie

  • Teil 1: wie Sie in wenigen Schritten moderne Webanwendungen bereitstellen;
  • Teil 2: Verwendung eines neuen S2I-Images mit einem vorhandenen HTTP-Server-Image wie NGINX unter Verwendung zugehöriger OpenShift-Assemblys für die Produktionsbereitstellung;
  • Teil 3: So führen Sie einen Entwicklungsserver für Ihre Anwendung auf der OpenShift-Plattform aus und synchronisieren ihn mit dem lokalen Dateisystem.

Zusätzliche Ressourcen

Source: habr.com

Kommentar hinzufügen