Moderne OpenShift-Apps, Teil 2: Verkettete Builds

Hallo! Dies ist der zweite Beitrag in unserer Reihe, in dem wir Ihnen zeigen, wie Sie moderne Webanwendungen auf Red Hat OpenShift bereitstellen.







Im vorherigen Beitrag haben wir die Funktionen des neuen S2I-Builder-Images (Source-to-Image), mit dem moderne Webanwendungen auf der OpenShift-Plattform erstellt und bereitgestellt werden sollen, leicht angesprochen. Damals interessierten wir uns für das Thema der schnellen Anwendungsbereitstellung. Heute werden wir uns ansehen, wie ein S2I-Image als "sauberes" Builder-Image verwendet und mit zugehörigen OpenShift-Assemblys kombiniert wird.



Sauberes Builder-Image



Wie bereits im ersten Teil erwähnt, verfügen die meisten modernen Webanwendungen über eine sogenannte Erstellungsphase, in der normalerweise Vorgänge wie Code-Transpilation, Verkettung mehrerer Dateien und Minimierung ausgeführt werden. Die resultierenden Dateien - statisches HTML, JavaScript und CSS - werden dem Ausgabeordner hinzugefügt. 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).



Source-to-Image (S2I)



Dieser Beitrag ist überhaupt nicht darum , was S2I ist und wie es zu benutzen (du mehr über sie lesen kann hier ), aber es ist wichtig , klar über die beiden Phasen dieses Prozesses zu sein , um zu verstehen , was die Web App Builder Bild der Fall ist.



Phase zusammenbauen



Der Assembly-Schritt ist von Natur aus sehr ähnlich zu dem, was passiert, wenn Sie Docker Build ausführen und ein neues Docker-Image erhalten. Dementsprechend tritt diese Phase beim Starten eines Builds auf der OpenShift-Plattform auf.



Im Fall eines Web App Builder-Images ist das Assemble-Skript für die Installation der Abhängigkeiten Ihrer Anwendung und die Ausführung des Builds verantwortlich . Standardmäßig verwendet das Builder-Image das Build-Konstrukt npm run, 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 für Angular-Anwendungen der Ordner project_name / dist. Und wie im letzten Beitrag gezeigt, kann der Speicherort des Ausgabeverzeichnisses, das standardmäßig erstellt wird, über die Umgebungsvariable OUTPUT_DIR überschrieben werden. Da sich der Speicherort des Ausgabeordners von Framework zu Framework unterscheidet, kopieren Sie einfach die generierte Ausgabe in den Standardordner im Image, nämlich / opt / apt-root / output. Dies ist wichtig, um den Rest dieses Artikels zu verstehen. Lassen Sie uns jedoch zunächst einen kurzen Blick auf die nächste Phase werfen - den Lauf (Laufphase).



Phase ausführen



Diese Phase tritt auf, wenn ein Docker-Lauf für ein neues Image aufgerufen wird, das während der Assembly-Phase erstellt wurde. Dies tritt auch bei der Bereitstellung auf der OpenShift-Plattform auf. Standardmäßig verwendet das Ausführungsskript das Servemodul , um statischen Inhalt im obigen Standardausgabeverzeichnis bereitzustellen.



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 wirklich nur statischen Inhalt bereitstellen, wird die in unserem Image installierte Node.js nicht benötigt - ein Webserver reicht aus.



Mit anderen Worten, wir brauchen eine Sache während der Montage und eine andere während der Ausführung. Hier bieten sich verkettete Builds an.



Verkettete Builds



In der OpenShift-Dokumentation schreiben sie Folgendes über verkettete Builds :



"Zwei Assemblys können miteinander verknüpft werden, wobei eine die kompilierte Entität generiert und die andere die 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 NGINX verwenden, um unseren Inhalt bereitzustellen.



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



Betrachten wir dies nun anhand eines konkreten Beispiels.



In diesem Tutorial verwenden wir eine einfache React-Anwendung, die mit dem Befehlszeilentool create-react-app erstellt wurde.



Die OpenShift-Vorlagendatei hilft uns, alles zusammenzustellen .



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



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 Sie sollten auf den Parameter OUTPUT_DIR achten. Für die React-Anwendung aus unserem Beispiel gibt es keinen 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.



Schauen wir uns nun den Abschnitt 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'


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



Das dritte Bild ist ein Web-App-Builder und stammt aus der nodeshift / ubi8-s2i-Web-App mit dem 10.x-Tag auf dem Docker-Hub .



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



Schauen wir uns nun die ersten beiden Bilder an. Sie sind beide zu Beginn leer und werden erst in der Erstellungsphase erstellt. Das erste Image, React-Web-App-Builder, ist das Ergebnis eines Assemblierungsschritts, bei dem das Web-App-Builder-Laufzeit-Image und unser Quellcode zusammengeführt werden. Deshalb setzen wir "-builder" in den Namen dieses Bildes.



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



Verwirrt? Schauen wir uns nun die Build-Konfigurationen an und es wird etwas klarer.



Unsere Vorlage enthält zwei Build-Konfigurationen. Hier ist der erste, und er ist ziemlich normal:



  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, wird in der Zeile mit der Bezeichnung 1 angegeben, dass das Ergebnis dieses Builds in dasselbe Image des React-Web-App-Builders eingefügt wird, das wir zuvor im Abschnitt ImageStreams gesehen haben.



Die Zeile mit der Bezeichnung 2 gibt an, woher der Code stammt. In unserem Fall ist dies ein Git-Repository, und der Speicherort, die Referenz und der Kontextordner werden durch die Parameter definiert, die wir oben bereits gesehen haben.



Die mit 3 bezeichnete Zeile ist bereits im Parameterbereich zu sehen. Es fügt die Umgebungsvariable OUTPUT_DIR hinzu, die in unserem Beispiel erstellt wurde.

In der Zeile mit der Bezeichnung 4 wird angegeben, dass das Web-App-Builder-Laufzeitbild verwendet werden soll, das wir bereits im Abschnitt ImageStream gesehen haben.



Die mit 5 bezeichnete Zeile besagt, dass wir einen inkrementellen Build verwenden möchten, wenn das S2I-Image dies unterstützt und das Web App Builder-Image dies tut. Beim ersten Start nach Abschluss der Montagephase speichert das Image den Ordner node_modules in einer Archivdatei. Bei nachfolgenden Durchläufen entpackt das Image diesen Ordner einfach, um die Erstellungszeit zu verkürzen.



Schließlich ist die mit 6 bezeichnete Zeile nur ein paar Auslöser, sodass der Build automatisch und ohne manuellen Eingriff gestartet wird, wenn sich etwas ändert.



Alles in allem ist dies eine ziemlich standardmäßige Build-Konfiguration.



Schauen wir uns nun die zweite Build-Konfiguration an. Es ist dem ersten sehr ähnlich, aber es gibt 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 ziemlich normal.



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



Die mit 2 bezeichnete Zeile gibt wie in der vorherigen Konfiguration an, woher der Quellcode stammt. Beachten Sie jedoch, dass wir hier sagen, dass es aus dem Bild stammt. Darüber hinaus aus dem Bild, das wir gerade erstellt haben - aus dem React-Web-App-Builder (in der Zeile mit der Bezeichnung 3 angegeben). Die Dateien, die wir verwenden möchten, befinden sich im Bild und ihr Speicherort ist dort in der Zeile mit der Bezeichnung 4 angegeben. In unserem Fall ist dies / opt / app-root / output /. Wenn Sie sich erinnern, werden hier die Dateien abgelegt, die aus den Ergebnissen der Erstellung unserer Anwendung generiert wurden.



Der in der Zeile mit der Bezeichnung 5 angegebene Zielordner ist nur das aktuelle Verzeichnis (denken Sie daran, dass sich alles in einem magischen Objekt namens OpenShift dreht, nicht auf Ihrem lokalen Computer).



Der Strategie-Abschnitt - Zeile mit der Bezeichnung 6 - ähnelt ebenfalls der ersten Build-Konfiguration. Nur dieses Mal werden wir die Nginx-Image-Laufzeit verwenden, die wir bereits im Abschnitt ImageStream gesehen haben.



Schließlich ist die mit 7 bezeichnete Zeile der Auslöserabschnitt, der diesen Build jedes Mal auslöst, wenn sich das Image des React-Web-App-Builders ändert.



Der Rest dieser Vorlage enthält eine ziemlich standardmäßige Bereitstellungskonfiguration sowie Dinge, die sich auf Dienste und Routen beziehen, aber darauf werden wir nicht eingehen. Beachten Sie, dass das Image, das bereitgestellt wird, das React-Web-App-Laufzeit-Image ist.



Stellen Sie die Anwendung bereit



Nachdem Sie sich die Vorlage angesehen haben, sehen wir uns an, wie Sie sie zum Bereitstellen der Anwendung verwenden.



Wir können ein 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 eine absichtlich technische Methode zum Auffinden der Vorlage. / Openshiftio / application.yaml.



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



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







Wenn Sie zum Übersichtsbildschirm zurückkehren, wird der Pod gestartet:







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







Anhang 1



Für Angular-Liebhaber haben wir auch eine Beispiel-App .



Die Vorlage ist hier bis auf die Variable OUTPUT_DIR dieselbe.



Anlage 2



In diesem Artikel haben wir als Webserver NGINX verwendet, aber es ist ziemlich einfach, es durch Apache zu ersetzen. Ändern Sie einfach das Dateivorlagenbild NGINX auf dem Weg des Apache .



Fazit



Im ersten Teil dieser Serie haben wir Ihnen gezeigt, wie Sie moderne Webanwendungen schnell auf der OpenShift-Plattform bereitstellen können. Heute haben wir uns angesehen, was ein Web-App-Image ausmacht und wie es mit einem reinen Webserver wie NGINX kombiniert werden kann, indem verkettete Builds verwendet werden, um einen produktionsfähigeren App-Build zu erstellen. Im nächsten, letzten Artikel dieser Reihe zeigen wir Ihnen, wie Sie einen Entwicklungsserver für Ihre Anwendung unter OpenShift ausführen und lokale und Remote-Dateien synchron halten.



Inhalt dieser Artikelserie










All Articles